/**
 * 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 (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: EndpointInstanceListener.java 20987 2011-03-14 12:10:10Z benoitf $
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.web.tomcat7.ws;

import org.apache.catalina.Context;
import org.apache.catalina.Host;
import org.apache.catalina.InstanceEvent;
import org.apache.catalina.InstanceListener;
import org.ow2.jonas.ws.jaxws.IJAXWSService;
import org.ow2.jonas.ws.jaxws.IWebServiceEndpoint;
import org.ow2.jonas.ws.jaxws.PortMetaData;
import org.ow2.jonas.ws.jaxws.WSException;
import org.ow2.jonas.ws.jaxws.http.servlet.JAXWSServlet;
import org.ow2.util.ee.metadata.war.api.IWarClassMetadata;

import javax.servlet.ServletContext;

/**
 * This Catalina InstanceListener is invoked during lifecycle phases
 * of the servlet's instances.
 * Its role is to first create the IWebServiceEndpoint instance
 * (using the IJAXWSService), then starting the newly created endpoint,
 * and finally, inject the endpoint into the JAXWSServlet instance.
 * @author Guillaume Sauthier
 */
public class EndpointInstanceListener implements InstanceListener {

    /**
     * Metadata used to create the WSEndpoint.
     */
    private IWarClassMetadata endpointMetadata;

    /**
     * JAXWS Service instance.
     */
    private IJAXWSService service;

    /**
     * The created endpoint.
     */
    private IWebServiceEndpoint endpoint;

    /**
     * Creates a new instanceListener dedicated for Web based,
     * web.xml described POJO web services
     * @param endpointMetadata Class metadatas
     * @param service the JAXWS Service
     */
    public EndpointInstanceListener(final IWarClassMetadata endpointMetadata,
                                    final IJAXWSService service) {
        this.endpointMetadata = endpointMetadata;
        this.service = service;
    }

    /**
     * Callback when an instance level (ie servlet instance) event is fired by the Wrapper.
     * @param event Servlet's instance lifecycle event
     */
    public void instanceEvent(final InstanceEvent event) {

        // Only react when the instance when just alive (but not already inited)
        if (InstanceEvent.AFTER_INIT_EVENT.equals(event.getType())) {

            // The servlet is a JAXWSServlet
            JAXWSServlet servlet = (JAXWSServlet) event.getServlet();

            // Maybe there are multiple instances of the servlet, so
            // // only creates the endpoint once
            if (endpoint == null) {

                // Create the endpoint from metadata
                ClassLoader loader = event.getWrapper().getLoader().getClassLoader();
                try {
                    ServletContext sc = event.getServlet().getServletConfig().getServletContext();
                    endpoint = service.createPOJOWebServiceEndpoint(endpointMetadata, loader, sc);
                } catch (WSException e) {
                    throw new RuntimeException("WebServiceEndpoint creation failed", e);
                }

                // Fill in some PMD values
                PortMetaData pmd = endpoint.getPortMetaData();

                // Update the url-pattern
                // Find the first servlet-mapping already registered in the web.xml
                String pattern = null;
                String[] mappings = event.getWrapper().findMappings();
                if (mappings.length != 0) {
                    pattern = URLUtils.findValidUrlPattern(mappings);
                }

                if (pattern != null) {
                    // Overwrite the default pattern name
                    pmd.setUrlPattern(pattern);
                }

                // Set context name
                Context context = (Context) event.getWrapper().getParent();
                pmd.setContextRoot(context.getName());

                // Compute a naive endpoint URL
                Host host = (Host) context.getParent();
                String url = URLUtils.getEndpointURL(pmd, host);
                pmd.setEndpointURL(url);

                // metadata and service references are no more required
                endpointMetadata = null;
                service = null;
            }

            // Inject the endpoint
            servlet.setWebServiceEndpoint(endpoint);

            // Print infos
            endpoint.displayInfos();

        }
    }
}
