content: /*
   * CDDL HEADER START
   *
   * The contents of this file are subject to the terms of the Common Development
   * and Distribution License (the "License").
   * You may not use this file except in compliance with the License.
   *
   * You can obtain a copy of the license at
   * src/com/vodafone360/people/VODAFONE.LICENSE.txt or
   * http://github.com/360/360-Engine-for-Android
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   * When distributing Covered Code, include this CDDL HEADER in each file and
   * include the License file at src/com/vodafone360/people/VODAFONE.LICENSE.txt.
   * If applicable, add the following below this CDDL HEADER, with the fields
   * enclosed by brackets "[]" replaced with your own identifying information:
   * Portions Copyright [yyyy] [name of copyright owner]
   *
   * CDDL HEADER END
   *
   * Copyright 2010 Vodafone Sales & Services Ltd.  All rights reserved.
   * Use is subject to license terms.
   */
  package com.vodafone360.people.service.transport.tcp;
  
  import java.io.DataInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.util.Hashtable;
  
  import com.vodafone360.people.datatypes.AuthSessionHolder;
  import com.vodafone360.people.engine.login.LoginEngine;
  import com.vodafone360.people.service.io.rpg.RpgHeader;
  import com.vodafone360.people.service.io.rpg.RpgMessageTypes;
  import com.vodafone360.people.service.transport.http.HttpConnectionThread;
  import com.vodafone360.people.service.utils.hessian.HessianEncoder;
  
  public class ConnectionTester {
      /**
       * We wait at least 59 seconds for a response from the server. After that we
       * return false.
       */
      private static final int MAX_TEST_RESPONSE_WAIT_TIME_MILLIS = 59 * 1000; // 59 seconds
  
  
      private DataInputStream mIs;
  
      private OutputStream mOs;
  
      public ConnectionTester(InputStream is, OutputStream os) {
          mIs = new DataInputStream(is);
          mOs = os;
      }
  
      /**
       * Starts a test by sending a test message to the RPG, which the RPG should
       * reply to.
       * 
       * @return True if the test succeeded, false if the RPG did not respond in a
       *         correct manner.
       */
      public boolean runTest() {
          if ((null == mIs) || (null == mOs)) {
              return false;
          }
  
          if (!sendTestMessage()) {
              HttpConnectionThread.logE("ConnectionTester.runTest()", "Could not send test message.",
                      null);
              return false;
          }
  
          if (!receiveTestResponse()) {
              HttpConnectionThread.logE("ConnectionTester.runTest()",
                      "Did not receive test response.", null);
              return false;
          }
  
          return true;
      }
  
      /**
       * Attempts to send a TCP test message (type 101) to the RPG.
       * 
       * @return True if sending happened without any exceptions false otherwise.
       */
      private boolean sendTestMessage() {
          try {
              HttpConnectionThread.logI("ConnectionTester.sentTestMessage()", "Sending TCP test request...");
              byte[] payload = getConnectionTestHessianPayload();
              mOs.write(payload);
          } catch (IOException ioe) {
              return false;
          } catch (Exception e) {
              return false;
          } finally {
              mOs = null; // clear reference
          }
  
          return true;
      }
  
      /**
       * Attempts to read any valid RPG response (even if it is not the requested TCP test
       * response)
       * 
       * @return True if we were able to receive an RPG response, otherwise false will 
       * be returned.
       */
      private boolean receiveTestResponse() {
          int waitingTimeMillis = 0;
  
          try {
              // wait until we have bytes available or we have waited for MAX_WAIT_TIME_MILLIS
              while (mIs.available() <= 0) {
                  if (waitingTimeMillis <= MAX_TEST_RESPONSE_WAIT_TIME_MILLIS) {
                      try {
                          Thread.sleep(200);
                          waitingTimeMillis += 200;
                      } catch (InterruptedException ie) {
                      }
                  } else {
                      return false;   // we timed out waiting for bytes
                  }
              }
          } catch (IOException ioe) {
              return false;
          } finally {
              mIs = null; // clear reference
          }
  
          HttpConnectionThread.logI("ConnectionTester.receiveTestResponse()", "Connection test successful!!");
          return true;
      }
  
      /**
       * Returns a byte-array containing the data needed for sending a connection
       * test to the RPG.
       * 
       * @throws IOException If there was an exception serializing the hash map to
       *             a hessian byte array.
       * @return A byte array representing the connection test request.
       */
      private byte[] getConnectionTestHessianPayload() throws IOException {
          // hash table for parameters to Hessian encode
          final Hashtable<String, Object> ht = new Hashtable<String, Object>();
  
          final AuthSessionHolder auth = LoginEngine.getSession();
          ht.put("userid", auth.userID);
  
          // do Hessian encoding
          final byte[] payload = HessianEncoder.createHessianByteArray("", ht);
          payload[1] = (byte)1;
          payload[2] = (byte)0;
  
          final int reqLength = RpgHeader.HEADER_LENGTH + payload.length;
  
          final RpgHeader rpgHeader = new RpgHeader();
          rpgHeader.setPayloadLength(payload.length);
          rpgHeader.setReqType(RpgMessageTypes.RPG_TCP_CONNECTION_TEST);
  
          final byte[] rpgMsg = new byte[reqLength];
          System.arraycopy(rpgHeader.createHeader(), 0, rpgMsg, 0, RpgHeader.HEADER_LENGTH);
  
          if (null != payload) {
              System.arraycopy(payload, 0, rpgMsg, RpgHeader.HEADER_LENGTH, payload.length);
          }
  
          return rpgMsg;
      }
  }
  