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);
   }
 }
 // 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);
   }
 }