package org.openslx.dozmod.thrift;
import java.awt.Frame;
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;
import javax.swing.JFileChooser;
import org.apache.log4j.Logger;
import org.apache.thrift.TException;
import org.openslx.bwlp.thrift.iface.ImageBaseWrite;
import org.openslx.bwlp.thrift.iface.ImageDetailsRead;
import org.openslx.bwlp.thrift.iface.ImagePermissions;
import org.openslx.bwlp.thrift.iface.ImageVersionDetails;
import org.openslx.bwlp.thrift.iface.ImageVersionWrite;
import org.openslx.bwlp.thrift.iface.LecturePermissions;
import org.openslx.bwlp.thrift.iface.LectureRead;
import org.openslx.bwlp.thrift.iface.LectureSummary;
import org.openslx.bwlp.thrift.iface.LectureWrite;
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.TransferInformation;
import org.openslx.bwlp.thrift.iface.TransferState;
import org.openslx.bwlp.thrift.iface.UserInfo;
import org.openslx.bwlp.thrift.iface.WhoamiInfo;
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;
import org.openslx.dozmod.gui.helper.MessageType;
import org.openslx.dozmod.gui.helper.QFileChooser;
import org.openslx.dozmod.util.FormatHelper;
import org.openslx.dozmod.util.VmWrapper;
import org.openslx.dozmod.util.VmWrapper.MetaDataMissingException;
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;
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;
/* *******************************************************************************
*
* LOGIN
*
* Login methods
*
* **************************************************************************
* ****
*/
/**
* @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 initializing the session worked, false otherwise
*/
public static boolean initSession(final Frame frame, AuthenticationData data) {
Client client = null;
WhoamiInfo whoami = null;
String address = null;
String satToken = null;
String masterToken = null;
if (data == null) {
// in session resume
SavedSession session = Config.getSavedSession();
if (session != null) {
address = session.address;
satToken = session.token;
masterToken = session.masterToken;
} else {
// fail
return false;
}
} else {
// after login
// TODO sat adress selection popup!!
address = "132.230.8.113";
satToken = data.satelliteToken;
masterToken = data.masterToken;
}
// try to get a new client
client = ThriftManager.getNewSatelliteClient(GraphicalCertHandler.getSslContext(address), address,
App.THRIFT_SSL_PORT, App.THRIFT_TIMEOUT_MS);
if (client == null)
return false;
// check our version
long remoteVersion = 0;
try {
remoteVersion = client.getVersion();
} catch (TException e) {
LOGGER.debug("Failed to retrieve remote version: ", e);
return false;
}
if (remoteVersion != Version.VERSION) {
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);
}
return false;
}
// all good, try to get the whoami info
try {
whoami = client.whoami(satToken);
} 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);
}
return false;
} catch (TInvocationException e) {
if (data != null) {
Gui.showMessageBox(
frame,
"Authentifizierung erfolgreich, bei der Kommunikation mit dem Satelliten trat jedoch ein interner Server-Fehler auf.",
MessageType.ERROR, LOGGER, e);
}
return false;
} catch (Exception e) {
if (data != null) {
Gui.showMessageBox(
frame,
"Authentifizierung erfolgreich, aber der Satellit akzeptiert das Sitzungstoken nicht.",
MessageType.ERROR, LOGGER, e);
}
return false;
}
if (whoami != null) {
Session.initialize(whoami, address, satToken, masterToken);
ThriftManager.setSatelliteAddress(
GraphicalCertHandler.getSslContext(Session.getSatelliteAddress()),
Session.getSatelliteAddress(), App.THRIFT_SSL_PORT, App.THRIFT_TIMEOUT_MS);
return true;
}
return false;
}
/* *******************************************************************************
*
* IMAGE CREATION
*
* Creates a base image with the given name
*
* **************************************************************************
* ****
*/
/**
* GUI-BLOCKING Creates the image with the given name. Returns the uuid
* returned by the server
*
* @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) {
String uuid = null;
try {
uuid = ThriftManager.getSatClient().createImage(Session.getSatelliteToken(), name);
} 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);
}
return uuid;
}
/**
* 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
*/
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;
}
/**
* 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
*/
public static void 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");
}
}
/* *******************************************************************************
*
* IMAGE VERSION UPLOAD
*
* Methods to upload an image version. This is compromised of two distinct
* 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
*
* @param frame
* @param transferInformation
* @param versionInfo
*/
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;
}
/* *******************************************************************************
*
* IMAGE VERSION DOWNLOAD
*
* Download image version action composed of the interface
* 'DownloadCallback' and the actual static method 'initDownload' to start
* the download.
*
* **************************************************************************
* ****
*/
/**
* The callback interface to inform the GUI about the status of the
* operation
*/
public interface DownloadCallback {
void downloadInitialized(boolean success);
}
/**
* 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
*/
public static void initDownload(final Frame frame, final String imageVersionId, final String imageName,
final String virtualizerId, final int osId, final long imageSize, final DownloadCallback callback) {
// TODO: Return value? Callback?
QFileChooser fc = new QFileChooser(Config.getDownloadPath(), true);
fc.setDialogTitle("Bitte wählen Sie einen Speicherort");
int action = fc.showSaveDialog(frame);
File selected = fc.getSelectedFile();
if (action != JFileChooser.APPROVE_OPTION || selected == null) {
if (callback != null)
callback.downloadInitialized(false);
return;
}
final File destDir = new File(selected, generateDirname(imageName, imageVersionId));
destDir.getAbsoluteFile().mkdirs();
final File tmpDiskFile = new File(destDir.getAbsolutePath(), VmWrapper.generateFilename(imageName,
null) + ".part");
if (destDir.exists()) {
boolean ret = Gui.showMessageBox(frame, "Verzeichnis '" + destDir.getAbsolutePath()
+ "' existiert bereits, wollen Sie die VM darin überschreiben?",
MessageType.QUESTION_YESNO, LOGGER, null);
if (!ret) {
// user aborted
if (callback != null)
callback.downloadInitialized(false);
return;
}
// delete it
if (!tmpDiskFile.delete() && tmpDiskFile.exists()) {
Gui.showMessageBox(frame, "Datei konnte nicht überschrieben werden!", MessageType.ERROR,
LOGGER, null);
if (callback != null)
callback.downloadInitialized(false);
return;
}
}
// 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);
if (callback != null)
callback.downloadInitialized(false);
return;
}
QuickTimer.scheduleOnce(new Task() {
@Override
public void fire() {
final TransferInformation transInf;
try {
transInf = ThriftManager.getSatClient().requestDownload(Session.getSatelliteToken(),
imageVersionId);
} catch (TException e) {
ThriftError.showMessage(frame, LOGGER, e, "Die Download-Anfrage ist gescheitert");
if (callback != null)
callback.downloadInitialized(false);
return;
}
final DownloadTask dlTask;
try {
dlTask = new DownloadTask(Session.getSatelliteAddress(), transInf.getPlainPort(),
transInf.getToken(), tmpDiskFile, imageSize, null);
} catch (FileNotFoundException e) {
Gui.asyncMessageBox(
"Konnte Download nicht vorbereiten: Der gewählte Zielort ist nicht beschreibbar",
MessageType.ERROR, LOGGER, e);
if (callback != null)
callback.downloadInitialized(false);
return;
}
dlTask.addListener(new TransferEventListener() {
@Override
public void update(TransferEvent event) {
if (event.state != TransferState.FINISHED)
return;
DiskImage diskImage = null;
String ext = virtualizerId;
try {
diskImage = new DiskImage(tmpDiskFile);
} catch (IOException | UnknownImageFormatException e) {
LOGGER.warn("Could not open downloaded image for analyze step", e);
}
if (diskImage != null) {
if (diskImage.format != null) {
ext = diskImage.format.extension;
}
if (diskImage.isCompressed) {
Gui.asyncMessageBox("Die heruntergeladene VM '" + imageName + "' ist ein"
+ "\nkomprimiertes Abbild. Sie müssen das Abbild dekomprimieren,"
+ "\nbevor Sie es verändern können."
+ "\n\n(TODO: Hinweis vmware disk tools)", MessageType.WARNING, null,
null); // TODO
}
}
File destImage = new File(destDir.getAbsolutePath(), VmWrapper.generateFilename(
imageName, ext));
destImage.delete();
if (!tmpDiskFile.renameTo(destImage)) {
destImage = tmpDiskFile; // Must be Windows...
}
try {
VmWrapper.wrapVm(destImage, imageName, transInf.getMachineDescription(),
virtualizerId, osId);
} catch (MetaDataMissingException | IOException e) {
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);
}
}
});
Gui.asyncExec(new Runnable() {
@Override
public void run() {
MainWindow.addDownload(imageName, tmpDiskFile.getName(), dlTask);
}
});
new Thread(dlTask).start();
Config.setDownloadPath(destDir.getParentFile().getAbsolutePath());
if (callback != null)
callback.downloadInitialized(true);
}
});
}
private static String generateDirname(String imageName, String imageVersionId) {
String fileName = imageName.replaceAll("[^a-zA-Z0-9_\\.\\-]+", "_");
if (fileName.length() > 50) {
fileName = fileName.substring(0, 50);
}
fileName += "--" + imageVersionId.substring(0, 8);
return fileName;
}
/* *******************************************************************************
*
* IMAGE METADATA
*
* Fetches image details or permissions
*
* **************************************************************************
* ****
*/
/**
* TODO
*/
public interface ImageMetaCallback {
void fetchedImageDetails(ImageDetailsRead details, Map<String, ImagePermissions> permissions);
}
public static ImageDetailsRead getImageDetails(final Frame frame, final String imageBaseId) {
ImageDetailsRead details = null;
try {
details = ThriftManager.getSatClient().getImageDetails(Session.getSatelliteToken(), imageBaseId);
} catch (TException e) {
ThriftError.showMessage(frame, LOGGER, e, "Fehler beim Lesen der Metadaten");
}
return details;
}
/**
* @param frame
* @param imageBaseId
* @param callback
*/
public static void getImageDetails(final Frame frame, final String imageBaseId,
final ImageMetaCallback callback) {
QuickTimer.scheduleOnce(new Task() {
ImageDetailsRead details = null;
@Override
public void fire() {
details = ThriftActions.getImageDetails(frame, imageBaseId);
Gui.asyncExec(new Runnable() {
@Override
public void run() {
if (callback != null) {
callback.fetchedImageDetails(details, null);
}
}
});
}
});
}
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;
@Override
public void fire() {
// sync calls
details = ThriftActions.getImageDetails(frame, imageBaseId);
permissions = ThriftActions.getImagePermissions(frame, imageBaseId);
Gui.asyncExec(new Runnable() {
@Override
public void run() {
if (callback != null) {
callback.fetchedImageDetails(details, permissions);
}
}
});
}
});
}
// async
public static void getImagePermissions(final Frame frame, final String imageBaseId,
final ImageMetaCallback callback) {
QuickTimer.scheduleOnce(new Task() {
Map<String, ImagePermissions> permissionMap = null;
@Override
public void fire() {
permissionMap = ThriftActions.getImagePermissions(frame, imageBaseId);
Gui.asyncExec(new Runnable() {
@Override
public void run() {
if (callback != null) {
callback.fetchedImageDetails(null, permissionMap);
}
}
});
}
});
}
// sync
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);
} catch (TException e) {
ThriftError.showMessage(frame, LOGGER, e, "Fehler beim Lesen der Metadaten");
}
return permissionMap;
}
/**
* 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
* @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());
} catch (TException e) {
ThriftError.showMessage(frame, LOGGER, e, "Fehler beim Übertragen der Besitzrechte");
return false;
}
return true;
}
/* *******************************************************************************
*
* IMAGE / VERSION DELETION
*
* Deletes a specific image version
*
* **************************************************************************
* ****
*/
/**
* Delete callback interface to be implemented by callers of
* ThriftActions.deleteImageVersion(..)
*/
public interface DeleteCallback {
/**
* Called once the status of a delete operation is determined
*
* @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) {
if (imageBaseId == null || imageBaseId.isEmpty())
return;
// first look if we have versions
ImageDetailsRead details = null;
// these help construct the question text for the user, bit ugly...
List<LectureSummary> lecturesToBeDeleted = null;
List<ImageVersionDetails> versionToBeDeleted = null;
try {
details = ThriftManager.getSatClient().getImageDetails(Session.getSatelliteToken(), imageBaseId);
List<LectureSummary> lectureList = ThriftManager.getSatClient().getLectureList(
Session.getSatelliteToken(), 100);
for (LectureSummary lecture : lectureList) {
if (lecture.getImageBaseId().equals(imageBaseId)) {
if (lecturesToBeDeleted == null)
lecturesToBeDeleted = new ArrayList<LectureSummary>();
lecturesToBeDeleted.add(lecture);
}
}
for (ImageVersionDetails version : details.getVersions()) {
if (version.isValid) {
if (versionToBeDeleted == null)
versionToBeDeleted = new ArrayList<ImageVersionDetails>();
versionToBeDeleted.add(version);
}
}
} catch (TException e) {
ThriftError.showMessage(frame, LOGGER, e,
"Fehler beim Holen der Versionen/Veranstaltung zu folgendes Image: " + imageBaseId);
return;
}
String questionText = "";
if (versionToBeDeleted != null) {
questionText = "Dieses Image hat folgende gültige Versionen:\n";
for (ImageVersionDetails version : versionToBeDeleted) {
questionText += version.getVersionId() + "\n";
}
} else {
questionText = "Dieses Image hat keine gültige Version.\n";
}
if (lecturesToBeDeleted != null) {
if (!questionText.isEmpty())
questionText += "\n";
questionText += "Dieses Image ist zu folgende Veranstaltungen verknüpft:\n";
for (LectureSummary lecture : lecturesToBeDeleted) {
questionText += lecture.getLectureName() + "\n";
}
} else {
if (!questionText.isEmpty())
questionText += "\n";
questionText += "Dieses Image ist zu keine Veranstaltungen verknüpft.\n";
}
questionText += "\nWollen Sie dieses Image wirklich löschen?\n";
if (!userConfirmed(frame, questionText))
return;
try {
ThriftManager.getSatClient().deleteImageBase(Session.getSatelliteToken(), imageBaseId);
} catch (TException e) {
// TODO Auto-generated catch block
ThriftError.showMessage(frame, LOGGER, e, "Konnte Basis-Image nicht löschen!");
}
}
/**
* NON-BLOCKING Deletes either an image base or an image version depending
* on the parameters. To delete an image base, give the imageBaseId and let
* imageVersionId be null. To delete an image version, set both imageBaseId
* 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
* DeleteCallback interface)
*/
public static void deleteImageVersion(final Frame frame, final String imageVersionId,
final DeleteCallback callback) {
// TODO async?
if (imageVersionId == null || imageVersionId.isEmpty())
return;
boolean success = false;
List<LectureSummary> lectureList = null;
try {
// fetch lectures
lectureList = ThriftManager.getSatClient().getLectureList(Session.getSatelliteToken(), 100);
} catch (TException e) {
ThriftError.showMessage(frame, LOGGER, e, "Fehler beim Holen der Liste der Veranstaltungen");
if (callback != null)
callback.isDeleted(success);
return;
}
String questionText = "";
// represents if we found matches of not, needed to make a proper
// message
boolean matches = false;
if (lectureList != null && !lectureList.isEmpty()) {
for (LectureSummary lecture : lectureList) {
if (lecture.getImageVersionId().equals(imageVersionId)) {
if (!matches)
questionText = "Diese Version ist zu folgende Veranstaltungen verknüpft:\n";
matches = true;
questionText += lecture.getLectureName() + "\n";
}
}
if (matches)
questionText += "\nWollen Sie diese Version samt Veranstaltungen löschen?\n";
}
if (!matches)
questionText = "Diese Version ist zu keine Veranstaltungen verknüpft.\n"
+ "Wollen Sie sie wirklich löschen?";
if (!userConfirmed(frame, questionText))
return;
try {
ThriftManager.getSatClient().deleteImageVersion(Session.getSatelliteToken(), imageVersionId);
LOGGER.info("Deleted version '" + imageVersionId + "'.");
success = true;
} catch (TException e) {
ThriftError.showMessage(frame, LOGGER, e, "Fehler beim Löschen der Version");
if (callback != null)
callback.isDeleted(success);
return;
}
final boolean fSuccess = success;
Gui.asyncExec(new Runnable() {
@Override
public void run() {
if (callback != null)
callback.isDeleted(fSuccess);
}
});
}
/* *******************************************************************************
*
* LECTURE CREATION
*
* Methods to create lectures
*
* **************************************************************************
* ****
*/
/**
* Creates a lecture with the given meta data
*
* @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) {
if (meta == null)
return null;
String uuid = null;
try {
// push to sat
uuid = ThriftManager.getSatClient().createLecture(Session.getSatelliteToken(), meta);
} catch (TException e) {
ThriftError.showMessage(frame, LOGGER, e, "Failed to create lecture");
}
return uuid;
}
/**
* 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
*/
public static boolean writeLecturePermissions(final Frame frame, final String lectureId,
final Map<String, LecturePermissions> permissions) {
try {
ThriftManager.getSatClient().writeLecturePermissions(Session.getSatelliteToken(), lectureId,
permissions);
} catch (TException e) {
ThriftError.showMessage(frame, LOGGER, e, "Failed to write lecture permissions");
return false;
}
return true;
}
/* *******************************************************************************
*
* LECTURE METADATA
*
* Methods to push metadata of lectures
*
* **************************************************************************
* ****
*/
/**
* @author joe
*
*/
public interface LectureMetaCallback {
void fetchedLectureDetails(LectureRead lecture, ImageDetailsRead image);
void fetchedLecturePermissions(Map<String, LecturePermissions> permissions);
}
/**
* NON-BLOCKING
*
* @param frame
* @param lectureId
* @param callback
*/
public static void getLectureWithImageDetails(final Frame frame, final String lectureId,
final LectureMetaCallback callback) {
QuickTimer.scheduleOnce(new Task() {
@Override
public void fire() {
final LectureRead lecture = ThriftActions.getLectureDetails(frame, lectureId);
ImageDetailsRead image = null;
if (lecture != null) {
image = ThriftActions.getImageDetails(frame, lecture.getImageBaseId());
}
if (image == null)
return;
final ImageDetailsRead fImage = image;
Gui.asyncExec(new Runnable() {
@Override
public void run() {
if (callback != null) {
callback.fetchedLectureDetails(lecture, fImage);
}
}
});
}
});
}
/**
* GUI-BLOCKING
*
* @param frame
* @param lectureId
* @param callback
*/
public static LectureRead getLectureDetails(final Frame frame, final String lectureId) {
LectureRead lecture = null;
try {
lecture = ThriftManager.getSatClient().getLectureDetails(Session.getSatelliteToken(), lectureId);
} catch (TException e) {
ThriftError.showMessage(frame, LOGGER, e, "Konnte Veranstaltungdaten nicht abrufen");
}
return lecture;
}
/**
* 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
* @return
*/
public static boolean updateLecture(final Frame frame, final String lectureId,
final LectureWrite lectureWrite) {
try {
ThriftManager.getSatClient().updateLecture(Session.getSatelliteToken(), lectureId, lectureWrite);
} catch (TException e) {
ThriftError.showMessage(frame, LOGGER, e, "Fehler beim Updaten der Veranstaltung");
return false;
}
return true;
}
/**
* GUI-BLOCKING
*
* @param frame
* @param lectureId
* @param callback
*/
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);
} catch (TException e) {
ThriftError.showMessage(frame, LOGGER, e, "Konnte Veranstaltungdaten nicht abrufen");
}
return permissions;
}
/**
* 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
* @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());
} catch (TException e) {
ThriftError.showMessage(frame, LOGGER, e, "Fehler beim Übertragen der Besitzrechte");
return false;
}
return true;
}
/* *******************************************************************************
*
* LECTURE DELETION
*
* Methods to delete lectures
*
* **************************************************************************
* ****
*/
/**
* Callback interface reporting the status of the deletion back to the gui
*/
public interface DeleteLectureCallback {
void deleted(boolean success);
}
/**
* NON-BLOCKING Deletes the lecture with the given lectureId
*
* @param frame
* @param lectureId
* @param 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?"))
return;
QuickTimer.scheduleOnce(new Task() {
boolean success = false;
@Override
public void fire() {
try {
ThriftManager.getSatClient().deleteLecture(Session.getSatelliteToken(), lectureId);
success = true;
} catch (TException e) {
ThriftError.showMessage(frame, LOGGER, e, "Konnte Veranstaltungdaten nicht abrufen");
}
Gui.asyncExec(new Runnable() {
@Override
public void run() {
if (callback != null) {
callback.deleted(success);
}
}
});
}
});
}
/* *******************************************************************************
*
* PRIVATE HELPERS
*
* **************************************************************************
* ****
*/
/**
* 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
* @return true if the user confirmed (clicked yes), false otherwise
*/
private static boolean userConfirmed(final Frame frame, final String message) {
return Gui.showMessageBox(frame, message, MessageType.QUESTION_YESNO, LOGGER, 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;
}
}
}