/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This 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 software 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 software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.jboss.test.cluster.apache_tomcat;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpRecoverableException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.jboss.test.JBossClusteredTestCase;
import org.jboss.test.JBossRMIAdaptorHelper;

import javax.management.MBeanInfo;
import javax.management.ObjectName;
import java.io.IOException;
import java.net.HttpURLConnection;

/**
 * Base class to test HttpSessionReplication with one apache webserver
 * loadbalancing multiple tomcat/JBoss instances.
 *
 * @author <a href="mailto:anil.saldhana@jboss.com">Anil Saldhana</a>.
 * @author Ben Wang
 * @version $Revision: 1.0
 */
public abstract class BaseTest
      extends JBossClusteredTestCase
{
   protected String apacheUrl = null;

   public BaseTest(String name)
   {
      super(name);
      apacheUrl = System.getProperty("apache.url");
   }


   /**
    * Tests connection to the Apache Server.
    * Note: We deal with just one Apache Server. We can bounce the different
    * JBoss/Tomcat servers and Apache will loadbalance.
    *
    * @throws Exception
    */
   public void testApacheConnection()
         throws Exception
   {
      getLog().debug("Enter testApacheConnection");
      try {
         getLog().debug(apacheUrl);
         assertTrue("Apache Up?", this.checkURL(apacheUrl));
      } catch (Exception e) {
         getLog().debug(e.getMessage());
      }
      getLog().debug("Exit testApacheConnection");
   }


   /**
    * Starts the Tomcat MBean running on a particular node
    *
    * @param instancenum Instance Number of the node
    * @throws Exception
    */
   protected void startTomcatInstance(int instancenum)
         throws Exception
   {
      String jndi = getJNDIUrl(instancenum);
      getLog().debug("JNDI URL Obtained=  " + jndi);
      JBossRMIAdaptorHelper server = new JBossRMIAdaptorHelper(jndi);
      //Get the MBeanInfo for the Tomcat MBean
      ObjectName name = new ObjectName("jboss.web:service=WebServer");
      MBeanInfo info = server.getMBeanInfo(name);
      System.out.println("Tomcat MBean:" + info.getClassName());

      getLog().debug("Going to start tomcat  ");
      //Going to stop the Tomcat Instance
      server.invokeOperation(name, "start", null, null);
      this.sleepThread(10);
      server.invokeOperation(name, "startConnectors", null, null);
   }

   /**
    * Shuts down the Tomcat MBean running on a particular node
    *
    * @param instancenum Instance Number of the node
    * @throws Exception
    */
   protected void shutDownTomcatInstance(int instancenum)
         throws Exception
   {
      String jndi = getJNDIUrl(instancenum);
      getLog().debug("JNDI URL Obtained=  " + jndi);
      JBossRMIAdaptorHelper server = new JBossRMIAdaptorHelper(jndi);
      //Get the MBeanInfo for the Tomcat MBean
      ObjectName name = new ObjectName("jboss.web:service=WebServer");
      MBeanInfo info = server.getMBeanInfo(name);
      System.out.println("Tomcat MBean:" + info.getClassName());

      getLog().debug("Going to stop tomcat  ");
      //Going to stop the Tomcat Instance
      server.invokeOperation(name, "stop", null, null);
   }


   /**
    * Generate the JNDI Url for the JBoss Instance with instance number
    *
    * @param instancenum
    * @return
    */
   protected String getJNDIUrl(int instancenum)
   {
      String jndi = "";
      try {
         int num = instancenum - 1; //node0,node1 etc
         String key = "node" + num + ".jndiurl"; // node0.jndiurl
         jndi = System.getProperty(key);
      } catch (Exception e) {
         fail("getJNDIUrl Failed with:" + e.getMessage());
      }

      return jndi;
   }

   /**
    * Sleep for specified time
    *
    * @param secs
    * @throws Exception
    */
   protected void sleepThread(long secs)
         throws Exception
   {
      Thread.sleep(1000 * secs);
   }


   /**
    * Makes a http call to the jsp that retrieves the attribute stored on the
    * session. When the attribute values mathes with the one retrieved earlier,
    * we have HttpSessionReplication.
    * Makes use of commons-httpclient library of Apache
    *
    * @param client
    * @param method
    * @return session attribute
    */
   protected String makeGet(HttpClient client, HttpMethod method)
   {
      try {
         client.executeMethod(method);
      } catch (HttpRecoverableException e) {
         log.debug("A recoverable exception occurred, retrying." +
               e.getMessage());
      } catch (IOException e) {
         log.debug(e);
         e.printStackTrace();
         System.exit(-1);
      }

      // Read the response body.
      byte[] responseBody = method.getResponseBody();

      // Release the connection.
      method.releaseConnection();

      // Deal with the response.
      // Use caution: ensure correct character encoding and is not binary data
      return new String(responseBody);
   }

   /**
    * Checks whether the url is valid or not
    *
    * @param url The URL which should be checked
    * @return whether the url is up or not
    */
   protected boolean checkURL(String url)
   {
      boolean ok = false;
      if (url != null) url = url.trim();
      try {
         HttpClient httpConn = new HttpClient();
         GetMethod g = new GetMethod(url);
         int responseCode = httpConn.executeMethod(g);
         log.debug("Response Code for " + url + " is=" + responseCode);
         ok = responseCode == HttpURLConnection.HTTP_OK;
      } catch (Exception e) {
         log.debug("Exception for checking url=" + url);
         log.debug(e);
         ok = false;
      }
      return ok;
   }

   protected void restartTomcat(int instance) throws Exception
   {
      //    Shut down the first tomcat instance
      this.shutDownTomcatInstance(instance);
      getLog().debug("Brought down the tomcat instance: " + instance);

      String httpurl = System.getProperty("node0.http.url", "http://localhost:8080");
      String tmsg = "Is Tomcat really down?Tomcat Up(" + httpurl + ")=";
      boolean isOK = checkURL(httpurl);
      assertTrue("check URL should fail but is " + isOK, !isOK);
      getLog().debug(tmsg + isOK);


      // Restart tomcat instance
      getLog().debug("Will Start the Tomcat MBean back instance: " + instance);
      this.startTomcatInstance(instance);
      this.sleepThread(10);
      isOK = checkURL(httpurl);
      assertTrue("check URL should be ok but is " + isOK, isOK);
      getLog().debug("Tomcat Up=" + isOK);

   }
}
