001 package org.hackystat.sensorshell.command; 002 003 import java.util.Date; 004 005 import org.hackystat.sensorbase.client.SensorBaseClient; 006 import org.hackystat.sensorshell.SensorShellProperties; 007 import org.hackystat.sensorshell.SingleSensorShell; 008 009 /** 010 * Implements the Ping command, which ensures that the SensorBase is reachable. 011 * @author Philip Johnson 012 */ 013 public class PingCommand extends Command { 014 015 /** The timeout in milliseconds, initialized from sensorshell.properties.*/ 016 private int timeout; 017 018 /** 019 * Creates the PingCommand. 020 * @param shell The sensorshell. 021 * @param properties The sensorproperties. 022 */ 023 public PingCommand(SingleSensorShell shell, SensorShellProperties properties) { 024 super(shell, properties); 025 this.timeout = properties.getPingTimeout() * 1000; 026 } 027 028 /** 029 * Does a ping on the hackystat server and returns true if the server was 030 * accessible. A ping-able server indicates the data will be sent to it, 031 * while a non-pingable server indicates that data will be stored offline. 032 * 033 * @return True if the server could be pinged. 034 */ 035 public boolean isPingable() { 036 return this.isPingable(this.timeout); 037 } 038 039 /** 040 * Does a ping on the hackystat server and returns true if the server was 041 * accessible. A ping-able server indicates the data will be sent to it, 042 * while a non-pingable server indicates that data will be stored offline. 043 * If the server is not reachable, or does not respond with given time frame, false will 044 * be returned. 045 * 046 * @param timeout Maximum seconds to wait for server response. A 0 value or negative 047 * value is equivalent to set time out to infinity. 048 * @return True if the server could be pinged. 049 */ 050 public boolean isPingable(int timeout) { 051 boolean result = false; 052 long startTime = new Date().getTime(); 053 PingWorkerThread workThread = new PingWorkerThread(this.host, this.email, this.password); 054 workThread.start(); 055 try { 056 workThread.join(timeout); //block this thread until work thread dies or times out. 057 } 058 catch (InterruptedException ex) { 059 //do nothing 060 } 061 //if work thread is still alive, then it's time out, result = false by default. 062 if (!workThread.isAlive()) { 063 result = workThread.serverPingable; 064 } 065 long elapsedTime = new Date().getTime() - startTime; 066 this.shell.println("Pinged " + this.host + " in " + elapsedTime + " ms. Result is: " + result); 067 return result; 068 } 069 070 /** 071 * Worker thread to ping the server to determine whether it's reachable or not. The original 072 * ping command is implemented as a synchronous command, a separate thread is need to 073 * implement time out feature. 074 * 075 * @author Qin ZHANG 076 */ 077 private static class PingWorkerThread extends Thread { 078 079 /** 080 * This instance will only be be accessed in the parent thread after the termination of this 081 * thread, there is no need to synchronize access. 082 */ 083 private boolean serverPingable = false; 084 private String host; 085 private String email; 086 private String password; 087 088 /** 089 * Constructs this worker thread. 090 * @param host The sensorbase host. 091 * @param email The client email. 092 * @param password The client password. 093 */ 094 public PingWorkerThread(String host, String email, String password) { 095 setDaemon(true); //want VM to terminate even if this thread is alive. 096 this.host = host; 097 this.email = email; 098 this.password = password; 099 } 100 101 /** Pings the server synchronously. */ 102 @Override 103 public void run() { 104 this.serverPingable = SensorBaseClient.isRegistered(this.host, this.email, this.password); 105 } 106 } 107 108 }