diff options
| author | Jonathan Bauer | 2015-09-01 16:45:04 +0200 |
|---|---|---|
| committer | Jonathan Bauer | 2015-09-01 16:45:04 +0200 |
| commit | 0505d3e4126c5b9b5915243fd159550b506ae592 (patch) | |
| tree | 532cb21c50bb20739c559d3bd7f0e9f8b753dcf1 | |
| parent | [client] Disclaimer minor typos & no close on clicking the "close" symbol (diff) | |
| parent | [client] Ignore certain thrift methods in our error handler (diff) | |
| download | tutor-module-0505d3e4126c5b9b5915243fd159550b506ae592.tar.gz tutor-module-0505d3e4126c5b9b5915243fd159550b506ae592.tar.xz tutor-module-0505d3e4126c5b9b5915243fd159550b506ae592.zip | |
Merge branch 'v1.1' of git.openslx.org:openslx-ng/tutor-module into v1.1
10 files changed, 305 insertions, 171 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 df0b160e..11c3c3da 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/GuiErrorCallback.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/GuiErrorCallback.java @@ -31,6 +31,9 @@ public class GuiErrorCallback implements ErrorCallback { // 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; // Otherwise, ask user if we should retry return Gui.syncExec(new GuiCallable<Boolean>() { @Override 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 f15e6e6c..dc1ce2df 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/ThriftActions.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/ThriftActions.java @@ -64,12 +64,10 @@ public class ThriftActions { * **** */ /** - * @param frame - * to show user feedback on - * @param data - * AuthenticationData as received from a successfull login, or + * @param frame to show user feedback on + * @param data AuthenticationData as received from a successful login, or * null if trying to resume a saved sessions - * @return true if initiliazing the session worked, false otherwise + * @return true if initializing the session worked, false otherwise */ public static boolean initSession(final Frame frame, AuthenticationData data) { Client client = null; @@ -114,8 +112,8 @@ public class ThriftActions { if (data != null) { Gui.showMessageBox(frame, "Das von Ihnen verwendete Dozentenmodul ist nicht mit dem Satelliten-Server kompatibel.\n" - + "Ihre Version: " + Version.VERSION + "\n" + "Satelliten-Version: " + remoteVersion, - MessageType.ERROR, LOGGER, null); + + "Ihre Version: " + Version.VERSION + "\n" + "Satelliten-Version: " + + remoteVersion, MessageType.ERROR, LOGGER, null); } return false; } @@ -125,8 +123,9 @@ public class ThriftActions { } catch (TAuthorizationException e) { if (data != null) { Gui.showMessageBox(frame, - "Authentifizierung erfolgreich, der Satellit verweigert jedoch die Verbindung.\n\n" + "Grund: " - + e.number.toString() + " (" + e.message + ")", MessageType.ERROR, null, null); + "Authentifizierung erfolgreich, der Satellit verweigert jedoch die Verbindung.\n\n" + + "Grund: " + e.number.toString() + " (" + e.message + ")", + MessageType.ERROR, null, null); } return false; } catch (TInvocationException e) { @@ -139,7 +138,8 @@ public class ThriftActions { return false; } catch (Exception e) { if (data != null) { - Gui.showMessageBox(frame, + Gui.showMessageBox( + frame, "Authentifizierung erfolgreich, aber der Satellit akzeptiert das Sitzungstoken nicht.", MessageType.ERROR, LOGGER, e); } @@ -148,7 +148,8 @@ public class ThriftActions { if (whoami != null) { Session.initialize(whoami, address, satToken, masterToken); - ThriftManager.setSatelliteAddress(GraphicalCertHandler.getSslContext(Session.getSatelliteAddress()), + ThriftManager.setSatelliteAddress( + GraphicalCertHandler.getSslContext(Session.getSatelliteAddress()), Session.getSatelliteAddress(), App.THRIFT_SSL_PORT, App.THRIFT_TIMEOUT_MS); return true; } @@ -168,8 +169,7 @@ public class ThriftActions { * GUI-BLOCKING Creates the image with the given name. Returns the uuid * returned by the server * - * @param frame - * calling this action + * @param frame calling this action * @return uuid as String, or null if the creation failed */ public static String createImage(final Frame frame, final String name) { @@ -179,7 +179,8 @@ public class ThriftActions { } catch (TException e) { ThriftError.showMessage(frame, LOGGER, e, "Erstellen des Images fehlgeschlagen"); } catch (Exception e) { - Gui.showMessageBox(frame, "Unbekannter Fehler beim Erstellen der VM", MessageType.ERROR, LOGGER, e); + Gui.showMessageBox(frame, "Unbekannter Fehler beim Erstellen der VM", MessageType.ERROR, LOGGER, + e); } return uuid; } @@ -188,14 +189,12 @@ 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 + * @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 */ - public static boolean updateImageBase(final Frame frame, final String imageBaseId, final ImageBaseWrite meta) { + public static boolean updateImageBase(final Frame frame, final String imageBaseId, + final ImageBaseWrite meta) { try { ThriftManager.getSatClient().updateImageBase(Session.getSatelliteToken(), imageBaseId, meta); } catch (TException e) { @@ -209,17 +208,15 @@ public class ThriftActions { * 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 + * @param frame to show user feedback on + * @param imageBaseId image's id we are writing permissions of + * @param permissions actual permissions map to write */ public static void writeImagePermissions(final Frame frame, final String imageBaseId, final Map<String, ImagePermissions> permissions) { try { - ThriftManager.getSatClient().writeImagePermissions(Session.getSatelliteToken(), imageBaseId, permissions); + ThriftManager.getSatClient().writeImagePermissions(Session.getSatelliteToken(), imageBaseId, + permissions); } catch (TException e) { ThriftError.showMessage(frame, LOGGER, e, "Konnte Berechtigungen nicht übertragen"); } @@ -241,12 +238,9 @@ public class ThriftActions { * 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 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 @@ -256,7 +250,8 @@ public class ThriftActions { 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) { + 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.", @@ -269,8 +264,8 @@ public class ThriftActions { } TransferInformation ti = null; try { - ti = ThriftManager.getSatClient().requestImageVersionUpload(Session.getSatelliteToken(), imageBaseId, - fileSize, null, // TODO remove deprecated parameter + 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) { @@ -285,19 +280,15 @@ public class ThriftActions { * 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 + * @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) { + 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()); @@ -305,7 +296,8 @@ public class ThriftActions { 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(), + Gui.asyncMessageBox( + "Kann VM nicht hochladen: Datei nicht gefunden\n\n" + diskFile.getAbsolutePath(), MessageType.ERROR, LOGGER, e); return null; } @@ -326,10 +318,12 @@ public class ThriftActions { 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()); + } 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); + Gui.asyncMessageBox("Aufbau der Verbindung zum Hochladen fehlgeschlagen", MessageType.ERROR, + LOGGER, null); hashGen.cancel(); uploadTask.cancel(); uploadTask = null; @@ -347,7 +341,8 @@ public class ThriftActions { public static boolean updateImageVersion(final Frame frame, final String versionId, final ImageVersionWrite versionInfo) { try { - ThriftManager.getSatClient().updateImageVersion(Session.getSatelliteToken(), versionId, versionInfo); + ThriftManager.getSatClient().updateImageVersion(Session.getSatelliteToken(), versionId, + versionInfo); } catch (TException e) { Gui.showMessageBox(frame, "Konnte neue Version nicht erstellen!", MessageType.ERROR, LOGGER, e); return false; @@ -378,19 +373,13 @@ public class ThriftActions { * NON-BLOCKING Initialises the download of the given imageVersionId saving * it to the given imageName * - * @param frame - * caller of this method - * @param imageVersionId - * image version id to download - * @param imageName - * destination file name - * @param virtualizerId - * id of the virtualizer - * @param imageSize - * size in bytes of the image to download - * @param callback - * callback function to return status of this operation to the - * GUI + * @param frame caller of this method + * @param imageVersionId image version id to download + * @param imageName destination file name + * @param virtualizerId id of the virtualizer + * @param imageSize size in bytes of the image to download + * @param callback callback function to return status of this operation to + * the GUI */ public static void initDownload(final Frame frame, final String imageVersionId, final String imageName, final String virtualizerId, final long imageSize, final DownloadCallback callback) { @@ -411,7 +400,8 @@ public class ThriftActions { if (diskFile.exists()) { boolean ret = Gui.showMessageBox(frame, "Datei '" + diskFile.getAbsolutePath() - + "' existiert bereits, wollen Sie sie überschreiben?", MessageType.QUESTION_YESNO, LOGGER, null); + + "' existiert bereits, wollen Sie sie überschreiben?", MessageType.QUESTION_YESNO, + LOGGER, null); if (!ret) { // user aborted if (callback != null) @@ -420,7 +410,8 @@ public class ThriftActions { } // delete it if (!diskFile.delete() && diskFile.exists()) { - Gui.showMessageBox(frame, "Datei konnte nicht überschrieben werden!", MessageType.ERROR, LOGGER, null); + Gui.showMessageBox(frame, "Datei konnte nicht überschrieben werden!", MessageType.ERROR, + LOGGER, null); if (callback != null) callback.downloadInitialized(false); return; @@ -430,8 +421,9 @@ public class ThriftActions { // Check the free space on disk if (destDir.getUsableSpace() < imageSize + SIZE_CHECK_EXTRA_DL) { Gui.showMessageBox(frame, "Nicht genügend Speicherplatz im ausgewählten Verzeichnis verfügbar.\n" - + "Brauche: " + FormatHelper.bytes(imageSize + SIZE_CHECK_EXTRA_DL, false) + "\n" + "Habe: " - + FormatHelper.bytes(destDir.getUsableSpace(), false), MessageType.ERROR, LOGGER, null); + + "Brauche: " + FormatHelper.bytes(imageSize + SIZE_CHECK_EXTRA_DL, false) + "\n" + + "Habe: " + FormatHelper.bytes(destDir.getUsableSpace(), false), MessageType.ERROR, + LOGGER, null); if (callback != null) callback.downloadInitialized(false); return; @@ -454,8 +446,8 @@ public class ThriftActions { public void fire() { TransferInformation transInf; try { - transInf = ThriftManager.getSatClient() - .requestDownload(Session.getSatelliteToken(), imageVersionId); + transInf = ThriftManager.getSatClient().requestDownload(Session.getSatelliteToken(), + imageVersionId); } catch (TException e) { ThriftError.showMessage(frame, LOGGER, e, "Die Download-Anfrage ist gescheitert"); if (callback != null) @@ -465,8 +457,8 @@ public class ThriftActions { final DownloadTask dlTask; try { - dlTask = new DownloadTask(Session.getSatelliteAddress(), transInf.getPlainPort(), transInf - .getToken(), tmpFile, imageSize, null); + dlTask = new DownloadTask(Session.getSatelliteAddress(), transInf.getPlainPort(), + transInf.getToken(), tmpFile, imageSize, null); } catch (FileNotFoundException e) { Gui.asyncMessageBox( "Konnte Download nicht vorbereiten: Der gewählte Zielort ist nicht beschreibbar", @@ -554,7 +546,8 @@ public class ThriftActions { * @param imageBaseId * @param callback */ - public static void getImageDetails(final Frame frame, final String imageBaseId, final ImageMetaCallback callback) { + public static void getImageDetails(final Frame frame, final String imageBaseId, + final ImageMetaCallback callback) { QuickTimer.scheduleOnce(new Task() { ImageDetailsRead details = null; @@ -573,7 +566,8 @@ public class ThriftActions { }); } - public static void getImageFullDetails(final Frame frame, final String imageBaseId, final ImageMetaCallback callback) { + public static void getImageFullDetails(final Frame frame, final String imageBaseId, + final ImageMetaCallback callback) { QuickTimer.scheduleOnce(new Task() { ImageDetailsRead details = null; Map<String, ImagePermissions> permissions = null; @@ -596,7 +590,8 @@ public class ThriftActions { } // async - public static void getImagePermissions(final Frame frame, final String imageBaseId, final ImageMetaCallback callback) { + public static void getImagePermissions(final Frame frame, final String imageBaseId, + final ImageMetaCallback callback) { QuickTimer.scheduleOnce(new Task() { Map<String, ImagePermissions> permissionMap = null; @@ -616,10 +611,12 @@ public class ThriftActions { } // sync - public static Map<String, ImagePermissions> getImagePermissions(final Frame frame, final String imageBaseId) { + public static Map<String, ImagePermissions> getImagePermissions(final Frame frame, + final String imageBaseId) { Map<String, ImagePermissions> permissionMap = null; try { - permissionMap = ThriftManager.getSatClient().getImagePermissions(Session.getSatelliteToken(), imageBaseId); + permissionMap = ThriftManager.getSatClient().getImagePermissions(Session.getSatelliteToken(), + imageBaseId); } catch (TException e) { ThriftError.showMessage(frame, LOGGER, e, "Fehler beim Lesen der Metadaten"); } @@ -629,17 +626,15 @@ public class ThriftActions { /** * GUI-BLOCKING Sets the owner of the given lectureId to newOwner * - * @param frame - * to display user feedback on - * @param lectureId - * lecture's id to set the new owner of - * @param newOwner - * as UserInfo + * @param frame to display user feedback on + * @param lectureId lecture's id to set the new owner of + * @param newOwner as UserInfo * @return true if it worked, false otherwise */ public static boolean setImageOwner(final Frame frame, final String lectureId, final UserInfo newOwner) { try { - ThriftManager.getSatClient().setImageOwner(Session.getSatelliteToken(), lectureId, newOwner.getUserId()); + ThriftManager.getSatClient().setImageOwner(Session.getSatelliteToken(), lectureId, + newOwner.getUserId()); } catch (TException e) { ThriftError.showMessage(frame, LOGGER, e, "Fehler beim Übertragen der Besitzrechte"); return false; @@ -664,13 +659,13 @@ public class ThriftActions { /** * Called once the status of a delete operation is determined * - * @param success - * true if deleted successfully, false otherwise + * @param success true if deleted successfully, false otherwise */ void isDeleted(boolean success); } - public static void deleteImageBase(final Frame frame, final String imageBaseId, final DeleteCallback callback) { + public static void deleteImageBase(final Frame frame, final String imageBaseId, + final DeleteCallback callback) { if (imageBaseId == null || imageBaseId.isEmpty()) return; // first look if we have versions @@ -680,8 +675,8 @@ public class ThriftActions { List<ImageVersionDetails> versionToBeDeleted = null; try { details = ThriftManager.getSatClient().getImageDetails(Session.getSatelliteToken(), imageBaseId); - List<LectureSummary> lectureList = ThriftManager.getSatClient().getLectureList(Session.getSatelliteToken(), - 100); + List<LectureSummary> lectureList = ThriftManager.getSatClient().getLectureList( + Session.getSatelliteToken(), 100); for (LectureSummary lecture : lectureList) { if (lecture.getImageBaseId().equals(imageBaseId)) { if (lecturesToBeDeleted == null) @@ -742,17 +737,14 @@ public class ThriftActions { * and imageVersionId. The success of the operation will be forwarded to the * GUI through the DeleteCallback. * - * @param frame - * next parent frame of the caller of this method - * @param imageBaseId - * uuid of the image that belongs to the version - * @param imageVersionId - * id of the image version to be deleted - * @param callback - * called to inform the GUI about the deletion status (see + * @param frame next parent frame of the caller of this method + * @param imageBaseId uuid of the image that belongs to the version + * @param imageVersionId id of the image version to be deleted + * @param callback called to inform the GUI about the deletion status (see * DeleteCallback interface) */ - public static void deleteImageVersion(final Frame frame, final String imageVersionId, final DeleteCallback callback) { + public static void deleteImageVersion(final Frame frame, final String imageVersionId, + final DeleteCallback callback) { // TODO async? if (imageVersionId == null || imageVersionId.isEmpty()) return; @@ -821,10 +813,8 @@ public class ThriftActions { /** * Creates a lecture with the given meta data * - * @param frame - * to show user feedback on - * @param meta - * actual meta data as LectureWrite + * @param frame to show user feedback on + * @param meta actual meta data as LectureWrite * @return the created lecture's id if it worked, null otherwise */ public static String createLecture(final Frame frame, final LectureWrite meta) { @@ -844,17 +834,15 @@ public class ThriftActions { * GUI-BLOCKING Writes custom lecture permissions (permissions param) for * the given lectureId. * - * @param frame - * to show user feedback on - * @param lectureId - * lecture's id to write custom permissions for - * @param permissions - * actual permission map to push + * @param frame to show user feedback on + * @param lectureId lecture's id to write custom permissions for + * @param permissions actual permission map to push */ public static boolean writeLecturePermissions(final Frame frame, final String lectureId, final Map<String, LecturePermissions> permissions) { try { - ThriftManager.getSatClient().writeLecturePermissions(Session.getSatelliteToken(), lectureId, permissions); + ThriftManager.getSatClient().writeLecturePermissions(Session.getSatelliteToken(), lectureId, + permissions); } catch (TException e) { ThriftError.showMessage(frame, LOGGER, e, "Failed to write lecture permissions"); return false; @@ -934,15 +922,13 @@ public class ThriftActions { * GUI-BLOCKING Updates the lecture with given lectureId to the given * lecture * - * @param frame - * to show user feedback on - * @param lectureId - * lecture's is to update - * @param lecture - * LectureWrite data to update the lecture with + * @param frame to show user feedback on + * @param lectureId lecture's is to update + * @param lecture LectureWrite data to update the lecture with * @return */ - public static boolean updateLecture(final Frame frame, final String lectureId, final LectureWrite lectureWrite) { + public static boolean updateLecture(final Frame frame, final String lectureId, + final LectureWrite lectureWrite) { try { ThriftManager.getSatClient().updateLecture(Session.getSatelliteToken(), lectureId, lectureWrite); } catch (TException e) { @@ -959,11 +945,13 @@ public class ThriftActions { * @param lectureId * @param callback */ - public static Map<String, LecturePermissions> getLecturePermissions(final Frame frame, final String lectureId) { + public static Map<String, LecturePermissions> getLecturePermissions(final Frame frame, + final String lectureId) { Map<String, LecturePermissions> permissions = null; try { - permissions = ThriftManager.getSatClient().getLecturePermissions(Session.getSatelliteToken(), lectureId); + permissions = ThriftManager.getSatClient().getLecturePermissions(Session.getSatelliteToken(), + lectureId); } catch (TException e) { ThriftError.showMessage(frame, LOGGER, e, "Konnte Veranstaltungdaten nicht abrufen"); } @@ -974,17 +962,15 @@ public class ThriftActions { /** * GUI-BLOCKING Sets the owner of the given lectureId to newOwner * - * @param frame - * to display user feedback on - * @param lectureId - * lecture's id to set the new owner of - * @param newOwner - * as UserInfo + * @param frame to display user feedback on + * @param lectureId lecture's id to set the new owner of + * @param newOwner as UserInfo * @return true if it worked, false otherwise */ public static boolean setLectureOwner(final Frame frame, final String lectureId, final UserInfo newOwner) { try { - ThriftManager.getSatClient().setLectureOwner(Session.getSatelliteToken(), lectureId, newOwner.getUserId()); + ThriftManager.getSatClient().setLectureOwner(Session.getSatelliteToken(), lectureId, + newOwner.getUserId()); } catch (TException e) { ThriftError.showMessage(frame, LOGGER, e, "Fehler beim Übertragen der Besitzrechte"); return false; @@ -1015,7 +1001,8 @@ public class ThriftActions { * @param lectureId * @param callback */ - public static void deleteLecture(final Frame frame, final String lectureId, final DeleteLectureCallback callback) { + public static void deleteLecture(final Frame frame, final String lectureId, + final DeleteLectureCallback callback) { if (lectureId == null) return; if (!userConfirmed(frame, "Wollen Sie diese Veranstaltung wirklick löschen?")) @@ -1053,10 +1040,8 @@ public class ThriftActions { /** * Helper to ask the user for confirmation. Returns his choice. * - * @param frame - * frame to show this message box on - * @param message - * question message to display to the user + * @param frame frame to show this message box on + * @param message question message to display to the user * @return true if the user confirmed (clicked yes), false otherwise */ private static boolean userConfirmed(final Frame frame, final String message) { diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/ThriftError.java b/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/ThriftError.java index 6982f8e5..33fd98b6 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/ThriftError.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/ThriftError.java @@ -102,4 +102,15 @@ public class ThriftError { } } + private static final String[] ignoredMethods = { "ping", "getStatus", "updateBlockHashes", + "cancelUpload", "cancelDownload" }; + + public static boolean failSilently(String methodName) { + for (int i = 0; i < ignoredMethods.length; ++i) { + if (ignoredMethods[i].equals(methodName)) + return true; + } + return false; + } + } diff --git a/dozentenmodulserver/setup/sat-01-schema.sql b/dozentenmodulserver/setup/sat-01-schema.sql index 051ab485..f030298a 100644 --- a/dozentenmodulserver/setup/sat-01-schema.sql +++ b/dozentenmodulserver/setup/sat-01-schema.sql @@ -74,7 +74,7 @@ CREATE TABLE IF NOT EXISTS `imageversion` ( `isvalid` tinyint(1) NOT NULL, `isprocessed` tinyint(1) NOT NULL, `mastersha1` binary(20) DEFAULT NULL, - `virtualizerconfig` text BINARY NULL DEFAULT NULL COMMENT 'Specific configuration of the virtualizer for this image. For vmware, this is basically a dump of the *.vmx.', + `virtualizerconfig` blob NULL DEFAULT NULL COMMENT 'Specific configuration of the virtualizer for this image. For vmware, this is basically a dump of the *.vmx.', PRIMARY KEY (`imageversionid`), KEY `version_access` (`imagebaseid`,`isvalid`,`createtime`), KEY `fk_imageversion_2_idx` (`uploaderid`), diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbImage.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbImage.java index c8e5fd2a..8a10fb85 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbImage.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbImage.java @@ -1,6 +1,7 @@ package org.openslx.bwlp.sat.database.mappers; import java.io.File; +import java.nio.ByteBuffer; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; @@ -13,6 +14,7 @@ import org.openslx.bwlp.sat.database.Database; import org.openslx.bwlp.sat.database.MysqlConnection; import org.openslx.bwlp.sat.database.MysqlStatement; import org.openslx.bwlp.sat.database.Paginator; +import org.openslx.bwlp.sat.database.models.ImageVersionMeta; import org.openslx.bwlp.sat.database.models.LocalImageVersion; import org.openslx.bwlp.sat.mail.MailGenerator; import org.openslx.bwlp.sat.permissions.User; @@ -29,6 +31,7 @@ import org.openslx.bwlp.thrift.iface.ShareMode; import org.openslx.bwlp.thrift.iface.TNotFoundException; import org.openslx.bwlp.thrift.iface.UserInfo; import org.openslx.filetransfer.util.ChunkList; +import org.openslx.filetransfer.util.FileChunk; import org.openslx.util.QuickTimer; import org.openslx.util.QuickTimer.Task; @@ -103,6 +106,7 @@ public class DbImage { rs.getLong("createtime"), rs.getLong("updatetime"), rs.getString("ownerid"), rs.getString("updaterid"), toShareMode(rs.getString("sharemode")), rs.getByte("istemplate") != 0, defaultPermissions); + image.setUserPermissions(DbImagePermissions.fromResultSetUser(rs)); User.setCombinedUserPermissions(image, user); return image; } catch (SQLException e) { @@ -536,16 +540,11 @@ public class DbImage { verStmt.setBinary("mastersha1", null); // TODO verStmt.setBinary("virtualizerconfig", machineDescription); verStmt.executeUpdate(); - // TODO: Write chunk hashes to DB - // Make this version the latest version - MysqlStatement baseStmt = connection.prepareStatement("UPDATE imagebase SET" - + " latestversionid = :imageversionid WHERE imagebaseid = :imagebaseid LIMIT 1"); - baseStmt.setString("imageversionid", imageVersionId); - baseStmt.setString("imagebaseid", imageBaseId); - baseStmt.executeUpdate(); + writeChunks(connection, imageVersionId, chunks); LocalImageVersion liv = new LocalImageVersion(imageVersionId, imageBaseId, filePath, fileSize, owner.userId, nowSecs, expireTime, true); DbLecture.autoUpdateUsedImage(connection, imageBaseId, liv); + // Make this version the latest version setLatestVersion(connection, imageBaseId, liv); connection.commit(); } catch (SQLException e) { @@ -554,6 +553,26 @@ public class DbImage { } } + private static void writeChunks(MysqlConnection connection, String imageVersionId, ChunkList chunks) + throws SQLException { + if (chunks == null || chunks.isEmpty()) + return; + for (FileChunk chunk : chunks.getAll()) { + if (chunk.getSha1Sum() == null) + return; + } + MysqlStatement stmt = connection.prepareStatement("INSERT IGNORE INTO imageblock" + + " (imageversionid, startbyte, blocksize, blocksha1, ismissing) VALUES" + + " (:imageversionid, :startbyte, :blocksize, :blocksha1, 0)"); + stmt.setString("imageversionid", imageVersionId); + for (FileChunk chunk : chunks.getAll()) { + stmt.setLong("startbyte", chunk.range.startOffset); + stmt.setInt("blocksize", chunk.range.getLength()); + stmt.setBinary("blocksha1", chunk.getSha1Sum()); + stmt.executeUpdate(); + } + } + protected static void markValid(MysqlConnection connection, boolean valid, LocalImageVersion... imageVersion) throws SQLException { if (imageVersion == null || imageVersion.length == 0) @@ -781,4 +800,35 @@ public class DbImage { } } + public static ImageVersionMeta getVersionDetails(String imageVersionId) throws SQLException, + TNotFoundException { + try (MysqlConnection connection = Database.getConnection()) { + MysqlStatement stmt = connection.prepareStatement("SELECT" + + " imageversionid, imagebaseid, virtualizerconfig FROM imageversion" + + " WHERE imageversionid = :imageversionid"); + stmt.setString("imageversionid", imageVersionId); + ResultSet rs = stmt.executeQuery(); + if (!rs.next()) + throw new TNotFoundException(); + return new ImageVersionMeta(imageVersionId, rs.getString("imagebaseid"), + rs.getBytes("virtualizerconfig"), getBlockHashes(connection, imageVersionId)); + } catch (SQLException e) { + LOGGER.error("Query failed in DbImage.getVersionDetails()", e); + throw e; + } + } + + private static List<ByteBuffer> getBlockHashes(MysqlConnection connection, String imageVersionId) + throws SQLException { + MysqlStatement stmt = connection.prepareStatement("SELECT blocksha1 FROM imageblock" + + " WHERE imageversionid = :imageversionid ORDER BY startbyte ASC"); + stmt.setString("imageversionid", imageVersionId); + ResultSet rs = stmt.executeQuery(); + List<ByteBuffer> list = new ArrayList<>(); + while (rs.next()) { + list.add(ByteBuffer.wrap(rs.getBytes("blocksha1"))); + } + return list; + } + } diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/fileserv/IncomingDataTransfer.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/fileserv/IncomingDataTransfer.java index e4e3349e..d008f5db 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/fileserv/IncomingDataTransfer.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/fileserv/IncomingDataTransfer.java @@ -4,7 +4,6 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; -import java.nio.charset.StandardCharsets; import java.security.NoSuchAlgorithmException; import java.sql.SQLException; import java.util.ArrayList; @@ -156,7 +155,7 @@ public class IncomingDataTransfer extends AbstractTransfer implements HashCheckC this.owner = publishData.user; this.image = idr; this.fileSize = publishData.fileSize; - this.machineDescription = transferInfo.machineDescription.getBytes(StandardCharsets.UTF_8); + this.machineDescription = ThriftUtil.unwrapByteBuffer(transferInfo.machineDescription); this.masterTransferInfo = transferInfo; this.versionSettings = new ImageVersionWrite(false); } diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/mail/MailGenerator.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/mail/MailGenerator.java index 47006742..2a47f5e8 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/mail/MailGenerator.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/mail/MailGenerator.java @@ -1,9 +1,11 @@ package org.openslx.bwlp.sat.mail; import java.sql.SQLException; +import java.text.BreakIterator; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Map.Entry; @@ -50,7 +52,7 @@ public class MailGenerator { for (UserInfo user : relevantUsers) { if (newVersion.uploaderId.equals(user.userId)) // Don't notice about changes by user continue; - MailQueue.queue(new Mail(user, message)); + MailQueue.queue(new Mail(user, wordWrap(message))); } } } @@ -67,13 +69,13 @@ public class MailGenerator { return; for (LectureSummary lecture : lectures) { List<UserInfo> relevantUsers = getUserToMail(lecture); - String message = "Die VM-Version der Veranstaltung '" + lecture.lectureName - + "' wurde gelöscht oder ist beschädigt,\n" - + " daher verweist sie jetzt auf die VM-Version vom " - + Formatter.date(newVersion.createTime) + ".\n" - + " Bitte überprüfen Sie ggf. die Verlinkte VM bzgl. Ihrer Kursinhalte."; + String message = "Die verlinkte VM zur Veranstaltung '" + lecture.lectureName + + "' wurde gelöscht oder ist beschädigt," + + " daher verweist sie jetzt auf die VM-Version vom " + + Formatter.date(newVersion.createTime) + "." + + " Bitte überprüfen Sie ggf., ob diese VM-Version für Ihren Kurs geeignet ist."; for (UserInfo user : relevantUsers) { - MailQueue.queue(new Mail(user, message)); + MailQueue.queue(new Mail(user, wordWrap(message))); } } } @@ -84,11 +86,11 @@ public class MailGenerator { for (LectureSummary lecture : lectures) { List<UserInfo> relevantUsers = getUserToMail(lecture); String message = "Die Veranstaltung '" + lecture.lectureName + "' musste deaktiviert werden," - + "\n da die verknüpfte VM gelöscht oder beschädigt wurde. Bitte prüfen" - + "\n Sie die Veranstaltung und ändern Sie ggf. die Verlinkung," - + "\n damit die Veranstaltung nicht gelöscht wird."; + + " da die verknüpfte VM gelöscht oder beschädigt wurde. Bitte überprüfen" + + " Sie die Veranstaltung und ändern Sie ggf. die Verlinkung," + + " damit die Veranstaltung wieder verwendbar ist."; for (UserInfo user : relevantUsers) { - MailQueue.queue(new Mail(user, message)); + MailQueue.queue(new Mail(user, wordWrap(message))); } } } @@ -114,27 +116,26 @@ public class MailGenerator { newVersion = version; } } - String message = "VM '" + image.imageName + "':"; + String message = "Virtuelle Maschine '" + image.imageName + "':"; if (newVersion == null) { - message += "\n Die letzte verbliebene Version der VM wurde gelöscht; VM deaktiviert."; + message += " Die letzte verbliebene Version der VM wurde gelöscht; VM deaktiviert."; } else { String uploaderName; try { User uploader = DbUser.getCached(newVersion.uploaderId); - uploaderName = uploader.ui.firstName + " " + uploader.ui.lastName + " <" + uploader.ui.eMail - + ">"; + uploaderName = Formatter.userFullName(uploader.ui) + " <" + uploader.ui.eMail + ">"; } catch (TNotFoundException | SQLException e) { uploaderName = "(unbekannt)"; } - message += "\n Neueste Version ist jetzt vom " + Formatter.date(oldVersion.createTime) + message += "\n Neueste Version ist jetzt vom " + Formatter.date(oldVersion.createTime) + " (erstellt von " + uploaderName + ")"; if (oldVersion != null) { - message += "\n Zuvor neueste Verson war vom " + Formatter.date(oldVersion.createTime); + message += "\n Vorherige Verson war vom " + Formatter.date(oldVersion.createTime); } } List<UserInfo> relevantUsers = getUserToMail(image); for (UserInfo user : relevantUsers) { - MailQueue.queue(new Mail(user, message)); + MailQueue.queue(new Mail(user, wordWrap(message))); } } @@ -150,18 +151,19 @@ public class MailGenerator { } String message; if (image.latestVersionId == null || image.latestVersionId.equals(version.imageVersionId)) { - message = "Die aktuellste Version der VM '" + image.imageName + "' läuft\n" + " in " + days - + " Tag(en) ab. Bitte aktualisieren Sie die VM."; + message = "Die aktuellste Version der VM '" + image.imageName + "' läuft in " + days + + " Tag(en) ab. Bitte aktualisieren Sie die VM, da verknüpfte" + + " Veranstaltungen sonst deaktiviert werden."; } else if (mailForced) { message = "Eine alte Version der VM '" + image.imageName + "' läuft in " + days - + " Tag(en) ab.\n" - + " Eine aktuellere Version ist vorhanden, diese Nachricht ist rein informell."; + + " Tag(en) ab (Version vom " + Formatter.date(version.createTime) + ")." + + " Eine aktuellere Version ist vorhanden, diese Nachricht dient nur der Information."; } else { return; } List<UserInfo> relevantUsers = getUserToMail(image); for (UserInfo user : relevantUsers) { - MailQueue.queue(new Mail(user, message)); + MailQueue.queue(new Mail(user, wordWrap(message))); } } @@ -171,7 +173,7 @@ public class MailGenerator { List<UserInfo> relevantUsers = getUserToMail(lecture); String message = "Die Veranstaltung '" + lecture.lectureName + "' läuft in " + days + " Tag(en) ab."; for (UserInfo user : relevantUsers) { - MailQueue.queue(new Mail(user, message)); + MailQueue.queue(new Mail(user, wordWrap(message))); } } @@ -248,4 +250,69 @@ public class MailGenerator { return list; } + private static String wordWrap(String input) { + return wordWrap(input, 76, "\n ", Locale.GERMAN); + } + + private static String wordWrap(String input, int width, String nlString, Locale locale) { + if (input == null) { + return ""; + } else if (width < 5) { + return input; + } else if (width >= input.length()) { + return input; + } + + StringBuilder buf = new StringBuilder(input); + boolean endOfLine = false; + int lineStart = 0; + + for (int i = 0; i < buf.length(); i++) { + if (buf.charAt(i) == '\n') { + lineStart = i + 1; + endOfLine = true; + } + + // handle splitting at width character + if (i > lineStart + width - 1) { + if (endOfLine) { + buf.insert(i, nlString); + lineStart = i + nlString.length(); + endOfLine = false; + } else { + int limit = i - lineStart - 1; + BreakIterator breaks = BreakIterator.getLineInstance(locale); + breaks.setText(buf.substring(lineStart, i)); + int end = breaks.last(); + + // if the last character in the search string isn't a space, + // we can't split on it (looks bad). Search for a previous + // break character + if (end == limit + 1) { + if (!Character.isWhitespace(buf.charAt(lineStart + end))) { + end = breaks.preceding(end - 1); + } + } + + // if the last character is a space, replace it with a \n + if (end != BreakIterator.DONE && end == limit + 1) { + buf.replace(lineStart + end, lineStart + end + 1, nlString.substring(0, 1)); + buf.insert(lineStart + end + 1, nlString.substring(1)); + lineStart = lineStart + end + nlString.length() - 1; + } + // otherwise, just insert a \n + else if (end != BreakIterator.DONE && end != 0) { + buf.insert(lineStart + end, nlString); + lineStart = lineStart + end + nlString.length(); + } else { + buf.insert(i, nlString); + lineStart = i + nlString.length(); + } + } + } + } + + return buf.toString(); + } + } diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/mail/MailQueue.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/mail/MailQueue.java index 0ba396d2..6ed921ff 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/mail/MailQueue.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/mail/MailQueue.java @@ -184,7 +184,7 @@ public class MailQueue { }, TimeUnit.MINUTES.toMillis(1)); } - private static boolean sendMail(MailConfig conf, SmtpMailer smtpc, UserInfo user, String message) { + private static boolean sendMail(MailConfig conf, SmtpMailer smtpc, UserInfo user, final String message) { // TODO: Template String fullMessage = "Guten Tag " + user.firstName + " " + user.lastName + ",\n\n" + "Bitte beachten Sie folgende Hinweise zu Virtuellen Maschinen und Veranstaltungen,\n" @@ -199,8 +199,14 @@ public class MailQueue { fullMessage += "\n\nBei weiteren Fragen wenden Sie sich bitte an den Support unter\n" + conf.replyTo; } - fullMessage += "\n\n--\n" + "Generiert auf " + conf.serverName; - return smtpc.send(user.eMail, "[bwLehrstuhl] Hinweise zu Ihren VMs/Veranstaltungen", fullMessage); + fullMessage += "\n\n-- \n" + "Generiert auf " + conf.serverName; + if (fullMessage.contains("\r\n")) { + fullMessage = fullMessage.replace("\r\n", "\n"); + } + if (fullMessage.contains("\n")) { + fullMessage = fullMessage.replace("\n", "\r\n"); + } + return smtpc.send(user.eMail, "[bwLehrpool] Hinweise zu Ihren VMs/Veranstaltungen", fullMessage); } } diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/permissions/User.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/permissions/User.java index 0fc8a365..191a5f92 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/permissions/User.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/permissions/User.java @@ -183,11 +183,14 @@ public class User { "No permission to delete this image"); } - public static void canDownloadImageVersionOrFail(UserInfo user, String imageVersionId) + public static void canDownloadImageVersionOrFail(UserInfo user, String imageBaseId, String imageVersionId) throws TAuthorizationException, TNotFoundException, TInvocationException { ImageDetailsRead image; try { - image = DbImage.getImageDetails(user, DbImage.getBaseIdForVersionId(imageVersionId)); + if (imageBaseId == null) { + imageBaseId = DbImage.getBaseIdForVersionId(imageVersionId); + } + image = DbImage.getImageDetails(user, imageBaseId); } catch (SQLException e) { throw new TInvocationException(); } diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/ServerHandler.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/ServerHandler.java index 3b76efcd..94d95042 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/ServerHandler.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/ServerHandler.java @@ -13,6 +13,7 @@ import org.openslx.bwlp.sat.database.mappers.DbImagePermissions; import org.openslx.bwlp.sat.database.mappers.DbLecture; import org.openslx.bwlp.sat.database.mappers.DbLecturePermissions; import org.openslx.bwlp.sat.database.mappers.DbUser; +import org.openslx.bwlp.sat.database.models.ImageVersionMeta; import org.openslx.bwlp.sat.database.models.LocalUser; import org.openslx.bwlp.sat.fileserv.FileServer; import org.openslx.bwlp.sat.fileserv.IncomingDataTransfer; @@ -133,14 +134,23 @@ public class ServerHandler implements SatelliteServer.Iface { throws TAuthorizationException, TInvocationException, TNotFoundException, TTransferRejectedException { UserInfo user = SessionManager.getOrFail(userToken); - User.canDownloadImageVersionOrFail(user, imageVersionId); + ImageVersionMeta imageVersion; + try { + imageVersion = DbImage.getVersionDetails(imageVersionId); + } catch (SQLException e) { + throw new TInvocationException(); + } + User.canDownloadImageVersionOrFail(user, imageVersion.imageBaseId, imageVersionId); OutgoingDataTransfer transfer; try { transfer = fileServer.createNewUserDownload(DbImage.getLocalImageData(imageVersionId)); } catch (SQLException e) { throw new TInvocationException(); } - return new TransferInformation(transfer.getId(), fileServer.getPlainPort(), fileServer.getSslPort()); + TransferInformation ti = new TransferInformation(transfer.getId(), fileServer.getPlainPort(), fileServer.getSslPort()); + ti.setBlockHashes(imageVersion.sha1sums); + ti.setMachineDescription(imageVersion.machineDescription); + return ti; } @Override |
