Java tutorial
/* Copyright 2010-2014 Norconex Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.norconex.jef4.status; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.commons.collections4.map.ListOrderedMap; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.XMLConfiguration; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; import com.norconex.commons.lang.PercentFormatter; import com.norconex.commons.lang.config.ConfigurationUtil; import com.norconex.commons.lang.file.FileUtil; import com.norconex.jef4.job.IJob; import com.norconex.jef4.job.group.IJobGroup; import com.norconex.jef4.log.ILogManager; public final class JobSuiteStatusSnapshot { private static final int TO_STRING_INDENT = 4; private final ILogManager logManager; private final JobStatusTreeNode rootNode; private Map<String, JobStatusTreeNode> flattenNodes = new ListOrderedMap<>(); private JobSuiteStatusSnapshot(JobStatusTreeNode rootNode, ILogManager logManager) { this.logManager = logManager; this.rootNode = rootNode; flattenNode(rootNode); } public IJobStatus getRoot() { return rootNode.jobStatus; } public IJobStatus getJobStatus(IJob job) { return getJobStatus(job.getId()); } public IJobStatus getJobStatus(String jobId) { JobStatusTreeNode node = flattenNodes.get(jobId); if (node != null) { return node.jobStatus; } return null; } public ILogManager getLogManager() { return logManager; } public List<IJobStatus> getJobStatusList() { List<IJobStatus> list = new ArrayList<>(flattenNodes.size()); for (JobStatusTreeNode node : flattenNodes.values()) { list.add(node.jobStatus); } return list; } public List<IJobStatus> getChildren(IJobStatus jobStatus) { return getChildren(jobStatus.getJobId()); } public List<IJobStatus> getChildren(String jobId) { JobStatusTreeNode node = flattenNodes.get(jobId); if (node == null) { return new ArrayList<IJobStatus>(0); } List<JobStatusTreeNode> nodes = node.children; List<IJobStatus> statuses = new ArrayList<>(nodes.size()); for (JobStatusTreeNode childNode : nodes) { statuses.add(childNode.jobStatus); } return statuses; } public IJobStatus getParent(IJobStatus jobStatus) { return getParent(jobStatus.getJobId()); } public IJobStatus getParent(String jobId) { JobStatusTreeNode node = flattenNodes.get(jobId); if (node == null) { return null; } return node.parentStatus; } public void accept(IJobStatusVisitor visitor) { accept(visitor, getRoot().getJobId()); } private void accept(IJobStatusVisitor visitor, String jobId) { if (visitor != null) { visitor.visitJobStatus(getJobStatus(jobId)); for (IJobStatus child : getChildren(jobId)) { accept(visitor, child.getJobId()); } } } private void flattenNode(JobStatusTreeNode node) { flattenNodes.put(node.jobStatus.getJobId(), node); for (JobStatusTreeNode childNode : node.children) { flattenNode(childNode); } } 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(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); } public static JobSuiteStatusSnapshot newSnapshot(File suiteIndex) throws IOException { //--- Ensure file looks good --- if (suiteIndex == null) { throw new IllegalArgumentException("Suite index file cannot be null."); } if (!suiteIndex.exists()) { return null; } if (!suiteIndex.isFile()) { throw new IllegalArgumentException("Suite index is not a file: " + suiteIndex.getAbsolutePath()); } //--- Load XML file --- String suiteName = FileUtil.fromSafeFileName(FilenameUtils.getBaseName(suiteIndex.getPath())); XMLConfiguration xml = new XMLConfiguration(); ConfigurationUtil.disableDelimiterParsing(xml); try { xml.load(suiteIndex); } catch (ConfigurationException e) { throw new IOException("Could not load suite index: " + suiteIndex, e); } //--- LogManager --- ILogManager logManager = ConfigurationUtil.newInstance(xml, "logManager"); //--- Load status tree --- IJobStatusStore serial = ConfigurationUtil.newInstance(xml, "statusStore"); return new JobSuiteStatusSnapshot(loadTreeNode(null, xml.configurationAt("job"), suiteName, serial), logManager); } private static JobStatusTreeNode loadTreeNode(IJobStatus parentStatus, HierarchicalConfiguration jobXML, String suiteName, IJobStatusStore store) throws IOException { if (jobXML == null) { return null; } String jobId = jobXML.getString("[@name]"); IJobStatus jobStatus = store.read(suiteName, jobId); List<HierarchicalConfiguration> xmls = jobXML.configurationsAt("job"); List<JobStatusTreeNode> childNodes = new ArrayList<JobStatusTreeNode>(); if (xmls != null) { for (HierarchicalConfiguration xml : xmls) { JobStatusTreeNode child = loadTreeNode(jobStatus, xml, suiteName, store); if (child != null) { childNodes.add(child); } } } return new JobStatusTreeNode(parentStatus, jobStatus, childNodes); } //--- Class: JobStatusTreeNode --------------------------------------------- public static class JobStatusTreeNode { private final IJobStatus parentStatus; private final IJobStatus jobStatus; private final List<JobStatusTreeNode> children; public JobStatusTreeNode(IJobStatus parentStatus, IJobStatus jobStatus, List<JobStatusTreeNode> children) { super(); this.parentStatus = parentStatus; this.jobStatus = jobStatus; if (children == null) { this.children = new ArrayList<>(0); } else { this.children = children; } } } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((flattenNodes == null) ? 0 : flattenNodes.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } JobSuiteStatusSnapshot other = (JobSuiteStatusSnapshot) obj; if (flattenNodes == null) { if (other.flattenNodes != null) { return false; } } else if (!flattenNodes.equals(other.flattenNodes)) { return false; } return true; } @Override public String toString() { final StringBuilder b = new StringBuilder(); toString(b, getRoot().getJobId(), 0); return b.toString(); } 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); } } }