001/*
002 * #%L
003 * Netarchivesuite - common
004 * %%
005 * Copyright (C) 2005 - 2014 The Royal Danish Library, the Danish State and University Library,
006 *             the National Library of France and the Austrian National Library.
007 * %%
008 * This program is free software: you can redistribute it and/or modify
009 * it under the terms of the GNU Lesser General Public License as
010 * published by the Free Software Foundation, either version 2.1 of the
011 * License, or (at your option) any later version.
012 * 
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Lesser Public License for more details.
017 * 
018 * You should have received a copy of the GNU General Lesser Public
019 * License along with this program.  If not, see
020 * <http://www.gnu.org/licenses/lgpl-2.1.html>.
021 * #L%
022 */
023package dk.netarkivet.common.distribute.arcrepository;
024
025import java.io.File;
026import java.io.OutputStream;
027import java.util.Collection;
028import java.util.List;
029
030import dk.netarkivet.common.distribute.RemoteFile;
031import dk.netarkivet.common.exceptions.ArgumentNotValid;
032import dk.netarkivet.common.exceptions.IllegalState;
033import dk.netarkivet.common.utils.batch.FileBatchJob;
034import dk.netarkivet.common.utils.batch.FileBatchJob.ExceptionOccurrence;
035
036/**
037 * Class for transferring batch status information.
038 */
039public class BatchStatus {
040
041    /** The total number of files processed so far. */
042    private final int noOfFilesProcessed;
043    /** A list of files that the batch job could not process. */
044    private final Collection<File> filesFailed;
045    /** The application ID identifying the bitarchive, that run this batch job. */
046    private final String bitArchiveAppId;
047    /** The file containing the result of the batch job. */
048    private RemoteFile resultFile;
049
050    /** A list of exceptions caught during the execution of the batchJob. */
051    private final List<ExceptionOccurrence> exceptions;
052
053    /**
054     * Create a new BatchStatus object for a specific bitarchive.
055     *
056     * @param bitArchiveAppId The application ID identifying the bitarchive, that run this batch job.
057     * @param filesFailed A list of files that the batch job could not process.
058     * @param noOfFilesProcessed The total number of files processed
059     * @param resultFile A file containing the result of the batch job
060     * @param exceptions A list of exceptions caught during the execution of the batchJob
061     */
062    public BatchStatus(String bitArchiveAppId, Collection<File> filesFailed, int noOfFilesProcessed,
063            RemoteFile resultFile, List<FileBatchJob.ExceptionOccurrence> exceptions) {
064        this.bitArchiveAppId = bitArchiveAppId;
065        this.filesFailed = filesFailed;
066        this.noOfFilesProcessed = noOfFilesProcessed;
067        this.resultFile = resultFile;
068        this.exceptions = exceptions;
069    }
070
071    /**
072     * Create a new BatchStatus object for a specific bitarchive.
073     *
074     * @param filesFailed A list of files that the batch job could not process
075     * @param noOfFilesProcessed The total number of files processed
076     * @param resultFile A file containing the result of the batch job
077     * @param exceptions A list of exceptions caught during the execution of the batchJob
078     */
079    public BatchStatus(Collection<File> filesFailed, int noOfFilesProcessed, RemoteFile resultFile,
080            List<FileBatchJob.ExceptionOccurrence> exceptions) {
081        this("ALL_BITARCHIVE_APPS", filesFailed, noOfFilesProcessed, resultFile, exceptions);
082    }
083
084    /**
085     * Get the number of files processed by the batch job. This counts all files whether failed or not.
086     *
087     * @return number of files passed to processFile
088     */
089    public int getNoOfFilesProcessed() {
090        return noOfFilesProcessed;
091    }
092
093    /**
094     * Get the File objects for the files that failed.
095     *
096     * @return A collection containing the files that processFile returned false on.
097     */
098    public Collection<File> getFilesFailed() {
099        return filesFailed;
100    }
101
102    /**
103     * Get the appId (internal string) for the bitarchive that these are the results from. Set to ALL_BITARCHIVE_APPS if
104     * this it the combined status.
105     *
106     * @return A uniquely identifying string that should *not* be parsed
107     */
108    public String getBitArchiveAppId() {
109        return bitArchiveAppId;
110    }
111
112    /**
113     * Get the file containing results from a batch job. This may be null, if the batch job resulted in errors.
114     *
115     * @return A remote file containing results in some job-specific format.
116     */
117    public RemoteFile getResultFile() {
118        return resultFile;
119    }
120
121    /**
122     * Get the list of exceptions that happened during the batch job.
123     *
124     * @return List of exceptions with information on where they occurred.
125     */
126    public List<ExceptionOccurrence> getExceptions() {
127        return exceptions;
128    }
129
130    /**
131     * Copy the results of a batch job into a local file. This deletes the file from the remote server as appropriate.
132     * Note that this method or appendResults can only be called once on a given object. If hasResultFile() returns
133     * true, this method is safe to call.
134     *
135     * @param targetFile File to copy the results into. This file will be overridden if hasResultFile() returns true;
136     * @throws IllegalState If the results have already been copied, or there are no results to copy due to errors.
137     */
138    public void copyResults(File targetFile) throws IllegalState {
139        ArgumentNotValid.checkNotNull(targetFile, "targetFile");
140        if (resultFile != null) {
141            try {
142                resultFile.copyTo(targetFile);
143            } finally {
144                RemoteFile tmpResultFile = resultFile;
145                resultFile = null;
146                tmpResultFile.cleanup();
147            }
148        } else {
149            throw new IllegalState("No results to copy into '" + targetFile + "' from batch job on '" + bitArchiveAppId
150                    + "' (" + filesFailed.size() + " failures in " + noOfFilesProcessed + " processed files)");
151        }
152    }
153
154    /**
155     * Append the results of a batch job into a stream. This deletes the results file from the remote server, so this or
156     * copyResults can only be called once. If hasResultFile() returns true, this method is safe to call.
157     *
158     * @param stream A stream to append results to.
159     * @throws IllegalState If the results have already been copied, or there are no results to copy due to errors.
160     */
161    public void appendResults(OutputStream stream) throws IllegalState {
162        ArgumentNotValid.checkNotNull(stream, "OutputStream stream");
163        if (resultFile != null) {
164            try {
165                resultFile.appendTo(stream);
166            } finally {
167                RemoteFile tmpResultFile = resultFile;
168                resultFile = null;
169                tmpResultFile.cleanup();
170            }
171        } else {
172            throw new IllegalState("No results to append to '" + stream + "' from batch job on '" + bitArchiveAppId
173                    + "' (" + filesFailed.size() + " failures in " + noOfFilesProcessed + " processed files)");
174        }
175    }
176
177    /**
178     * Returns true if this object has a result file. There is no result file if no bitarchives succeeded in processing
179     * any files, or if the result file sent has already been deleted (e.g., by calling copyResults or appendResults).
180     *
181     * @return True if this object has a result file.
182     */
183    public boolean hasResultFile() {
184        return resultFile != null;
185    }
186
187    /**
188     * Returns a human-readable description of this object. The value returned should not be machine-processed, as it is
189     * subject to change without notice.
190     *
191     * @return Human-readable description of this object.
192     */
193    public String toString() {
194        return getFilesFailed().size() + " failures in processing " + getNoOfFilesProcessed() + " files at "
195                + getBitArchiveAppId();
196    }
197
198}