diff options
Diffstat (limited to 'dozentenmodul/src/main/java/ftp/DownloadTask.java')
| -rw-r--r-- | dozentenmodul/src/main/java/ftp/DownloadTask.java | 246 |
1 files changed, 138 insertions, 108 deletions
diff --git a/dozentenmodul/src/main/java/ftp/DownloadTask.java b/dozentenmodul/src/main/java/ftp/DownloadTask.java index ef95b8da..95e74169 100644 --- a/dozentenmodul/src/main/java/ftp/DownloadTask.java +++ b/dozentenmodul/src/main/java/ftp/DownloadTask.java @@ -4,10 +4,9 @@ import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; +import java.io.RandomAccessFile; import java.nio.charset.StandardCharsets; import java.util.Map; @@ -20,6 +19,10 @@ import models.SessionData; import org.apache.commons.io.FileUtils; import org.apache.log4j.Logger; import org.apache.thrift.TException; +import org.openslx.filetransfer.DataReceivedCallback; +import org.openslx.filetransfer.Downloader; +import org.openslx.filetransfer.FileRange; +import org.openslx.filetransfer.WantRangeCallback; import org.openslx.thrifthelper.ThriftManager; import util.ResourceLoader; @@ -37,27 +40,78 @@ public class DownloadTask extends SwingWorker<Void, Void> { */ private final static Logger LOGGER = Logger.getLogger(DownloadTask.class); - private static final int BUFFER_SIZE = 8 * 1024 * 1024; private static final double UPDATE_INTERVAL_SECONDS = 0.6; private static final double UPDATE_INTERVAL_MS = UPDATE_INTERVAL_SECONDS * 1000; private static final double BYTES_PER_MIB = 1024 * 1024; + private static final long CHUNK_SIZE = 16 * 1024 * 1024; - private String host; - private int port; - private String username; - private String password; - private String downloadPath; - private String saveDir; - private int percentCompleted; + private final String host; + private final int port; + private final String downloadToken; + private final String saveDir; + private final long fileSize; + private boolean success = false; - public DownloadTask(String host, int port, String username, String password, - String downloadPath, String saveDir) { + public DownloadTask(String host, int port, String downloadToken, String saveDir, long fileSize) { this.host = host; this.port = port; - this.username = username; - this.password = password; - this.downloadPath = downloadPath; + this.downloadToken = downloadToken; this.saveDir = saveDir; + this.fileSize = fileSize; + } + + class Callbacks implements WantRangeCallback, DataReceivedCallback { + // initialize the counters needed for speed calculations + private long currentRequestedOffset = -1; + private long totalBytesRead = 0; + private long lastUpdate = 0; + private long lastBytes = 0; + private long currentBytes = 0; + private final RandomAccessFile file; + + public Callbacks(RandomAccessFile file) { + this.file = file; + } + + @Override + public FileRange get() { + if (currentRequestedOffset == -1) + currentRequestedOffset = 0; + else + currentRequestedOffset += CHUNK_SIZE; + if (currentRequestedOffset >= fileSize) + return null; + long end = currentRequestedOffset + CHUNK_SIZE; + if (end > fileSize) + end = fileSize; + return new FileRange(currentRequestedOffset, end); + } + + @Override + public boolean dataReceived(final long fileOffset, final int dataLength, final byte[] data) { + try { + file.seek(fileOffset); + file.write(data, 0, dataLength); + } catch (Exception e) { + LOGGER.error("Could not write to file at offset " + fileOffset, e); + return false; + } + currentBytes += dataLength; + totalBytesRead += dataLength; + final long now = System.currentTimeMillis(); + if (lastUpdate + UPDATE_INTERVAL_MS < now) { + final int percentCompleted = (int) ((totalBytesRead * 100) / fileSize); + setProgress(percentCompleted); + lastBytes = (lastBytes * 2 + currentBytes) / 3; + final double speed = lastBytes / UPDATE_INTERVAL_SECONDS; + firePropertyChange("speed", 0, speed / BYTES_PER_MIB); + firePropertyChange("bytesread", 0, totalBytesRead); + lastUpdate = now; + currentBytes = 0; + } + return true; + } + } /** @@ -65,61 +119,45 @@ public class DownloadTask extends SwingWorker<Void, Void> { */ @Override protected Void doInBackground() throws Exception { - FTPUtility util = new FTPUtility(host, port, username, password); - try { - util.connect(); + boolean ret = false; + // show filesize in the GUI + firePropertyChange("filesize", 0, fileSize); - // show filesize in the GUI - long fileSize = util.getFileSize(downloadPath); - firePropertyChange("filesize", 0, fileSize); - util.downloadFile(downloadPath); + Downloader download = null; + RandomAccessFile file = null; + try { + download = new Downloader(host, port, null, downloadToken); // TODO: SSL + try { + file = new RandomAccessFile(new File(saveDir), "rw"); + } catch (Exception e2) { + JOptionPane.showMessageDialog(null, "Could not open destination file:\n" + saveDir + "\n" + + e2.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); + e2.printStackTrace(); + setProgress(0); + return null; + } - // prepare the input/output streams - String fileName = new File(downloadPath).getName(); - File downloadFile = new File(saveDir + File.separator + fileName); - FileOutputStream outputStream = new FileOutputStream(downloadFile); - InputStream inputStream = util.getInputStream(); + Callbacks cb = new Callbacks(file); - // initialize the counters needed for speed calculations - percentCompleted = 0; - byte[] buffer = new byte[BUFFER_SIZE]; - int bytesRead = -1; - long totalBytesRead = 0; - long lastUpdate = 0; - long lastBytes = 0; - long currentBytes = 0; - while ((bytesRead = inputStream.read(buffer)) != -1 && !isCancelled()) { - outputStream.write(buffer, 0, bytesRead); - currentBytes += bytesRead; - totalBytesRead += bytesRead; - long now = System.currentTimeMillis(); - if (lastUpdate + UPDATE_INTERVAL_MS < now) { - percentCompleted = (int) ((totalBytesRead * 100) / fileSize); - setProgress(percentCompleted); - lastBytes = (lastBytes * 2 + currentBytes) / 3; - final double speed = lastBytes / UPDATE_INTERVAL_SECONDS; - firePropertyChange("speed", 0, speed / BYTES_PER_MIB); - firePropertyChange("bytesread", 0, totalBytesRead); - lastUpdate = now; - currentBytes = 0; + ret = download.download(cb, cb); + } finally { + if (file != null) { + try { + file.close(); + } catch (Exception e) { } } - // finalize the download by updating the progress bar one last time - // (in case we didn't get to do it because of the time interval) - percentCompleted = (int) ((totalBytesRead * 100) / fileSize); - setProgress(percentCompleted); - firePropertyChange("bytesread", 0, totalBytesRead); - outputStream.close(); - util.finish(); - } catch (FTPException ex) { - JOptionPane.showMessageDialog(null, - "Error downloading file: " + ex.getMessage(), "Error", - JOptionPane.ERROR_MESSAGE); - ex.printStackTrace(); - setProgress(0); - cancel(true); - } finally { - util.disconnect(); + if (download != null) + download.close(null); + } + + // if the download succeeded, set the progress to 100% manually again here to make + // sure the GUI knows about it. + if (ret) { + setProgress(100); + firePropertyChange("bytesread", 0, fileSize); + firePropertyChange("success", false, true); + success = true; } return null; @@ -130,24 +168,26 @@ public class DownloadTask extends SwingWorker<Void, Void> { */ @Override protected void done() { - if (!isCancelled() && percentCompleted == 100) { + if (isCancelled()) + return; + if (success) { LOGGER.info("Datei erfolgreich heruntergeladen."); String vmxResult = ""; - vmxResult = generateVmx() ? "Passende VMX generiert." - : "Keine passende VMX generiert!"; - JOptionPane.showMessageDialog(null, "Datei erfolgreich heruntergeladen. " - + vmxResult, "Message", JOptionPane.INFORMATION_MESSAGE); - } else if (!isCancelled() && percentCompleted != 100) { + vmxResult = generateVmx() ? "Passende VMX generiert." : "Keine passende VMX generiert!"; + JOptionPane.showMessageDialog(null, "Datei erfolgreich heruntergeladen. " + vmxResult, "Message", + JOptionPane.INFORMATION_MESSAGE); + } else { LOGGER.error("Datei wurde unvollständig heruntergeladen."); JOptionPane.showMessageDialog(null, - "Datei wurde unvollständig heruntergeladen. Bitte wiederholen.", - "Message", JOptionPane.INFORMATION_MESSAGE); + "Datei wurde unvollständig heruntergeladen. Bitte wiederholen.", "Message", + JOptionPane.INFORMATION_MESSAGE); } } /** * Helper to generate the vmx for the downloaded image - * + * TODO: Not really related to DownloadTask... + * * @return true|false indicating the success of the file creation */ private boolean generateVmx() { @@ -159,8 +199,7 @@ public class DownloadTask extends SwingWorker<Void, Void> { LOGGER.debug("Image's ID: " + Image.ImageId); Map<String, String> imageData = null; try { - imageData = ThriftManager.getSatClient().getImageData( - Image.ImageId, Image.Version, + imageData = ThriftManager.getSatClient().getImageData(Image.ImageId, Image.Version, SessionData.authToken); } catch (TException e) { LOGGER.error("Thrift exception during transfer, see trace: ", e); @@ -177,37 +216,29 @@ public class DownloadTask extends SwingWorker<Void, Void> { int hardwareVersion = extractHardwareVersion(saveDir + File.separator + imageData.get("path").replaceFirst("^prod/", "")); if (hardwareVersion == 0) { - LOGGER - .error("'extractHardwareVersion' returned 0 indicating some problem. See logs."); + LOGGER.error("'extractHardwareVersion' returned 0 indicating some problem. See logs."); LOGGER.error("Falling back to default hardware version of '10'."); hardwareVersion = 10; } // TODO: sanity checks on the content of imageData would be good here... // use the information we received about the image - vmxTemplate = vmxTemplate.replace("%VM_DISPLAY_NAME%", - imageData.get("name")); + vmxTemplate = vmxTemplate.replace("%VM_DISPLAY_NAME%", imageData.get("name")); vmxTemplate = vmxTemplate.replace("%VM_GUEST_OS%", imageData.get("os")); vmxTemplate = vmxTemplate.replace("%VM_CPU_COUNT%", imageData.get("cpu")); vmxTemplate = vmxTemplate.replace("%VM_RAM_SIZE%", String.valueOf(Integer.valueOf(imageData.get("ram")) * 1024)); - vmxTemplate = vmxTemplate.replace("%VM_DISK_PATH%", imageData.get("path") - .replaceFirst("^prod/", "")); - vmxTemplate = vmxTemplate.replace("%VM_HW_VERSION%", - String.valueOf(hardwareVersion)); + vmxTemplate = vmxTemplate.replace("%VM_DISK_PATH%", imageData.get("path").replaceFirst("^prod/", "")); + vmxTemplate = vmxTemplate.replace("%VM_HW_VERSION%", String.valueOf(hardwareVersion)); // build filename for the vmx, basicly the same as the path of the vmdk // just without the leading "prod/" and "vmx" instead of "vmdk" at the end. - String targetFilename = saveDir - + File.separator - + imageData.get("path").replaceFirst("^prod/", "") - .replaceFirst("\\.vmdk$", "") + ".vmx"; + String targetFilename = saveDir + File.separator + + imageData.get("path").replaceFirst("^prod/", "").replaceFirst("\\.vmdk$", "") + ".vmx"; try { // try to write it to file - FileUtils.writeStringToFile(new File(targetFilename), vmxTemplate, - StandardCharsets.UTF_8); + FileUtils.writeStringToFile(new File(targetFilename), vmxTemplate, StandardCharsets.UTF_8); } catch (IOException e) { - LOGGER.error("Could not write vmx-template to '" + targetFilename - + "'. See trace: ", e); + LOGGER.error("Could not write vmx-template to '" + targetFilename + "'. See trace: ", e); return false; } return true; @@ -216,44 +247,41 @@ public class DownloadTask extends SwingWorker<Void, Void> { /** * Helper to extract the hardware version of the VMDK file by inspecting its * content. - * - * @return value of hardware version as integer. A return value of 0 indicates + * + * @return value of hardware version as integer. A return value of 0 + * indicates * an error. */ private int extractHardwareVersion(String path) { BufferedReader br = null; try { try { - br = new BufferedReader( - new InputStreamReader(new FileInputStream(path))); + br = new BufferedReader(new InputStreamReader(new FileInputStream(path))); String line; // first 4 characters of a VMDK file start with 'KDMV' // first lets check if this is the case line = br.readLine(); if (!line.subSequence(0, 4).equals("KDMV")) { - LOGGER - .error("Did not see 'KDMV' as first chars of the VMDK! Returning 0."); + LOGGER.error("Did not see 'KDMV' as first chars of the VMDK! Returning 0."); LOGGER.debug("First line was: " + line); LOGGER.debug("First 4 characters of it: " + line.subSequence(0, 4)); return 0; } - // only read a maximum of 20 lines, just in case... + // only read a maximum of 25 lines, just in case... int round = 0; - while ((line = br.readLine()) != null && round < 20) { - if (line.matches("^ddb\\.virtualHWVersion.*")) { + while ((line = br.readLine()) != null && round < 25) { + if (line.startsWith("ddb.virtualHWVersion")) { String[] tmp = line.split("="); // we should get 2 strings only after the split, lets be sure if (tmp.length != 2) { - LOGGER - .debug("Splitting returned more than 2 parts, this should not happen!"); + LOGGER.debug("Splitting returned more than 2 parts, this should not happen!"); return 0; } int candidate = Integer.parseInt(tmp[1].trim().replace("\"", "")); LOGGER.debug("Considering hardware version: " + candidate); if (candidate > 0) { - LOGGER - .debug("Valid value of the candidate. Using hardware version of: " - + candidate); + LOGGER.debug("Valid value of the candidate. Using hardware version of: " + + candidate); return candidate; } else { LOGGER.error("Candidate is not > 0! Returning 0."); @@ -262,8 +290,10 @@ public class DownloadTask extends SwingWorker<Void, Void> { } round++; } - LOGGER.error("Failed to find hardware version. Tried " + round - + " rounds."); + LOGGER.error("Failed to find hardware version. Tried " + round + " rounds."); + } catch (NumberFormatException e) { + // Not a number? + return 0; } finally { br.close(); } |
