code: protected void endOfJob() {
  
  
  		// 1. Execute the very last artifacts (jobListener)
  		try {
  			jobListenersAfterJob();
  		} catch (Throwable t) {
  			StringWriter sw = new StringWriter();
  			PrintWriter pw = new PrintWriter(sw);
  			t.printStackTrace(pw);
  			logger.warning("Error invoking jobListener.afterJob(). Stack trace: " + sw.toString());
  			batchStatusFailedFromException();
  		}
  
  		// 2. transition to final batch status
  		transitionToFinalBatchStatus();
  
  		// 3. default ExitStatus if necessary
  		if (jobContext.getExitStatus() == null) {
  			logger.fine("No job-level exitStatus set, defaulting to job batch Status = " + jobContext.getBatchStatus());
  			jobContext.setExitStatus(jobContext.getBatchStatus().name());
  		}
  
  		// 4. persist statuses and end time data
  		logger.fine("Job complete for job id=" + jobExecution.getJobInstance().getJobName() + ", executionId=" + jobExecution.getExecutionId() 
  				+ ", batchStatus=" + jobContext.getBatchStatus() + ", exitStatus=" + jobContext.getExitStatus());
  		persistJobBatchAndExitStatus();
  
  	}
docs: /*
  Follow similar pattern for end of step in BaseStepControllerImpl
  
  1. Execute the very last artifacts (jobListener)
  2. transition to final batch status
  3. default ExitStatus if necessary
  4. persist statuses and end time data
  
  We don't want to give up on the orderly process of 2,3,4, if we blow up
  in after job, so catch that and keep on going.