/*
 * Copyright (C) The MX4J Contributors.
 * All rights reserved.
 *
 * This software is distributed under the terms of the MX4J License version 1.0.
 * See the terms of the MX4J License in the documentation provided with this software.
 */

package mx4j.tools.remote.http.jetty;

import java.io.IOException;
import java.util.Map;

import javax.management.remote.JMXServiceURL;

import mx4j.log.Log;
import mx4j.log.Logger;
import mx4j.tools.remote.http.HTTPConnectorServer;
import mx4j.tools.remote.http.WebContainer;
import org.mortbay.http.HttpListener;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.ServletHandler;
import org.mortbay.jetty.servlet.ServletHttpContext;

/**
 * Jetty's implementation of WebContainer interface
 *
 * @version $Revision: 1.6 $
 */
public class JettyWebContainer implements WebContainer
{
   private final Server server;

   public JettyWebContainer()
   {
      server = new Server();
   }

   protected Logger getLogger()
   {
      return Log.getLogger(getClass().getName());
   }

   protected Server getServer()
   {
      return server;
   }

   public void start(JMXServiceURL url, Map environment) throws IOException
   {
      try
      {
         configure(url, environment);
         getServer().start();
      }
      catch (IOException x)
      {
         throw x;
      }
      catch (Exception x)
      {
         throw new IOException(x.toString());
      }
   }

   private void configure(JMXServiceURL url, Map environment) throws IOException
   {
      Logger logger = getLogger();

      if (environment != null)
      {
         Object config = environment.get(HTTPConnectorServer.WEB_CONTAINER_CONFIGURATION);
         if (config instanceof String)
         {
            if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Configuring Jetty with configuration " + config);
            getServer().configure((String)config);

            // Be sure there is at least one listener on the port specified by the JMXServiceURL
            HttpListener[] listeners = getServer().getListeners();
            if (listeners != null)
            {
               boolean found = false;
               for (int i = 0; i < listeners.length; ++i)
               {
                  HttpListener listener = listeners[i];
                  if (listener.getPort() == url.getPort())
                  {
                     found = true;
                     break;
                  }
               }
               if (!found) throw new IOException("No listener configured with configuration " + config + " matches JMXServiceURL " + url);
               // Configured successfully, return
               if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Configured Jetty successfully with configuration " + config);
               return;
            }
            else
            {
               if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Jetty configuration " + config + " does not have any listener");
            }
         }
         else
         {
            if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Skipping Jetty configuration " + config + " (must be a String)");
         }
      }
      configureListener(url, environment);
   }

   protected void configureListener(JMXServiceURL url, Map environment) throws IOException
   {
      Logger logger = getLogger();
      if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Configuring Jetty with a default listener on port " + url.getPort());
      String host = url.getHost();
      if (host == null) host = "";
      getServer().addListener(host + ":" + url.getPort());
   }

   public void stop() throws IOException
   {
      try
      {
         getServer().stop();
      }
      catch (InterruptedException x)
      {
         Thread.currentThread().interrupt();
      }
   }

   public void deploy(String servletClassName, JMXServiceURL url, Map environment) throws IOException
   {
      try
      {
         String urlPattern = resolveServletMapping(url);
         ServletHttpContext context = (ServletHttpContext)getServer().getContext("/");
         context.addServlet(urlPattern, servletClassName);
         // TODO: be sure an undeployed url is not restarted !
         if (!context.isStarted()) context.start();
      }
      catch (Exception x)
      {
         throw new IOException(x.toString());
      }
   }

   public void undeploy(String servletName, JMXServiceURL url, Map environment)
   {
      String urlPattern = resolveServletMapping(url);
      ServletHttpContext context = (ServletHttpContext)getServer().getContext("/");
      ServletHandler handler = context.getServletHandler();
      handler.getServletMap().remove(urlPattern);
   }

   private String resolveServletMapping(JMXServiceURL url)
   {
      String path = url.getURLPath();
      String urlPattern = null;
      if (path.endsWith("/"))
         urlPattern = path + "*";
      else
         urlPattern = path + "/*";
      if (!urlPattern.startsWith("/")) urlPattern = "/" + urlPattern;
      return urlPattern;
   }
}
