/*
 * JBoss, the OpenSource J2EE webOS
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.test.cluster.apache_tomcat;

import java.io.IOException;
import java.net.HttpURLConnection;

import junit.framework.Test;

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.ObjectName;
import javax.management.MBeanInfo;

/**
 * This testcase is written to test HttpSessionReplication with one apache webserver
 * loadbalancing multiple tomcat/JBoss instances.
 *
 * @author <a href="mailto:anil.saldhana@jboss.com">Anil Saldhana</a>.
 * @version $Revision: 1.0
 * @see org.jboss.test.cluster.apache_tomcat.HttpSessionReplicationTestCase
 */
public class HttpSessionReplicationTestCase
   extends JBossClusteredTestCase
{
   private String apacheurl = null;

   public HttpSessionReplicationTestCase(String name)
   {
      super(name);
/* try{
             this.getPropertiesFile();
             String numin = prop.getProperty("NumOfInstances");
             numInstances = Integer.parseInt( numin );
             if( numInstances < 2 ) fail( "Atleast two nodes needed");
             this.getLog().debug("Number of nodes="+numInstances);

             //Lets build up the jndi server urls now
             //this.setServerNames(servernames);
            }catch( Exception e){
                fail( e.getMessage());
            }  */
   }

   public static Test suite() throws Exception
   {
      Test t1 = JBossClusteredTestCase.getDeploySetup(HttpSessionReplicationTestCase.class,
         "http-sr.war");
      return t1;
   }

   /**
    * 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
      {
         /*String apacheurl =  prop.getProperty("ApacheUrl");
       getLog().debug(apacheurl);
assertTrue("Apache Up?", this.checkURL(apacheurl));*/
         apacheurl = System.getProperty("apache.url");
         getLog().debug(apacheurl);
         assertTrue("Apache Up?", this.checkURL(apacheurl));
      }
      catch (Exception e)
      {
         getLog().debug(e.getMessage());
      }
      getLog().debug("Exit testApacheConnection");
   }

   /**
    * Main method that deals with the Http Session Replication Test
    *
    * @throws Exception
    */
   public void testHttpSessionReplication()
      throws Exception
   {
      String attr = "";
      getLog().debug("Enter testHttpSessionReplication");

      apacheurl = System.getProperty("apache.url");
      String urlname = apacheurl + System.getProperty("apache.set.url");
      String geturlname = apacheurl + System.getProperty("apache.get.url");

      getLog().debug(urlname + ":::::::" + geturlname);

// Create an instance of HttpClient.
      HttpClient client = new HttpClient();

// Create a method instance.
      HttpMethod method = new GetMethod(geturlname);

//    Get the Attribute set by testsessionreplication.jsp
      attr = makeGet(client, method);

//    Shut down the first tomcat instance
      this.shutDownTomcatInstance(1);
      getLog().debug("Brought down the first tomcat instance");

      String[] httpURLs = super.getHttpURLs();
      String httpurl = httpURLs[0];
      String tmsg = "Is 1st Tomcat really down?Tomcat Up(" + httpurl + ")=";
      getLog().debug(tmsg + checkURL(httpurl));

//Give 30 seconds for things to stabilize.
      sleepThread(30);

//    Make connection
      method = new GetMethod(geturlname);
      String attr2 = makeGet(client, method);
      this.sleepThread(10);
      getLog().debug("Will Start the Tomcat MBean back");
      this.startTomcatInstance(1);
      this.sleepThread(10);
      getLog().debug("Tomcat Up=" + checkURL(httpurl));
      String tstr = "attr1=" + attr + " and attr2=" + attr2;
      if (!attr2.equals(attr)) fail("Http Session Replication failed with " + tstr);
      getLog().debug("Http Session Replication has happened");
      getLog().debug("Exit testHttpSessionReplication");
   }


   /**
    * Starts the Tomcat MBean running on a particular node
    *
    * @param instancenum Instance Number of the node
    * @throws Exception
    */
   private 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
    */
   private 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
    */
   private String getJNDIUrl(int instancenum)
   {
      String jndi = "";
      try
      {
         int num = instancenum - 1; //node0,node1 etc
         String key = "node" + num + ".jndi.url"; // 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
    */
   private 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
    */
   private 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
    */
   private 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;
   }

}