/* * Copyright 2013 Robert von Burg <eitch@eitchnet.ch> * * 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 li.strolch.fileserver; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.rmi.RemoteException; import java.text.MessageFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import li.strolch.utils.helper.FileHelper; import li.strolch.utils.helper.StringHelper; /** * @author Robert von Burg <eitch@eitchnet.ch> * */ public class FileClientUtil { private static final Logger logger = LoggerFactory.getLogger(FileClientUtil.class); /** * @param rmiFileClient * @param origFilePart * @param dstFile */ public static void downloadFile(FileClient rmiFileClient, FilePart origFilePart, File dstFile) { // here we don't overwrite, the caller must make sure the destination file does not exist if (dstFile.exists()) { String msg = "The destination file {0} already exists. Delete it first, if you want to overwrite it!"; //$NON-NLS-1$ msg = MessageFormat.format(msg, dstFile.getAbsolutePath()); throw new RuntimeException(msg); } try { FilePart tmpPart = origFilePart; int loops = 0; int startLength = tmpPart.getPartLength(); while (true) { loops += 1; // get the next part tmpPart = rmiFileClient.requestFile(tmpPart); // validate length of data if (tmpPart.getPartLength() != tmpPart.getPartBytes().length) { String msg = "Invalid tmpPart. Part length is not as long as the bytes passed {0} / {1}"; //$NON-NLS-1$ msg = MessageFormat.format(msg, tmpPart.getPartLength(), tmpPart.getPartBytes().length); throw new RuntimeException(msg); } // validate offset is size of file if (tmpPart.getPartOffset() != dstFile.length()) { String msg = "The part offset $offset is not at the end of the file {0} / {1}"; //$NON-NLS-1$ msg = MessageFormat.format(msg, tmpPart.getPartOffset(), dstFile.length()); throw new RuntimeException(msg); } // append the part FileHelper.appendFilePart(dstFile, tmpPart.getPartBytes()); // update the offset tmpPart.setPartOffset(tmpPart.getPartOffset() + tmpPart.getPartBytes().length); // break if the offset is past the length of the file if (tmpPart.getPartOffset() >= tmpPart.getFileLength()) break; } String msg = "{0}: {1}: Requested {2} parts. StartSize: {3} EndSize: {4}"; //$NON-NLS-1$ msg = MessageFormat.format(msg, tmpPart.getFileType(), tmpPart.getFileName(), loops, startLength, tmpPart.getPartLength()); logger.info(msg); // validate that the offset is at the end of the file if (tmpPart.getPartOffset() != origFilePart.getFileLength()) { msg = "Offset {0} is not at file length {1} after reading all the file parts!"; //$NON-NLS-1$ msg = MessageFormat.format(msg, tmpPart.getPartOffset(), origFilePart.getFileLength()); throw new RuntimeException(msg); } // now validate hashes String dstFileHash = StringHelper.getHexString(FileHelper.hashFileSha256(dstFile)); if (!dstFileHash.equals(origFilePart.getFileHash())) { msg = "Downloading the file {0} failed because the hashes don''t match. Expected: {1} / Actual: {2}"; //$NON-NLS-1$ msg = MessageFormat.format(msg, origFilePart.getFileName(), origFilePart.getFileHash(), dstFileHash); throw new RuntimeException(msg); } } catch (Exception e) { if (e instanceof RuntimeException) throw (RuntimeException) e; String msg = "Downloading the file {0} failed because of an underlying exception {1}"; //$NON-NLS-1$ msg = MessageFormat.format(msg, origFilePart.getFileName(), e.getLocalizedMessage()); throw new RuntimeException(msg); } } /** * @param rmiFileClient * @param srcFile * @param fileType */ public static void uploadFile(FileClient rmiFileClient, File srcFile, String fileType) { // make sure the source file exists if (!srcFile.canRead()) { String msg = MessageFormat.format("The source file does not exist at {0}", srcFile.getAbsolutePath()); //$NON-NLS-1$ throw new RuntimeException(msg); } try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(srcFile));) { // get the size of the file long fileLength = srcFile.length(); String fileHash = StringHelper.getHexString(FileHelper.hashFileSha256(srcFile)); // create the file part to send FilePart filePart = new FilePart(srcFile.getName(), fileType); filePart.setFileLength(fileLength); filePart.setFileHash(fileHash); // define the normal size of the parts we're sending. The last part will naturally have a different size int partLength; if (fileLength > FileHandler.MAX_PART_SIZE) partLength = FileHandler.MAX_PART_SIZE; else partLength = (int) fileLength; // this is the byte array of data we're sending each time byte[] bytes = new byte[partLength]; // open the stream to the file int read = 0; int offset = 0; // loop by reading the number of bytes needed for each part int loops = 0; int startLength = partLength; while (true) { loops += 1; // read the bytes into the array read = inputStream.read(bytes); // validate we read the expected number of bytes if (read == -1) throw new IOException("Something went wrong while reading the bytes as -1 was returned!"); //$NON-NLS-1$ if (read != bytes.length) { String msg = "Something went wrong while reading the bytes as the wrong number of bytes were read. Expected {0} Actual: {1}"; //$NON-NLS-1$ msg = MessageFormat.format(msg, bytes.length, read); throw new IOException(msg); } // set the fields on the FilePart filePart.setPartBytes(bytes); filePart.setPartOffset(offset); filePart.setPartLength(bytes.length); // and if this is the last part, then also set that int nextOffset = offset + bytes.length; if (nextOffset == fileLength) filePart.setLastPart(true); // now send the part to the server rmiFileClient.uploadFilePart(filePart); // if this was the last part, then break if (filePart.isLastPart()) break; // otherwise update the offset for the next part by also making sure the next part is not larger than // the last part of the file if (nextOffset + bytes.length > fileLength) { long remaining = fileLength - nextOffset; if (remaining > FileHandler.MAX_PART_SIZE) { String msg = "Something went wrong as the remaining part {0} is larger than MAX_PART_SIZE {1}!"; //$NON-NLS-1$ msg = MessageFormat.format(msg, remaining, FileHandler.MAX_PART_SIZE); throw new RuntimeException(msg); } partLength = (int) remaining; bytes = new byte[partLength]; } // and save the offset for the next loop offset = nextOffset; } String msg = "{0}: {1}: Sent {2} parts. StartSize: {3} EndSize: {4}"; //$NON-NLS-1$ msg = MessageFormat.format(msg, filePart.getFileType(), filePart.getFileName(), loops, startLength, filePart.getPartLength()); logger.info(msg); } catch (Exception e) { if (e instanceof RuntimeException) throw (RuntimeException) e; String msg = "Uploading the file {0} failed because of an underlying exception {1}"; //$NON-NLS-1$ msg = MessageFormat.format(msg, srcFile.getAbsolutePath(), e.getLocalizedMessage()); throw new RuntimeException(msg); } } /** * @param rmiFileClient * @param fileDeletion * @param dstFile */ public static void deleteFile(FileClient rmiFileClient, FileDeletion fileDeletion, File dstFile) { try { rmiFileClient.deleteFile(fileDeletion); } catch (RemoteException e) { String msg = "Deleting the file {0} failed because of an underlying exception {1}"; //$NON-NLS-1$ msg = MessageFormat.format(msg, fileDeletion.getFileName(), e.getLocalizedMessage()); throw new RuntimeException(msg); } } }