001/*
002 * #%L
003 * Netarchivesuite - archive
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.archive.checksum.distribute;
024
025import java.io.File;
026
027import org.slf4j.Logger;
028import org.slf4j.LoggerFactory;
029
030import dk.netarkivet.archive.distribute.ArchiveMessage;
031import dk.netarkivet.archive.distribute.ArchiveMessageVisitor;
032import dk.netarkivet.common.distribute.ChannelID;
033import dk.netarkivet.common.distribute.RemoteFile;
034import dk.netarkivet.common.exceptions.ArgumentNotValid;
035import dk.netarkivet.common.exceptions.IOFailure;
036
037/**
038 * The message to correct a bad entry in an archive. <li>In a bitarchive it should replace a corrupted file.</li> <li>In
039 * a checksum archive it should replace checksum entry of the file.</li> <br>
040 * The message contains the checksum of the 'bad' entry in the archive, which is only corrected if it actually has this
041 * 'bad checksum'.
042 */
043@SuppressWarnings({"serial"})
044public class CorrectMessage extends ArchiveMessage {
045
046    private static final Logger log = LoggerFactory.getLogger(CorrectMessage.class);
047
048    /** The file to replace the current bad entry. */
049    private RemoteFile theRemoteFile;
050    /** The name of the arc-file. */
051    private String arcFilename;
052    /** The 'bad' checksum. */
053    private String theIncorrectChecksum;
054    /** The replica, where this message should be sent. */
055    private String replicaId;
056    /** The credentials to allow the correction of the archive entry. */
057    private String credentials;
058    /** The 'removed' file, which has to be returned. */
059    private RemoteFile removedFile;
060
061    /**
062     * Constructor. Initializes the variables.
063     *
064     * @param to Where the message should be sent.
065     * @param replyTo Who is sending this message.
066     * @param badChecksum The checksum of the 'bad' entry.
067     * @param rf The remote file to replace the 'bad' entry.
068     * @param repId The identification of the replica, where this message should be sent.
069     * @param cred The credentials to allow the correction of an entry.
070     * @throws ArgumentNotValid If any of the arguments are null, or any of the strings are empty.
071     */
072    public CorrectMessage(ChannelID to, ChannelID replyTo, String badChecksum, RemoteFile rf, String repId, String cred)
073            throws ArgumentNotValid {
074        super(to, replyTo);
075        // Validate arguments ('super' validates the channels).
076        ArgumentNotValid.checkNotNull(rf, "RemoteFile file");
077        ArgumentNotValid.checkNotNullOrEmpty(badChecksum, "String badChecksum");
078        ArgumentNotValid.checkNotNullOrEmpty(repId, "String repId");
079        ArgumentNotValid.checkNotNullOrEmpty(cred, "String cred");
080        this.theIncorrectChecksum = badChecksum;
081        this.theRemoteFile = rf;
082        this.arcFilename = rf.getName();
083        this.replicaId = repId;
084        this.credentials = cred;
085    }
086
087    /**
088     * Retrieve name of the uploaded file.
089     *
090     * @return current value of arcfileName
091     */
092    public String getArcfileName() {
093        return arcFilename;
094    }
095
096    /**
097     * Retrieves the content of the remoteFile and writes it into the local file. Note: This is transferred through a
098     * remote file handle, and then the handle is invalidated. This method may only be called once.
099     *
100     * @param toFile where to write the content
101     * @throws IOFailure on error reading the remote file or writing the local file
102     * @throws ArgumentNotValid If <b>toFile</b> is null.
103     */
104    public void getData(File toFile) throws IOFailure, ArgumentNotValid {
105        ArgumentNotValid.checkNotNull(toFile, "toFile");
106
107        // ensure that the local file exists.
108        if (theRemoteFile == null) {
109            throw new IOFailure("No remoteFile in this message.");
110        }
111        // retrieve the data.
112        theRemoteFile.copyTo(toFile);
113        try {
114            // cleanup afterwards.
115            theRemoteFile.cleanup();
116        } catch (IOFailure e) {
117            // Just log errors on deleting. They are fairly harmless.
118            // Can't make Logger a field, as this class is Serializable
119            log.warn("Could not cleanup remote file {}", theRemoteFile.getName());
120        }
121        theRemoteFile = null;
122    }
123
124    /**
125     * Method for retrieving the correct file.
126     *
127     * @return The RemoteFile for the correct file.
128     */
129    public RemoteFile getCorrectFile() {
130        return theRemoteFile;
131    }
132
133    /**
134     * Method for retrieving the 'bad' checksum which should correspond to the checksum of the current entry on this
135     * file in the archive.
136     *
137     * @return The checksum for the archive entry.
138     */
139    public String getIncorrectChecksum() {
140        return theIncorrectChecksum;
141    }
142
143    /**
144     * Method for retrieving the replica, where this message should be sent.
145     *
146     * @return The id of the replica where this message should be sent.
147     */
148    public String getReplicaId() {
149        return replicaId;
150    }
151
152    /**
153     * The credentials to allow correction of an entry in the archive.
154     *
155     * @return The credentials.
156     */
157    public String getCredentials() {
158        return credentials;
159    }
160
161    /**
162     * Returns the removed file.
163     *
164     * @return The removed file.
165     * @throws IOFailure If the removed file is null.
166     */
167    public RemoteFile getRemovedFile() throws IOFailure {
168        if (removedFile == null) {
169            log.warn("The removed file is null. Perhaps the message has not been sent.");
170        }
171        return removedFile;
172    }
173
174    /**
175     * Sets the removed file. This is the file which are returned to the sender of the message.
176     *
177     * @param rf The removed file which is part of the reply of this message.
178     * @throws ArgumentNotValid If the remote file is null.
179     */
180    public void setRemovedFile(RemoteFile rf) throws ArgumentNotValid {
181        ArgumentNotValid.checkNotNull(rf, "RemoteFile rf");
182        removedFile = rf;
183    }
184
185    /**
186     * Accept this message.
187     *
188     * @param v The message visitor accepting this message.
189     */
190    public void accept(ArchiveMessageVisitor v) {
191        v.visit(this);
192    }
193
194    /**
195     * Generate String representation of this object.
196     *
197     * @return String representation of this object
198     */
199    public String toString() {
200        return super.toString() + ", Arcfile: " + arcFilename + ", Removed: " + (removedFile != null);
201    }
202
203}