public static JobSuiteStatusSnapshot create( IJob rootJob, ILogManager logManager) { if (rootJob == null) { throw new IllegalArgumentException("Root job cannot be null."); } return new JobSuiteStatusSnapshot( createTreeNode(null, rootJob), logManager); } private static JobStatusTreeNode createTreeNode(
private void accept(IJobStatusVisitor visitor, String jobId) { if (visitor != null) { visitor.visitJobStatus(getJobStatus(jobId)); for (IJobStatus child : getChildren(jobId)) { accept(visitor, child.getJobId()); } } }
private JobSuiteStatusSnapshot( JobStatusTreeNode rootNode, ILogManager logManager) { this.logManager = logManager; this.rootNode = rootNode; flattenNode(rootNode); }
private void toString(StringBuilder b, String jobId, int depth) { IJobStatus status = getJobStatus(jobId); b.append(StringUtils.repeat(' ', depth * TO_STRING_INDENT)); b.append(StringUtils.leftPad(new PercentFormatter().format( status.getProgress()), TO_STRING_INDENT)); b.append(" ").append(status.getJobId()); b.append(System.lineSeparator()); for (IJobStatus child : getChildren(jobId)) { toString(b, child.getJobId(), depth + 1); } } }
private void initialize(boolean resumeIfIncomplete) throws IOException { JobSuiteStatusSnapshot statusTree = JobSuiteStatusSnapshot.newSnapshot(getSuiteIndexFile()); if (statusTree != null) { LOG.info("Previous execution detected."); MutableJobStatus status = (MutableJobStatus) statusTree.getRoot(); JobState state = status.getState(); ensureValidExecutionState(state); if (resumeIfIncomplete && !state.isOneOf( JobState.COMPLETED, JobState.PREMATURE_TERMINATION)) { LOG.info("Resuming from previous execution."); prepareStatusTreeForResume(statusTree); } else { // Back-up so we can start clean LOG.info("Backing up previous execution status and log files."); backupSuite(statusTree); statusTree = null; } } else { LOG.info("No previous execution detected."); } if (statusTree == null) { statusTree = JobSuiteStatusSnapshot.create( getRootJob(), getLogManager()); writeJobSuiteIndex(statusTree); } this.jobSuiteStatusSnapshot = statusTree; }
public IJobStatus getJobStatus(String jobId) { if (jobSuiteStatusSnapshot != null) { return jobSuiteStatusSnapshot.getJobStatus(jobId); } try { File indexFile = JEFUtil.getSuiteIndexFile(getWorkdir(), getId()); JobSuiteStatusSnapshot snapshot = JobSuiteStatusSnapshot.newSnapshot(indexFile); if (snapshot != null) { return snapshot.getJobStatus(jobId); } return null; } catch (IOException e) { throw new JEFException("Cannot obtain suite status.", e); } }
return new JobSuiteStatusSnapshot(loadTreeNode( null, xml.configurationAt("job"), suiteName, serial), logManager);
private void backupSuite(JobSuiteStatusSnapshot statusTree) throws IOException { IJobStatus suiteStatus = statusTree.getRoot(); Date backupDate = suiteStatus.getDuration().getEndTime(); if (backupDate == null) { List<IJobStatus> statuses = statusTree.getJobStatusList(); for (IJobStatus jobStatus : statuses) { getJobStatusStore().backup(
public IJobStatus getJobStatus(IJob job) { return getJobStatus(job.getId()); } public IJobStatus getJobStatus(String jobId) {
public List<IJobStatus> getChildren(IJobStatus jobStatus) { return getChildren(jobStatus.getJobId()); } public List<IJobStatus> getChildren(String jobId) {
public IJobStatus getParent(IJobStatus jobStatus) { return getParent(jobStatus.getJobId()); } public IJobStatus getParent(String jobId) {
public void accept(IJobStatusVisitor visitor) { jobSuiteStatusSnapshot.accept(visitor); }
private void writeJobSuiteIndex(JobSuiteStatusSnapshot statusTree) throws IOException { File indexFile = getSuiteIndexFile(); StringWriter out = new StringWriter(); out.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); out.write("<suite-index>"); //--- Log Manager --- out.flush(); getLogManager().saveToXML(out); //--- JobStatusSerializer --- out.flush(); getJobStatusStore().saveToXML(out); //--- Job Status --- writeJobId(out, statusTree, statusTree.getRoot()); out.write("</suite-index>"); out.flush(); // Using RandomAccessFile since evidence has shown it is better at // dealing with files/locks in a way that cause less/no errors. try (RandomAccessFile ras = new RandomAccessFile(indexFile, "rwd"); FileChannel channel = ras.getChannel(); FileLock lock = channel.lock()) { ras.writeUTF(out.toString()); } }
private static JobStatusTreeNode createTreeNode( IJobStatus parentStatus, IJob job) { IJobStatus status = new MutableJobStatus(job.getId()); List<JobStatusTreeNode> childNodes = new ArrayList<>(); if (job instanceof IJobGroup) { IJob[] jobs = ((IJobGroup) job).getJobs(); for (IJob childJob : jobs) { JobStatusTreeNode childNode = createTreeNode(status, childJob); if (childNode != null) { childNodes.add(childNode); } } } return new JobStatusTreeNode(parentStatus, status, childNodes); }
private void accept( IJobVisitor visitor, IJob job, Class<IJob> jobClassFilter) { if (job == null) { return; } if (jobClassFilter == null || jobClassFilter.isInstance(job)) { IJobStatus status = null; if (jobSuiteStatusSnapshot != null) { status = jobSuiteStatusSnapshot.getJobStatus(job); } visitor.visitJob(job, status); } if (job instanceof IJobGroup) { for (IJob childJob : ((IJobGroup) job).getJobs()) { accept(visitor, childJob, jobClassFilter); } } }
private void writeJobId(Writer out, JobSuiteStatusSnapshot statusTree, IJobStatus status) throws IOException { out.write("<job name=\""); out.write(StringEscapeUtils.escapeXml10(status.getJobId())); out.write("\">"); for (IJobStatus child : statusTree.getChildren(status)) { writeJobId(out, statusTree, child); } out.write("</job>"); }
@Override protected void statusUpdated(MutableJobStatus status) { try { getJobStatusStore().write(getId(), status); } catch (IOException e) { throw new JEFException( "Cannot persist status update for job: " + status.getJobId(), e); } fire(jobLifeCycleListeners, "jobProgressed", status); IJobStatus parentStatus = jobSuiteStatusSnapshot.getParent(status); if (parentStatus != null) { IJobGroup jobGroup = (IJobGroup) jobs.get(parentStatus.getJobId()); if (jobGroup != null) { jobGroup.groupProgressed(status); } } } }, this);
private void prepareStatusTreeForResume(JobSuiteStatusSnapshot statusTree) { statusTree.accept(new IJobStatusVisitor() { @Override public void visitJobStatus(IJobStatus jobStatus) { MutableJobStatus status = (MutableJobStatus) jobStatus; status.setStopRequested(false); JobDuration duration = status.getDuration(); if (status.isStarted() && !status.isCompleted()) { status.incrementResumeAttempts(); if (duration != null) { duration.setResumedStartTime( duration.getStartTime()); duration.setResumedLastActivity( status.getLastActivity()); } } } }); }