/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-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.lib.service;

import java.util.ArrayList;
import java.util.List;

import javax.naming.Context;

import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import org.ow2.jonas.lib.util.Log;
import org.ow2.jonas.properties.ServerProperties;
import org.ow2.jonas.service.Service;
import org.ow2.jonas.service.ServiceException;

import org.ow2.jonas.lib.management.javaee.ManagedObject;
/**
 * Abstract implementation of a {@link Service}.
 */
public abstract class AbsServiceImpl extends ManagedObject implements Service {

    /**
     * Logger.
     */
    private static Logger logger = Log.getLogger("org.ow2.jonas.service");

    /**
     * service name.
     */
    private String name = null;

    /**
     * service status.
     */
    private boolean started = false;

    /**
     * Server Properties.
     */
    private ServerProperties serverProps;

    /**
     * Initialize the service.
     * @param ctx configuration of the service
     * @throws ServiceException service initialization failed
     */
    public void init(final Context ctx) throws ServiceException {
        // Only call doInit(Context) for old fashioned services
        this.doInit(ctx);
    }

    /**
     * Get the Server Properties.
     */
    public ServerProperties getServerProperties() {
        return this.serverProps;
    }

    /**
     * Set the Server Properties.
     * @param props {@link ServerProperties} instance
     */
    public void setServerProperties(final ServerProperties props) {
        this.serverProps = props;
    }

    /**
     * Start the service.
     * @throws ServiceException service start-up failed
     */
    public void start() throws ServiceException {
        this.doStart();
        this.started = true;
    }

    /**
     * Stop the service.
     * @throws ServiceException service stopping failed
     */
    public void stop() throws ServiceException {
        if (this.isStarted()) {
            this.doStop();
            this.started = false;
        }
    }

    /**
     * Returns true if the service is started, false otherwise.
     * @return true if the service is started
     */
    public boolean isStarted() {
        return this.started;
    }

    /**
     * Returns the service's name.
     * @return the service name
     */
    public String getName() {
        return this.name;
    }

    /**
     * Set the service's name.
     * @param name the name to set
     */
    public void setName(final String name) {
        this.name = name;
    }

    /**
     * Return the domain's name of this service.
     * @return the domain name
     */
    public String getDomainName() {
        return serverProps.getDomainName();
    }

    /**
     * Return the JOnAS server's name of this service.
     * @return the server name
     */
    public String getJonasServerName() {
        return serverProps.getServerName();
    }

    /**
     * Default initialization method to be overridden by sub-classes.
     * @param ctx configuration of the service
     * @throws ServiceException service initialization failed
     * @deprecated
     */
    @Deprecated
    protected void doInit(final Context ctx) throws ServiceException {
        logger.log(BasicLevel.WARN, "Deprecated initialization method. New services must have setters.");
    }

    /**
     * Abstract start-up method to be implemented by sub-classes.
     * @throws ServiceException service start-up failed
     */
    protected abstract void doStart() throws ServiceException;

    /**
     * Abstract method for service stopping to be implemented by sub-classes.
     * @throws ServiceException service stopping failed
     */
    protected abstract void doStop() throws ServiceException;

    /**
     * @return a String representation of a given Service.
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return this.getClass().getSimpleName() + "[name:" + getName() + ", started:" + isStarted() + "]";
    }

    /**
     * Utility Exception throwing method to identify the error source.
     * @param message Descriptive requirement message.
     * @throws ServiceException always.
     */
    protected void throwRequirementException(final String message) throws ServiceException {
        StringBuilder sb = new StringBuilder();
        sb.append("Service: '" + getName() + "' requires: ");
        sb.append(message);
        throw new ServiceException(sb.toString());
    }

    /**
     * Utility method to convert a given String of comma-separated elements to a List.
     * @param value String value
     * @return List constructed from the given String
     */
    protected static List<String> convertToList(final String value) {
        // only handle String list
        // separator is the ','
        String[] values = value.split(",");
        List<String> injection = new ArrayList<String>();

        // We should have at least 1 real value
        if (!((values.length == 1) && ("".equals(values[0])))) {
            for (int i = 0; i < values.length; i++) {
                String part = values[i];
                injection.add(part.trim());
            }
        }
        return injection;
    }

    /**
     * Value used as sequence number by reconfiguration notifications.
     */
    private long sequenceNumber;
    
    /**
     * Return a sequence number and increase this number.
     * @return a sequence number
     */
    public long getSequenceNumber() {
        return ++sequenceNumber;
    }
}
