/*
* Copyright (c) 2006-2012 XMind Ltd. and others.
*
* This file is a part of XMind 3. XMind releases 3 and above are dual-licensed
* under the Eclipse Public License (EPL), which is available at
* http://www.eclipse.org/legal/epl-v10.html and the GNU Lesser General Public
* License (LGPL), which is available at http://www.gnu.org/licenses/lgpl.html
* See http://www.xmind.net/license.html for details.
*
* Contributors: XMind Ltd. - initial API and implementation
*/
package net.xmind.share.jobs;
import java.io.File;
import java.io.IOException;
import net.xmind.share.Info;
import net.xmind.share.Messages;
import net.xmind.share.XmindSharePlugin;
import net.xmind.signin.IAccountInfo;
import net.xmind.signin.IAuthenticationListener;
import net.xmind.signin.XMindNet;
import org.apache.commons.httpclient.HttpStatus;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
import org.xmind.core.CoreException;
import org.xmind.core.IMeta;
import org.xmind.core.IWorkbook;
import org.xmind.ui.dialogs.SimpleInfoPopupDialog;
public class UploadJob extends Job {
private class TransferWorker implements Runnable {
private Thread thread = null;
public void start() {
if (thread != null)
return;
thread = new Thread(this);
thread.setName("Upload:" + info.getString(Info.TITLE)); //$NON-NLS-1$
thread.setDaemon(false);
thread.setPriority(Thread.NORM_PRIORITY);
thread.start();
}
public void run() {
session.transfer();
}
}
private class ProgressWorker implements Runnable {
private IProgressMonitor monitor;
private int ticks;
private Thread thread = null;
private int ticksUploaded = 0;
public ProgressWorker(IProgressMonitor monitor, int ticks) {
this.monitor = monitor;
this.ticks = ticks;
}
public void start() {
if (thread != null)
return;
thread = new Thread(this);
thread.setName("ProgressWorker:" + info.getString(Info.TITLE)); //$NON-NLS-1$
thread.setDaemon(true);
thread.setPriority(Thread.MIN_PRIORITY);
thread.start();
}
public void cancel() {
if (thread != null) {
thread.interrupt();
thread = null;
}
}
public boolean isCompleted() {
return session.getStatus() == UploadSession.COMPLETED;
}
public void run() {
while (!monitor.isCanceled() && !session.hasError()
&& !isCompleted()) {
session.retrieveProgress();
if (monitor.isCanceled() || session.hasError())
return;
if (isCompleted()) {
monitor.worked(ticks - ticksUploaded);
ticksUploaded = ticks;
return;
}
int newUploaded = (int) (session.getUploadProgress() * ticks);
if (newUploaded > ticksUploaded) {
monitor.worked(newUploaded - ticksUploaded);
ticksUploaded = newUploaded;
}
try {
Thread.sleep(760);
} catch (InterruptedException e) {
return;
}
}
}
}
private Info info;
private UploadSession session;
private TransferWorker transferWorker;
public UploadJob(Info info) {
super(NLS.bind(Messages.UploadJob_name, info.getString(Info.TITLE)));
this.info = info;
}
protected IStatus run(IProgressMonitor monitor) {
IStatus status = doRun(monitor);
// prompt completion information to user
if (status.isOK()) {
promptCompletion();
return status;
}
if (status.matches(IStatus.ERROR)) {
// show error dialog
status = promptError(session.getStatus(), status);
if (status.isOK() || !status.matches(IStatus.ERROR))
return status;
// log this error, but prevent system from prompting dialogs,
// because we have shown our own dialogs above.
XmindSharePlugin.getDefault().getLog().log(status);
return new Status(IStatus.WARNING, status.getPlugin(),
status.getCode(), status.getMessage() == null
|| "".equals(status.getMessage()) ? //$NON-NLS-1$
Messages.UploadJob_Failure_message
: status.getMessage(), status.getException());
}
// other status
return status;
}
private IStatus doRun(IProgressMonitor monitor) {
monitor.beginTask(null, 100);
session = new UploadSession(info);
// retrieve session and url
monitor.subTask(Messages.UploadJob_Task_Prepare);
session.prepare();
if (session.hasError())
return session.getError();
if (monitor.isCanceled())
return Status.CANCEL_STATUS;
monitor.worked(5);
// save the permalink into file
savePermalink();
if (monitor.isCanceled())
return Status.CANCEL_STATUS;
monitor.worked(5);
// start transfering file data up to XMind server
monitor.subTask(Messages.UploadJob_Task_TransferFile);
transferWorker = new TransferWorker();
transferWorker.start();
if (session.hasError())
return session.getError();
if (monitor.isCanceled())
return Status.CANCEL_STATUS;
// wait for processing completion, error or user canceling
// while retrieving transfer progress
ProgressWorker progressWorker = new ProgressWorker(monitor, 89);
progressWorker.start();
do {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
return Status.CANCEL_STATUS;
}
// uploading failed
if (session.hasError())
return session.getError();
// cancel uploading
if (monitor.isCanceled()) {
monitor.subTask(Messages.UploadJob_Task_Cancel);
session.cancel();
progressWorker.cancel();
if (session.hasError())
return session.getError();
return Status.CANCEL_STATUS;
}
} while (!progressWorker.isCompleted());
// uploading completed
monitor.done();
return Status.OK_STATUS;
}
private void savePermalink() {
if (session.getPermalink() == null)
return;
IWorkbook workbook = (IWorkbook) info.getProperty(Info.WORKBOOK);
if (workbook != null) {
workbook.getMeta().setValue(Info.SHARE + IMeta.SEP + "SourceUrl", //$NON-NLS-1$
session.getPermalink());
File file = (File) info.getProperty(Info.FILE);
if (file != null) {
try {
workbook.saveTemp();
workbook.save(file.getAbsolutePath());
} catch (IOException ignore) {
} catch (CoreException ignore) {
}
} else {
try {
workbook.save();
} catch (IOException ignore) {
} catch (CoreException ignore) {
}
}
}
}
private void promptCompletion() {
final Display display = PlatformUI.getWorkbench().getDisplay();
if (display == null || display.isDisposed())
return;
display.asyncExec(new Runnable() {
public void run() {
final SimpleInfoPopupDialog[] dialogs = new SimpleInfoPopupDialog[1];
IAction viewAction = new Action() {
public void run() {
showUploadedMap(session.getViewLink());
if (dialogs[0] != null)
dialogs[0].close();
}
};
viewAction.setText(Messages.UploadJob_View_text);
SimpleInfoPopupDialog dialog = new SimpleInfoPopupDialog(null,
null, Messages.UploadJob_OpenMap_message, 0, null,
viewAction);
dialog.setDuration(10000);
dialog.setGroupId("org.xmind.notifications"); //$NON-NLS-1$
dialog.popUp();
dialogs[0] = dialog;
}
});
}
private void showUploadedMap(String url) {
if (url != null) {
XMindNet.gotoURL(true, url);
return;
}
IAccountInfo accountInfo = XMindNet.getAccountInfo();
if (accountInfo == null)
return;
String userId = accountInfo.getUser();
String token = accountInfo.getAuthToken();
XMindNet.gotoURL(
String.format("http://www.xmind.net/xmind/account/%s/%s/", //$NON-NLS-1$
userId, token), true);
}
private IStatus promptError(int uploadStatus, IStatus error) {
int code = error.getCode();
String message = null;
boolean tryAgainAllowed = true;
if (uploadStatus == UploadSession.PREPARING) {
if (code > 0) {
if (code == HttpStatus.SC_UNAUTHORIZED) {
resignin();
return Status.CANCEL_STATUS;
}
}
} else if (uploadStatus == UploadSession.UPLOADING) {
if (code > 0) {
if (code == HttpStatus.SC_NOT_FOUND) {
return Status.CANCEL_STATUS;
} else if (code == UploadSession.CODE_VERIFICATION_FAILURE) {
message = Messages.ErrorDialog_Unauthorized_message;
tryAgainAllowed = false;
}
}
}
if (message == null)
message = Messages.ErrorDialog_message;
promptErrorMessage(message, tryAgainAllowed);
return error;
}
private void promptErrorMessage(final String message,
final boolean tryAgainAllowed) {
Display display = PlatformUI.getWorkbench().getDisplay();
if (display == null || display.isDisposed())
return;
display.asyncExec(new Runnable() {
public void run() {
if (tryAgainAllowed) {
if (MessageDialog.openQuestion(null,
Messages.ErrorDialog_title, message)) {
schedule();
}
} else {
MessageDialog.openError(null, Messages.ErrorDialog_title,
message);
}
}
});
}
private void resignin() {
XMindNet.signOut();
XMindNet.signIn(new IAuthenticationListener() {
public void postSignIn(IAccountInfo accountInfo) {
info.setProperty(Info.USER_ID, accountInfo.getUser());
info.setProperty(Info.TOKEN, accountInfo.getAuthToken());
schedule();
}
public void postSignOut(IAccountInfo oldAccountInfo) {
}
}, false);
}
@Override
protected void canceling() {
if (session != null) {
session.cancel();
}
super.canceling();
}
}