public void updateJobOutput(
     String jobId, ExecutableState newStatus, Map<String, String> info, String output) {
   try {
     final ExecutableOutputPO jobOutput = executableDao.getJobOutput(jobId);
     Preconditions.checkArgument(
         jobOutput != null, "there is no related output for job id:" + jobId);
     ExecutableState oldStatus = ExecutableState.valueOf(jobOutput.getStatus());
     if (newStatus != null && oldStatus != newStatus) {
       if (!ExecutableState.isValidStateTransfer(oldStatus, newStatus)) {
         throw new IllegalStateTranferException(
             "there is no valid state transfer from:" + oldStatus + " to:" + newStatus);
       }
       jobOutput.setStatus(newStatus.toString());
     }
     if (info != null) {
       jobOutput.setInfo(info);
     }
     if (output != null) {
       jobOutput.setContent(output);
     }
     executableDao.updateJobOutput(jobOutput);
     logger.info("job id:" + jobId + " from " + oldStatus + " to " + newStatus);
   } catch (PersistentException e) {
     logger.error("error change job:" + jobId + " to " + newStatus.toString());
     throw new RuntimeException(e);
   }
 }
 private DefaultOutput parseOutput(ExecutableOutputPO jobOutput) {
   final DefaultOutput result = new DefaultOutput();
   result.setExtra(jobOutput.getInfo());
   result.setState(ExecutableState.valueOf(jobOutput.getStatus()));
   result.setVerboseMsg(jobOutput.getContent());
   result.setLastModified(jobOutput.getLastModified());
   return result;
 }
 // for migration only
 // TODO delete when migration finished
 public void resetJobOutput(String jobId, ExecutableState state, String output) {
   try {
     final ExecutableOutputPO jobOutput = executableDao.getJobOutput(jobId);
     jobOutput.setStatus(state.toString());
     if (output != null) {
       jobOutput.setContent(output);
     }
     executableDao.updateJobOutput(jobOutput);
   } catch (PersistentException e) {
     throw new RuntimeException(e);
   }
 }