diff options
author | Simon Rettberg | 2015-10-01 20:00:27 +0200 |
---|---|---|
committer | Simon Rettberg | 2015-10-01 20:00:27 +0200 |
commit | 1fd45f1ec985012179b26c8136eadf0c5ae3c2c8 (patch) | |
tree | 05f2c0065d4e837f896cd3b0668125e87a211806 /dozentenmodul/src/main/java/org/openslx/dozmod/thrift | |
parent | [client] Fix escape not working in message boxes (diff) | |
download | tutor-module-1fd45f1ec985012179b26c8136eadf0c5ae3c2c8.tar.gz tutor-module-1fd45f1ec985012179b26c8136eadf0c5ae3c2c8.tar.xz tutor-module-1fd45f1ec985012179b26c8136eadf0c5ae3c2c8.zip |
[client] Start upload only when finishing wizard, add final summary page to wizard
Diffstat (limited to 'dozentenmodul/src/main/java/org/openslx/dozmod/thrift')
4 files changed, 300 insertions, 167 deletions
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/GuiErrorCallback.java b/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/GuiErrorCallback.java index 11c3c3da..26e11504 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/GuiErrorCallback.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/GuiErrorCallback.java @@ -25,23 +25,26 @@ public class GuiErrorCallback implements ErrorCallback { @Override public boolean thriftError(int failCount, final String method, final Throwable t) { // if it's not a transport exception, do not retry - if (!(t instanceof TTransportException)) + if (t != null && !(t instanceof TTransportException)) return false; - final TTransportException tex = (TTransportException) t; // if it's the first fail, retry immediately if (failCount == 1) return true; // Some methods are non-critical, so don't show a pop-up if (ThriftError.failSilently(method)) - return false; + return failCount == 2; // As it's silent, give it a second try... // Otherwise, ask user if we should retry + final TTransportException tex = (TTransportException) t; return Gui.syncExec(new GuiCallable<Boolean>() { @Override public Boolean run() { + String errMsg = null; + if (tex != null) { + errMsg = " (Fehler " + tex.getType() + ")"; + } return Gui.showMessageBox(parent, "Die Kommunikation mit " + serverString + " ist" - + " gestört. Der Aufruf der Funktion " + method + " ist fehlgeschlagen (Fehler " - + tex.getType() + ").\n\n" + "Möchten Sie den Aufruf wiederholen?", - MessageType.ERROR_RETRY, LOGGER, t); + + " gestört. Der Aufruf der Funktion " + method + " ist fehlgeschlagen" + errMsg + + ".\n\n" + "Möchten Sie den Aufruf wiederholen?", MessageType.ERROR_RETRY, LOGGER, t); } }); } diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/ThriftActions.java b/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/ThriftActions.java index a1711990..d22bf39c 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/ThriftActions.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/ThriftActions.java @@ -5,8 +5,6 @@ import java.awt.Window; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; -import java.nio.ByteBuffer; -import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -28,6 +26,7 @@ import org.openslx.bwlp.thrift.iface.Satellite; import org.openslx.bwlp.thrift.iface.SatelliteServer.Client; import org.openslx.bwlp.thrift.iface.TAuthorizationException; import org.openslx.bwlp.thrift.iface.TInvocationException; +import org.openslx.bwlp.thrift.iface.TNotFoundException; import org.openslx.bwlp.thrift.iface.TransferInformation; import org.openslx.bwlp.thrift.iface.TransferState; import org.openslx.bwlp.thrift.iface.UserInfo; @@ -36,11 +35,9 @@ import org.openslx.dozmod.App; import org.openslx.dozmod.Config; import org.openslx.dozmod.Config.SavedSession; import org.openslx.dozmod.authentication.Authenticator.AuthenticationData; -import org.openslx.dozmod.filetransfer.AsyncHashGenerator; import org.openslx.dozmod.filetransfer.DownloadTask; import org.openslx.dozmod.filetransfer.TransferEvent; import org.openslx.dozmod.filetransfer.TransferEventListener; -import org.openslx.dozmod.filetransfer.UploadTask; import org.openslx.dozmod.gui.GraphicalCertHandler; import org.openslx.dozmod.gui.Gui; import org.openslx.dozmod.gui.MainWindow; @@ -58,7 +55,6 @@ import org.openslx.sat.thrift.version.Version; import org.openslx.thrifthelper.ThriftManager; import org.openslx.util.QuickTimer; import org.openslx.util.QuickTimer.Task; -import org.openslx.util.Util; import org.openslx.util.vm.DiskImage; import org.openslx.util.vm.DiskImage.UnknownImageFormatException; @@ -66,7 +62,6 @@ public class ThriftActions { private static final Logger LOGGER = Logger.getLogger(ThriftActions.class); private static final long SIZE_CHECK_EXTRA_DL = 50l * 1024l * 1024l; - private static final long SIZE_CHECK_EXTRA_UL = 150l * 1024l * 1024l; /* ******************************************************************************* * @@ -74,8 +69,7 @@ public class ThriftActions { * * Login methods * - * ************************************************************************** - * **** + * ******************************************************************************* */ /** * @param window the parentWindow @@ -108,7 +102,9 @@ public class ThriftActions { } else { if (data.satellites.isEmpty()) { Gui.asyncMessageBox("Login erfolgreich, aber es wurde kein Satellit-Server gefunden.\n" - + " Bitte geben Sie die Adresse Ihres Satelliten an.", MessageType.ERROR, LOGGER, null);} + + " Bitte geben Sie die Adresse Ihres Satelliten an.", MessageType.ERROR, LOGGER, + null); + } sat = SatelliteListWindow.open(window, data.satellites); } @@ -137,7 +133,7 @@ public class ThriftActions { Gui.asyncMessageBox( "Authentifizierung erfolgreich, die Verbindung zum Satelliten-Server ist jedoch nicht möglich.\n\n" + "Möglicherweise ist der Server nicht verfügbar, oder die Netzwerkverbindung gestört.", - MessageType.ERROR, null, null); + MessageType.ERROR, null, null); } return false; } @@ -167,7 +163,7 @@ public class ThriftActions { Gui.asyncMessageBox( "Authentifizierung erfolgreich, der Satellit verweigert jedoch die Verbindung.\n\n" + "Grund: " + e.number.toString() + " (" + e.message + ")", - MessageType.ERROR, null, null); + MessageType.ERROR, null, null); } return false; } catch (TInvocationException e) { @@ -213,8 +209,7 @@ public class ThriftActions { * * Creates a base image with the given name * - * ************************************************************************** - * **** + * ******************************************************************************* */ /** * GUI-BLOCKING Creates the image with the given name. Returns the uuid @@ -240,39 +235,34 @@ public class ThriftActions { * GUI-BLOCKING Pushes a new image base to the server with the given * imageBaseId and the meta information in meta * - * @param frame to show user feedback on * @param imageBaseId image's id we are writing meta information of * @param meta actual meta information as ImageBaseWrite + * @throws TException + * @throws TInvocationException + * @throws TNotFoundException + * @throws TAuthorizationException */ - public static boolean updateImageBase(final Frame frame, final String imageBaseId, - final ImageBaseWrite meta) { - try { - ThriftManager.getSatClient().updateImageBase(Session.getSatelliteToken(), imageBaseId, meta); - } catch (TException e) { - ThriftError.showMessage(frame, LOGGER, e, "Konnte Metadaten des Images nicht übertragen"); - return false; - } - return true; + public static void updateImageBase(final String imageBaseId, final ImageBaseWrite meta) + throws TAuthorizationException, TNotFoundException, TInvocationException, TException { + ThriftManager.getSatClient().updateImageBase(Session.getSatelliteToken(), imageBaseId, meta); } /** * GUI-BLOCKING Pushes the given permission map as custom permission for the * given imageBaseId * - * @param frame to show user feedback on * @param imageBaseId image's id we are writing permissions of * @param permissions actual permissions map to write + * @throws TException + * @throws TInvocationException + * @throws TNotFoundException + * @throws TAuthorizationException */ - public static boolean writeImagePermissions(final Frame frame, final String imageBaseId, - final Map<String, ImagePermissions> permissions) { - try { - ThriftManager.getSatClient().writeImagePermissions(Session.getSatelliteToken(), imageBaseId, - permissions); - } catch (TException e) { - ThriftError.showMessage(frame, LOGGER, e, "Konnte Berechtigungen nicht übertragen"); - return false; - } - return true; + public static void writeImagePermissions(final String imageBaseId, + final Map<String, ImagePermissions> permissions) throws TAuthorizationException, + TNotFoundException, TInvocationException, TException { + ThriftManager.getSatClient().writeImagePermissions(Session.getSatelliteToken(), imageBaseId, + permissions); } /* ******************************************************************************* @@ -283,124 +273,23 @@ public class ThriftActions { * steps: - requestVersionUpload(..) to request the upload at the server - * initUpload(..) to actually start the upload of the file * - * ************************************************************************** - * **** + * ****************************************************************************** */ - /** - * GUI-BLOCKING Request the upload of an image version. Returns the - * TransferInformation received by the server or null if the request failed. - * Will give user feedback about failures. - * - * @param frame caller of this method - * @param imageBaseId uuid of the image to upload a version of - * @param fileSize size in bytes(?) of the uploaded file - * @param blockHashes - * @param machineDescription - * @param callback - * @return TransferInformation received by the server, null if the request - * failed. - */ - public static TransferInformation requestVersionUpload(final Frame frame, final String imageBaseId, - final long fileSize, final List<ByteBuffer> blockHashes, final ByteBuffer machineDescription) { - try { - if (ThriftManager.getSatClient().getStatus().getAvailableStorageBytes() < fileSize - + SIZE_CHECK_EXTRA_UL) { - Gui.showMessageBox( - frame, - "Nicht genügend Speicherplatz Satelliten. Löschen Sie nicht verwendete Imageversionen oder kontaktieren sie den Administrator.", - MessageType.ERROR, LOGGER, null); - return null; - } - } catch (TException e1) { - ThriftError.showMessage(frame, LOGGER, e1, "Konnte Status des Satelliten nicht abfragen!"); - return null; - } - TransferInformation ti = null; - try { - ti = ThriftManager.getSatClient().requestImageVersionUpload(Session.getSatelliteToken(), - imageBaseId, fileSize, null, // TODO remove deprecated parameter - machineDescription); - LOGGER.info("Version upload granted, versionId: '" + ti.toString()); - } catch (TAuthorizationException e) { - ThriftError.showMessage(frame, LOGGER, e, "Upload einer neuen Version nicht erlaubt!"); - } catch (TException e) { - ThriftError.showMessage(frame, LOGGER, e, "Upload-Anfrage gescheitert!"); - } - return ti; - } /** - * GUI-BLOCKING Starts uploading the given diskFile using the - * transferInformation and hashGen - * - * @param frame caller of this method - * @param transferInformation transfer information to use for the upload - * @param hashGen hash generator for this file - * @param diskFile the file to upload - * @return UploadTask if the uploading initialized, or null if uploading - * failed - */ - public static InitUploadStatus initUpload(final Frame frame, - final TransferInformation transferInformation, final File diskFile) { - UploadTask uploadTask = null; - // do actually start the upload now - LOGGER.debug("Starting upload for: " + diskFile.toPath()); - try { - uploadTask = new UploadTask(Session.getSatelliteAddress(), transferInformation.getPlainPort(), - transferInformation.getToken(), diskFile); - } catch (FileNotFoundException e) { - Gui.asyncMessageBox( - "Kann VM nicht hochladen: Datei nicht gefunden\n\n" + diskFile.getAbsolutePath(), - MessageType.ERROR, LOGGER, e); - return null; - } - AsyncHashGenerator hashGen = null; - try { - hashGen = new AsyncHashGenerator(transferInformation.token, diskFile); - hashGen.start(); - Util.sleep(50);// A little ugly... Give the hash generator a head - // start - } catch (FileNotFoundException | NoSuchAlgorithmException e) { - Gui.showMessageBox(frame, "Kann keine Block-Hashes für den Upload berechnen, " - + "automatische Fehlerkorrektur deaktiviert.", MessageType.WARNING, LOGGER, e); - } - Util.sleep(50); // A little ugly... Give the hash generator a head start - Thread uploadThread = new Thread(uploadTask); - uploadThread.setDaemon(true); - uploadThread.start(); - do { // Even more ugly - block the GUI thread so we know whether the - // upload started, and only then switch to the next page - Util.sleep(5); - } while (uploadTask.getFailCount() == 0 && uploadTask.getTransferCount() == 0 - && !uploadTask.isCanceled()); - - if (uploadTask.getTransferCount() == 0) { - Gui.asyncMessageBox("Aufbau der Verbindung zum Hochladen fehlgeschlagen", MessageType.ERROR, - LOGGER, null); - hashGen.cancel(); - uploadTask.cancel(); - uploadTask = null; - } - return new InitUploadStatus(uploadTask, hashGen); - } - - /** - * GUI-BLOCKING Gives user feedback TODO + * GUI-BLOCKING * * @param frame * @param transferInformation * @param versionInfo + * @throws TException + * @throws TInvocationException + * @throws TNotFoundException + * @throws TAuthorizationException */ - public static boolean updateImageVersion(final Frame frame, final String versionId, - final ImageVersionWrite versionInfo) { - try { - ThriftManager.getSatClient().updateImageVersion(Session.getSatelliteToken(), versionId, - versionInfo); - } catch (TException e) { - Gui.showMessageBox(frame, "Konnte neue Version nicht erstellen!", MessageType.ERROR, LOGGER, e); - return false; - } - return true; + public static void updateImageVersion(final String versionId, final ImageVersionWrite versionInfo) + throws TAuthorizationException, TNotFoundException, TInvocationException, TException { + ThriftManager.getSatClient().updateImageVersion(Session.getSatelliteToken(), versionId, versionInfo); } /* ******************************************************************************* @@ -411,8 +300,7 @@ public class ThriftActions { * 'DownloadCallback' and the actual static method 'initDownload' to start * the download. * - * ************************************************************************** - * **** + * ******************************************************************************* */ /** * The callback interface to inform the GUI about the status of the @@ -548,7 +436,7 @@ public class ThriftActions { Gui.asyncMessageBox( "Zur heruntergeladenen VM konnte keine vmx-Datei angelegt werden." + "\nSie können versuchen, das Abbild manuell in den VMWare-Player zu importieren.", - MessageType.WARNING, LOGGER, e); + MessageType.WARNING, LOGGER, e); } } }); @@ -1140,18 +1028,4 @@ public class ThriftActions { return Gui.showMessageBox(frame, message, MessageType.QUESTION_YESNO, null, null); } - /** - * Wrapper class for UploadTask & AsyncHashGenerator - * - */ - public static class InitUploadStatus { - public final UploadTask task; - public final AsyncHashGenerator hasher; - - public InitUploadStatus(final UploadTask task, final AsyncHashGenerator hasher) { - this.task = task; - this.hasher = hasher; - } - } - } diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/UploadInitiator.java b/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/UploadInitiator.java new file mode 100644 index 00000000..b176a5cb --- /dev/null +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/UploadInitiator.java @@ -0,0 +1,241 @@ +package org.openslx.dozmod.thrift; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.NoSuchAlgorithmException; +import java.util.concurrent.TimeUnit; + +import org.apache.log4j.Logger; +import org.apache.thrift.TException; +import org.openslx.bwlp.thrift.iface.SatelliteStatus; +import org.openslx.bwlp.thrift.iface.TAuthorizationException; +import org.openslx.bwlp.thrift.iface.TTransferRejectedException; +import org.openslx.bwlp.thrift.iface.TransferInformation; +import org.openslx.dozmod.filetransfer.AsyncHashGenerator; +import org.openslx.dozmod.filetransfer.UploadTask; +import org.openslx.thrifthelper.ThriftManager; +import org.openslx.util.QuickTimer; + +public class UploadInitiator { + + private static final Logger LOGGER = Logger.getLogger(UploadInitiator.class); + + private static final long SIZE_CHECK_EXTRA_UL = 150l * 1024l * 1024l; + + public enum UploadInitState { + IDLE, + REQUESTING, + WAITING_FOR_SLOT, + UPLOAD_STARTING, + UPLOAD_STARTED, + ERROR + } + + private final File diskFile; + private final long fileSize; + private final String imageBaseId; + private final ByteBuffer machineDescription; + private final AsyncHashGenerator hashGen; + private TransferInformation transferInformation = null; + private UploadTask uploadTask; + private UploadInitState initState = UploadInitState.IDLE; + private String errorMessage = null; + + /** + * GUI-BLOCKING Request the upload of an image version. Returns the + * TransferInformation received by the server or null if the request failed. + * Will give user feedback about failures. + * + * @param imageBaseId uuid of the image to upload a version of + * @param diskFile the file to upload + * @param machineDescription + * @throws TException + * @throws IOException + */ + public UploadInitiator(final String imageBaseId, final File diskFile, final ByteBuffer machineDescription) + throws WrappedException, IOException { + if (!diskFile.canRead()) + throw new FileNotFoundException(diskFile.getName()); + this.fileSize = diskFile.length(); + SatelliteStatus status; + try { + status = ThriftManager.getSatClient().getStatus(); + } catch (TException e1) { + throw new WrappedException(e1, "Konnte Status des Satelliten nicht abfragen!"); + } + if (status.getAvailableStorageBytes() != -1 + && status.getAvailableStorageBytes() < fileSize + SIZE_CHECK_EXTRA_UL) { + throw new IOException("Nicht genügend Speicherplatz Satelliten.\n" + + "Löschen Sie nicht verwendete Imageversionen oder kontaktieren sie den Administrator."); + } + this.diskFile = diskFile; + AsyncHashGenerator hg; + try { + hg = new AsyncHashGenerator(diskFile); + } catch (NoSuchAlgorithmException e) { + LOGGER.warn("Cannot instantiate hash generator: No error correction available!"); + hg = null; + } + this.hashGen = hg; + this.machineDescription = machineDescription; + this.imageBaseId = imageBaseId; + } + + public synchronized void startHashing() throws IllegalThreadStateException { + if (hashGen == null) + return; + hashGen.start(); + } + + public interface GotUploadTokenCallback { + public void fire(); + } + GotUploadTokenCallback gotTokenCallback = null; + + public synchronized void startUpload(GotUploadTokenCallback gotTokenCallback) { + if (initState != UploadInitState.IDLE) + throw new IllegalStateException("Upload already started"); + this.gotTokenCallback = gotTokenCallback; + initState = UploadInitState.REQUESTING; + QuickTimer.scheduleAtFixedRate(startUploadInternal, 1, TimeUnit.SECONDS.toMillis(15)); + } + + private QuickTimer.Task startUploadInternal = new QuickTimer.Task() { + @Override + public void fire() { + LOGGER.debug("start upload internal"); + try { + transferInformation = ThriftManager.getSatClient().requestImageVersionUpload( + Session.getSatelliteToken(), imageBaseId, fileSize, null, // TODO remove deprecated parameter + machineDescription); + } catch (TAuthorizationException e) { + errorMessage = "Upload vom Server verweigert"; + cancelError(); + this.cancel(); + return; + } catch (TTransferRejectedException e) { + if (e.message != null && e.message.startsWith("Server busy")) { + initState = UploadInitState.WAITING_FOR_SLOT; + } else { + errorMessage = "Upload-Anfrage gescheitert!"; + cancelError(); + this.cancel(); + } + return; + } catch (TException e) { + errorMessage = "Upload-Anfrage gescheitert!"; + cancelError(); + this.cancel(); + return; + } + // Everything worked out so far + LOGGER.info("Version upload granted, versionId: " + transferInformation.toString()); + if (gotTokenCallback != null) { + gotTokenCallback.fire(); + } + if (hashGen != null) { + hashGen.setUploadToken(transferInformation.token); + } + initState = UploadInitState.UPLOAD_STARTING; + QuickTimer.scheduleAtFixedRate(launchUploadTask, 1, 100); + this.cancel(); + } + }; + + /** + * Prepare the given file for uploading + * + * @param transferInformation transfer information to use for the upload + * @param hashGen hash generator for this file + * @param diskFile the file to upload + * @return UploadTask if the uploading initialized, or null if uploading + * failed + */ + private QuickTimer.Task launchUploadTask = new QuickTimer.Task() { + @Override + public void fire() { + LOGGER.debug("launch upload task"); + if (initState != UploadInitState.UPLOAD_STARTING) { + this.cancel(); + return; + } + if (uploadTask == null) { + // do actually start the upload now + LOGGER.debug("Starting upload for: " + diskFile.getName()); + try { + uploadTask = new UploadTask(Session.getSatelliteAddress(), + transferInformation.getPlainPort(), transferInformation.getToken(), diskFile); + } catch (FileNotFoundException e) { + errorMessage = "Kann VM nicht hochladen: Datei nicht gefunden\n\n" + + diskFile.getAbsolutePath(); + cancelError(); + this.cancel(); + return; + } + Thread uploadThread = new Thread(uploadTask); + uploadThread.setDaemon(true); + uploadThread.start(); + } + + if (uploadTask.getFailCount() == 0 && uploadTask.getTransferCount() == 0 + && !uploadTask.isCanceled()) { + // Still initializing, wait... + return; + } + if (!uploadTask.isComplete() && uploadTask.getTransferCount() == 0) { + // Init failed + errorMessage = "Aufbau der Verbindung zum Hochladen fehlgeschlagen"; + cancelError(); + this.cancel(); + return; + } + // Init succeeded + initState = UploadInitState.UPLOAD_STARTED; + this.cancel(); + } + }; + + /** + * Set state to cancelled and clean up + */ + public synchronized void cancelError() { + if (initState == UploadInitState.ERROR) + return; + initState = UploadInitState.ERROR; + if (hashGen != null) { + hashGen.cancel(); + } + if (uploadTask != null) { + uploadTask.cancel(); + } + if (transferInformation != null) { + try { + ThriftManager.getSatClient().cancelUpload(transferInformation.token); + } catch (Exception e) { + } + } + } + + public UploadInitState getState() { + return initState; + } + + public String getErrorMessage() { + return errorMessage; + } + + public AsyncHashGenerator getHasher() { + return hashGen; + } + + public UploadTask getUploadTask() { + return uploadTask; + } + + public String getToken() { + return transferInformation == null ? null : transferInformation.token; + } + +} diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/WrappedException.java b/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/WrappedException.java new file mode 100644 index 00000000..1eb9783a --- /dev/null +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/WrappedException.java @@ -0,0 +1,15 @@ +package org.openslx.dozmod.thrift; + +import org.apache.thrift.TException; + + +public class WrappedException extends Exception { + private static final long serialVersionUID = 989657721513312675L; + public final TException exception; + public final String displayMessage; + + public WrappedException(TException e, String msg) { + this.exception = e; + this.displayMessage = msg; + } +} |