/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2008 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.ws.cxf;

import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.jaxws.spi.ProviderImpl;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Level;
import org.ow2.jonas.lib.service.AbsServiceImpl;
import static org.ow2.jonas.lib.util.Log.setComponentLogLevel;
import org.ow2.jonas.service.ServiceException;
import org.ow2.jonas.ws.cxf.client.CXFServiceReferenceBuilder;
import org.ow2.jonas.ws.jaxws.IJAXWSService;
import org.ow2.util.ee.metadata.common.api.struct.IJaxwsWebServiceRef;
import org.ow2.util.log.Log;
import org.ow2.util.log.LogFactory;

import javax.naming.Reference;
import javax.xml.ws.spi.Provider;

/**
 * The CXFService class is used to declare CXF as a module in JOnAS.
 * 
 */
public class CXFService extends AbsServiceImpl implements IJAXWSService {

    /**
     * This Bus is shared by all clients inside this JVM.
     * This is the default CXF Bus.
     */
    private Bus clientBus;

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

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

        // CXF Bus init is extra verbose, level up the default logging level
        Level old = setComponentLogLevel("org.apache.cxf", BasicLevel.LEVEL_ERROR);
        Level old2 = setComponentLogLevel("org.springframework", BasicLevel.LEVEL_ERROR);

        // Force initialization of the singleton Bus shared by all clients.
        clientBus = BusFactory.getDefaultBus();

        // Reset log levels
        setComponentLogLevel("org.apache.cxf", old);
        setComponentLogLevel("org.springframework", old2);

        // Force usage of the CXF JAX-WS Provider
        System.setProperty(Provider.JAXWSPROVIDER_PROPERTY, ProviderImpl.class.getName());

        logger.info("CXF service started");
    }

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

        Level old = setComponentLogLevel("org.apache.cxf", BasicLevel.LEVEL_ERROR);
        Level old2 = setComponentLogLevel("org.springframework", BasicLevel.LEVEL_ERROR);

        // Stop the client bus
        // true means 'wait for complete stop'
        clientBus.shutdown(true);
        clientBus = null;
        BusFactory.setDefaultBus(null);

        setComponentLogLevel("org.apache.cxf", old);
        setComponentLogLevel("org.springframework", old2);

        logger.info("CXF service stopped");
    }

    /**
     * Construct a Reference dedicated to the given @WebServiceRef metadata.
     *
     * @param serviceRef the reference described by the user.
     * @return a JNDI Naming {@link javax.naming.Reference} that can be bound in a JNDI Context.
     */
    public Reference createNamingReference(final IJaxwsWebServiceRef serviceRef) {

        CXFServiceReferenceBuilder builder = new CXFServiceReferenceBuilder();

        builder.setServiceClass(serviceRef.getValue());

        // If the 2 values are different, the type denotes the SEI
        // That means that the required field is a SEI
        if (!serviceRef.getValue().equals(serviceRef.getType())) {
            builder.setSeiClassname(serviceRef.getType());
        } // Otherwise, a Service will be injected

        // If there is an alternate WSDL URL to be provided, that's the place to do it !
        builder.setWsdlLocation(serviceRef.getWsdlLocation());

        return builder.buildReference();
    }
}
