extensions/net.sf.basedb.opengrid/trunk/src/net/sf/basedb/opengrid/CmdResult.java

Code
Comments
Other
Rev Date Author Line
4067 02 Sep 16 nicklas 1 package net.sf.basedb.opengrid;
4067 02 Sep 16 nicklas 2
5984 10 Jul 20 nicklas 3 import java.util.Date;
5984 10 Jul 20 nicklas 4
4257 30 Nov 16 nicklas 5 import org.json.simple.JSONObject;
4067 02 Sep 16 nicklas 6
5984 10 Jul 20 nicklas 7 import net.sf.basedb.opengrid.config.ClusterConfig;
4257 30 Nov 16 nicklas 8 import net.sf.basedb.opengrid.json.JSONOptions;
5984 10 Jul 20 nicklas 9 import net.sf.basedb.util.formatter.DateFormatter;
4257 30 Nov 16 nicklas 10
4067 02 Sep 16 nicklas 11 /**
4067 02 Sep 16 nicklas 12   Holds the result from executing a single command on a cluster.
4067 02 Sep 16 nicklas 13
4067 02 Sep 16 nicklas 14   @author nicklas
4067 02 Sep 16 nicklas 15   @since 1.0
4067 02 Sep 16 nicklas 16 */
4212 08 Nov 16 nicklas 17 public class CmdResult<R> 
4067 02 Sep 16 nicklas 18 {
4067 02 Sep 16 nicklas 19   private final String cmd;
4067 02 Sep 16 nicklas 20   private int exitStatus;
4067 02 Sep 16 nicklas 21   private String stdout;
4067 02 Sep 16 nicklas 22   private String stderr;
4212 08 Nov 16 nicklas 23   private R result;
4310 17 Jan 17 nicklas 24   private RuntimeException exception;
4067 02 Sep 16 nicklas 25   
4067 02 Sep 16 nicklas 26   /**
4067 02 Sep 16 nicklas 27     Creates a new result instance.
4067 02 Sep 16 nicklas 28   */
4067 02 Sep 16 nicklas 29   public CmdResult(String cmd)
4067 02 Sep 16 nicklas 30   {
4067 02 Sep 16 nicklas 31     this.cmd = cmd;
4067 02 Sep 16 nicklas 32   }
4067 02 Sep 16 nicklas 33   
4212 08 Nov 16 nicklas 34   /**
4222 09 Nov 16 nicklas 35     Clone a cmd result instance except for the result field.
4222 09 Nov 16 nicklas 36   */
5984 10 Jul 20 nicklas 37   public CmdResult(CmdResult<?> other)
4222 09 Nov 16 nicklas 38   {
4222 09 Nov 16 nicklas 39     this.cmd = other.cmd;
4222 09 Nov 16 nicklas 40     this.exitStatus = other.exitStatus;
4222 09 Nov 16 nicklas 41     this.stdout = other.stdout;
4222 09 Nov 16 nicklas 42     this.stderr = other.stderr;
4222 09 Nov 16 nicklas 43     this.exception = other.exception;
4222 09 Nov 16 nicklas 44   }
4222 09 Nov 16 nicklas 45   
4222 09 Nov 16 nicklas 46   /**
4212 08 Nov 16 nicklas 47     Get the command that was executed.
4212 08 Nov 16 nicklas 48   */
4212 08 Nov 16 nicklas 49   public String getCmd()
4212 08 Nov 16 nicklas 50   {
4212 08 Nov 16 nicklas 51     return cmd;
4212 08 Nov 16 nicklas 52   }
4212 08 Nov 16 nicklas 53   
6072 20 Nov 20 nicklas 54   /**
6072 20 Nov 20 nicklas 55     Calculate a hard timeout for the command that depends on the given 
6072 20 Nov 20 nicklas 56     soft timeout. The soft timeout is the timeout that is given to 
6072 20 Nov 20 nicklas 57     {@link AbstractSession#execute(CmdResult, int)}. If the command has not
6072 20 Nov 20 nicklas 58     finished after the soft timeout it is allowed to continue as long as it
6072 20 Nov 20 nicklas 59     is providing data on either the stdout or stderr stream until the 
6072 20 Nov 20 nicklas 60     hard timeout is reached. If this happens the command is aborted.
6072 20 Nov 20 nicklas 61     
6072 20 Nov 20 nicklas 62     The default implementation allows a hard timeout that is 10 times
6072 20 Nov 20 nicklas 63     longer than the soft timeout. Subclasses may override this implementation
6072 20 Nov 20 nicklas 64     if the need a different timeout.
6072 20 Nov 20 nicklas 65     
6072 20 Nov 20 nicklas 66     @param timeout The soft timeout in seconds
6072 20 Nov 20 nicklas 67     @return The hard timeout in seconds
6072 20 Nov 20 nicklas 68     @since 1.4
6072 20 Nov 20 nicklas 69   */
6072 20 Nov 20 nicklas 70   public int getHardTimeout(int timeout)
6072 20 Nov 20 nicklas 71   {
6072 20 Nov 20 nicklas 72     return timeout * 10;
6072 20 Nov 20 nicklas 73   }
6072 20 Nov 20 nicklas 74   
5984 10 Jul 20 nicklas 75   protected void setExitStatus(int exitStatus)
4067 02 Sep 16 nicklas 76   {
4067 02 Sep 16 nicklas 77     this.exitStatus = exitStatus;
4067 02 Sep 16 nicklas 78   }
4067 02 Sep 16 nicklas 79   
4067 02 Sep 16 nicklas 80   /**
4067 02 Sep 16 nicklas 81     Get the exit status of the command. A value of 0 should indicate success,
4067 02 Sep 16 nicklas 82     all other values some kind of error.
4067 02 Sep 16 nicklas 83   */
4067 02 Sep 16 nicklas 84   public int getExitStatus()
4067 02 Sep 16 nicklas 85   {
4067 02 Sep 16 nicklas 86     return exitStatus;
4067 02 Sep 16 nicklas 87   }
4067 02 Sep 16 nicklas 88   
5984 10 Jul 20 nicklas 89   protected void setResult(R result)
4212 08 Nov 16 nicklas 90   {
4212 08 Nov 16 nicklas 91     this.result = result;
4212 08 Nov 16 nicklas 92   }
4212 08 Nov 16 nicklas 93   
4212 08 Nov 16 nicklas 94   /**
4212 08 Nov 16 nicklas 95     Get the result that was parsed from the command output.
4212 08 Nov 16 nicklas 96     Normally, the result is only available if the exit status 
4212 08 Nov 16 nicklas 97     is 0. However the {@link OpenGridSession#executeCmd(String, int)} 
4212 08 Nov 16 nicklas 98     will return stderr as the result if the command failed.
4212 08 Nov 16 nicklas 99   */
4212 08 Nov 16 nicklas 100   public R getResult()
4212 08 Nov 16 nicklas 101   {
4212 08 Nov 16 nicklas 102     return result;
4212 08 Nov 16 nicklas 103   }
4212 08 Nov 16 nicklas 104   
5984 10 Jul 20 nicklas 105   protected void setStdout(String stdout)
4067 02 Sep 16 nicklas 106   {
4067 02 Sep 16 nicklas 107     this.stdout = stdout;
4067 02 Sep 16 nicklas 108   }
4067 02 Sep 16 nicklas 109   /**
4067 02 Sep 16 nicklas 110     Get the text written to the standard output stream from the command.
4067 02 Sep 16 nicklas 111   */
4067 02 Sep 16 nicklas 112   public String getStdout()
4067 02 Sep 16 nicklas 113   {
4067 02 Sep 16 nicklas 114     return stdout;
4067 02 Sep 16 nicklas 115   }
4067 02 Sep 16 nicklas 116   
5984 10 Jul 20 nicklas 117   protected void setStderr(String stderr)
4067 02 Sep 16 nicklas 118   {
4067 02 Sep 16 nicklas 119     this.stderr = stderr;
4067 02 Sep 16 nicklas 120   }
4067 02 Sep 16 nicklas 121   /**
4067 02 Sep 16 nicklas 122     Get the text written to standard error stream from the command.
4067 02 Sep 16 nicklas 123   */
4067 02 Sep 16 nicklas 124   public String getStderr()
4067 02 Sep 16 nicklas 125   {
4067 02 Sep 16 nicklas 126     return stderr;
4067 02 Sep 16 nicklas 127   }
4067 02 Sep 16 nicklas 128   
5984 10 Jul 20 nicklas 129   protected void setException(Exception ex)
4067 02 Sep 16 nicklas 130   {
4310 17 Jan 17 nicklas 131     this.exception = ex instanceof RuntimeException ? (RuntimeException)ex : new RuntimeException(ex);
4067 02 Sep 16 nicklas 132     this.stderr = ex.getMessage();
4067 02 Sep 16 nicklas 133     this.exitStatus = -1;
4067 02 Sep 16 nicklas 134   }
4067 02 Sep 16 nicklas 135   /**
4067 02 Sep 16 nicklas 136     Get the exception that may have caused a failure. Exception are typically
4067 02 Sep 16 nicklas 137     indications that something was wrong on the local server and not the
4067 02 Sep 16 nicklas 138     remote server.
4067 02 Sep 16 nicklas 139   */
4310 17 Jan 17 nicklas 140   public RuntimeException getException()
4067 02 Sep 16 nicklas 141   {
4067 02 Sep 16 nicklas 142     return exception;
4067 02 Sep 16 nicklas 143   }
4310 17 Jan 17 nicklas 144   
4310 17 Jan 17 nicklas 145   /**
4310 17 Jan 17 nicklas 146     Throws an exception if the exist status is not 0. If an exception
4310 17 Jan 17 nicklas 147     has been set by {@link #setException(Exception)} that exception is 
4310 17 Jan 17 nicklas 148     re-thrown, otherwise a new RuntimeException is created with stderr
4310 17 Jan 17 nicklas 149     (or stdout in case stderr is empty) as the message text.
4310 17 Jan 17 nicklas 150    */
4310 17 Jan 17 nicklas 151   public void throwExceptionIfNonZeroExitStatus()
4310 17 Jan 17 nicklas 152   {
4310 17 Jan 17 nicklas 153     if (exitStatus == 0) return;
4310 17 Jan 17 nicklas 154     RuntimeException e = exception;
4310 17 Jan 17 nicklas 155     if (e == null) 
4310 17 Jan 17 nicklas 156     {
4310 17 Jan 17 nicklas 157       e = new RuntimeException(stderr != null ? stderr : stdout);
4310 17 Jan 17 nicklas 158     }
4310 17 Jan 17 nicklas 159     throw e;
4310 17 Jan 17 nicklas 160   }
4310 17 Jan 17 nicklas 161   
5984 10 Jul 20 nicklas 162   /**
5984 10 Jul 20 nicklas 163     This method is called after the command has been executed and
5984 10 Jul 20 nicklas 164     the exit code, stdout and stderr has been updated. Subclasses
5984 10 Jul 20 nicklas 165     can override this method to take actions. The default implementation
5984 10 Jul 20 nicklas 166     does nothing.
5984 10 Jul 20 nicklas 167    */
5984 10 Jul 20 nicklas 168   protected void parseResult()
5984 10 Jul 20 nicklas 169   {}
5984 10 Jul 20 nicklas 170   
4067 02 Sep 16 nicklas 171   @Override
4067 02 Sep 16 nicklas 172   public String toString()
4067 02 Sep 16 nicklas 173   {
4067 02 Sep 16 nicklas 174     if (exitStatus == 0)
4067 02 Sep 16 nicklas 175     {
4067 02 Sep 16 nicklas 176       return cmd + ": " + stdout;
4067 02 Sep 16 nicklas 177     }
4067 02 Sep 16 nicklas 178     else
4067 02 Sep 16 nicklas 179     {
4067 02 Sep 16 nicklas 180       return cmd + ": [" + exitStatus + "] " + stderr;
4067 02 Sep 16 nicklas 181     }
4067 02 Sep 16 nicklas 182   }
4257 30 Nov 16 nicklas 183   
4257 30 Nov 16 nicklas 184   /**
4257 30 Nov 16 nicklas 185     Get the information in this result as a JSON object.
4257 30 Nov 16 nicklas 186     The following properties are set by default:
4067 02 Sep 16 nicklas 187
4257 30 Nov 16 nicklas 188     * cmd
4257 30 Nov 16 nicklas 189     * exitStatus
4257 30 Nov 16 nicklas 190     * stdout
4257 30 Nov 16 nicklas 191     * stderr
4257 30 Nov 16 nicklas 192   */
4257 30 Nov 16 nicklas 193   public JSONObject asJSONObject(JSONOptions options)
4257 30 Nov 16 nicklas 194   {
4257 30 Nov 16 nicklas 195     JSONObject json = new JSONObject();
4257 30 Nov 16 nicklas 196     json.put("cmd", getCmd());
4257 30 Nov 16 nicklas 197     json.put("exitStatus", getExitStatus());
4257 30 Nov 16 nicklas 198     json.put("stdout", getStdout());
4257 30 Nov 16 nicklas 199     json.put("stderr", getStderr());
4257 30 Nov 16 nicklas 200     return json;
4257 30 Nov 16 nicklas 201   }
4257 30 Nov 16 nicklas 202
5984 10 Jul 20 nicklas 203   /**
5984 10 Jul 20 nicklas 204     An implementation that set the result to 'stdout' if
5984 10 Jul 20 nicklas 205     the exit code is 0, and to 'stderr' if not.
5984 10 Jul 20 nicklas 206     @since 1.4
5984 10 Jul 20 nicklas 207   */
5984 10 Jul 20 nicklas 208   public static class StdioResult
5984 10 Jul 20 nicklas 209     extends CmdResult<String>
5984 10 Jul 20 nicklas 210   {
5984 10 Jul 20 nicklas 211
5984 10 Jul 20 nicklas 212     public StdioResult(String cmd) 
5984 10 Jul 20 nicklas 213     {
5984 10 Jul 20 nicklas 214       super(cmd);
5984 10 Jul 20 nicklas 215     }
5984 10 Jul 20 nicklas 216
5984 10 Jul 20 nicklas 217     @Override
5984 10 Jul 20 nicklas 218     protected void parseResult() 
5984 10 Jul 20 nicklas 219     {
5984 10 Jul 20 nicklas 220       setResult(getExitStatus()==0 ? getStdout() : getStderr());
5984 10 Jul 20 nicklas 221     }
5984 10 Jul 20 nicklas 222   }
5984 10 Jul 20 nicklas 223   
5984 10 Jul 20 nicklas 224   /**
5984 10 Jul 20 nicklas 225     An implementation that parses the 'stdout' to a date
5984 10 Jul 20 nicklas 226     if the exit code is 0.
5984 10 Jul 20 nicklas 227     @since 1.4
5984 10 Jul 20 nicklas 228   */
5984 10 Jul 20 nicklas 229   public static class DateResult
5984 10 Jul 20 nicklas 230     extends CmdResult<Date>
5984 10 Jul 20 nicklas 231   {
5984 10 Jul 20 nicklas 232
5984 10 Jul 20 nicklas 233     private final DateFormatter dateFormat;
5984 10 Jul 20 nicklas 234     
5984 10 Jul 20 nicklas 235     /**
5984 10 Jul 20 nicklas 236       Create a date result using the default date format.
5984 10 Jul 20 nicklas 237       @see ClusterConfig#DATE_CMD
5984 10 Jul 20 nicklas 238     */
5984 10 Jul 20 nicklas 239     public DateResult(String cmd) 
5984 10 Jul 20 nicklas 240     {
5984 10 Jul 20 nicklas 241       this(cmd, ClusterConfig.DATE_CMD);
5984 10 Jul 20 nicklas 242     }
5984 10 Jul 20 nicklas 243     
5984 10 Jul 20 nicklas 244     /**
5984 10 Jul 20 nicklas 245       Create a date result using a custom date format.
5984 10 Jul 20 nicklas 246     */
5984 10 Jul 20 nicklas 247     public DateResult(String cmd, DateFormatter dateFormat)
5984 10 Jul 20 nicklas 248     {
5984 10 Jul 20 nicklas 249       super(cmd);
5984 10 Jul 20 nicklas 250       this.dateFormat = dateFormat;
5984 10 Jul 20 nicklas 251     }
5984 10 Jul 20 nicklas 252
5984 10 Jul 20 nicklas 253     @Override
5984 10 Jul 20 nicklas 254     protected void parseResult() 
5984 10 Jul 20 nicklas 255     {
5984 10 Jul 20 nicklas 256       if (getExitStatus() != 0) return;
5984 10 Jul 20 nicklas 257       try
5984 10 Jul 20 nicklas 258       {
5984 10 Jul 20 nicklas 259         setResult(dateFormat.parseString(getStdout()));
5984 10 Jul 20 nicklas 260       }
5984 10 Jul 20 nicklas 261       catch (RuntimeException ex)
5984 10 Jul 20 nicklas 262       {
5984 10 Jul 20 nicklas 263         setException(ex);
5984 10 Jul 20 nicklas 264       }
5984 10 Jul 20 nicklas 265     }
5984 10 Jul 20 nicklas 266   }
4067 02 Sep 16 nicklas 267 }