package net.xmind.share.jobs; import java.io.File; import java.io.IOException; import net.xmind.share.Info; import net.xmind.share.XmindSharePlugin; import net.xmind.signin.IDataStore; import net.xmind.signin.internal.XMindNetRequest; import org.apache.commons.httpclient.HttpStatus; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.json.JSONException; /** * The whole process: * <ol> * <li>Retrieve upload session</li> * <li>Upload file</li> * <li>Retrieve uploading progress</li> * <li>Cancel uploading</li> * </ol> * * @author Frank Shaka * */ public class UploadSession { public static final int INITIALIZED = 0; public static final int PREPARING = 1; public static final int UPLOADING = 2; public static final int COMPLETED = 3; public static final int CANCELING = 4; public static final int CANCELED = 5; public static final int CODE_VERIFICATION_FAILURE = 1001; private static final boolean DEBUG = System .getProperty("org.xmind.debug.share") != null; //$NON-NLS-1$ private static final String UPLOAD_API = "/_fs/mapfile/%s"; //$NON-NLS-1$ private static final String SESSION_API = "/_fs/mapfile/%s/%s"; //$NON-NLS-1$ // private static final String RES_URL = "http://www.xmind.net/_fs/mapfile/"; //$NON-NLS-1$ // private static final String RES_URL = "http://172.16.231.141:8080/upload/"; //$NON-NLS-1$ private String userName; private String authToken; private String title; private File sourceFile; private String sessionId; private int status; private IStatus termination; private String permalink; private String viewLink; private double uploadProgress; private XMindNetRequest prepareRequest = null; private XMindNetRequest transferRequest = null; private XMindNetRequest retrieveProgressRequest = null; public UploadSession(Info info) { this.userName = info.getString(Info.USER_ID); Assert.isNotNull(this.userName); this.authToken = info.getString(Info.TOKEN); Assert.isNotNull(this.authToken); this.title = info.getString(Info.TITLE); Assert.isNotNull(this.title); this.sourceFile = (File) info.getProperty(Info.FILE); Assert.isNotNull(this.sourceFile); setStatus(INITIALIZED); } public File getSourceFile() { return sourceFile; } public String getPermalink() { return permalink; } public String getViewLink() { return viewLink; } public double getUploadProgress() { return uploadProgress; } public int getStatus() { return status; } public IStatus getError() { return termination; } public boolean hasError() { return termination != null && !termination.isOK(); } /** * Retrieve upload session. * <p> * [Request:]<br> * Url: http://www.xmindshare.com/_fs/mapfile/{USERNAME}<br> * Method: POST<br> * Headers: AuthToken<br> * Params: title:{TITLE}<br> * </p> * <p> * [Response]<br> * 400: Url is invalid, or the required fields not present in request.<br> * 401: User must signin.<br> * 403: User is allowed only to upload file for themselves.<br> * 500: Server error.<br> * 200: OK<br> * session: {SESSION}<br> * url: {URL} * * @throws IOException * @throws JSONException */ public IStatus prepare() { setStatus(PREPARING); debug("[upload][prepare] userName=%s, authToken=%s, title=%s", //$NON-NLS-1$ userName, authToken, title); XMindNetRequest request = new XMindNetRequest(); if (DEBUG) request.debug(); prepareRequest = request; request.uri(UPLOAD_API, userName); request.setAuthToken(authToken); request.addParameter("title", title); //$NON-NLS-1$ request.post(); if (request.isAborted()) { setStatus(CANCELED); return ok(); } int code = request.getCode(); IDataStore data = request.getData(); debug("[upload][prepare] response code=%s", code); //$NON-NLS-1$ debug("[upload][prepare] response text='%s'", request.getResponseText()); //$NON-NLS-1$ if (code == HttpStatus.SC_OK && data != null) { String sessionId = data.getString("session"); //$NON-NLS-1$ if (sessionId == null) return error(500); this.sessionId = sessionId; this.permalink = data.getString("url"); //$NON-NLS-1$ String mapname = data.getString("mapname"); //$NON-NLS-1$ if (mapname != null) { this.viewLink = String.format( "http://www.xmind.net/xmind/map/%s/%s/%s", //$NON-NLS-1$ userName, authToken, mapname); } return ok(); } return error(code, request.getException()); // try { // String url = makeUploadURL(userName); // debug("[prepare upload] url=" + url); //$NON-NLS-1$ // // HttpClient client = new HttpClient(); // request.setURI(new URI(url, true, client.getParams() // .getUriCharset())); // request.setRequestHeader("Content-Type", //$NON-NLS-1$ // "application/x-www-form-urlencoded; charset=UTF-8"); //$NON-NLS-1$ // setTokenAndJson(request, authToken); // request.setParameter("title", title); //$NON-NLS-1$ // // debug("[prepare upload] execute 'post'"); //$NON-NLS-1$ // int code = client.executeMethod(request); // debug("[prepare upload] result code=" + code); //$NON-NLS-1$ // if (code != HttpStatus.SC_OK) // return error(code); // // String resp = request.getResponseBodyAsString(); // debug("[prepare upload] response=" + resp); //$NON-NLS-1$ // JSONObject json = new JSONObject(resp); // code = json.optInt("_code", -1); //$NON-NLS-1$ // if (code != HttpStatus.SC_OK) // return error(code); // // this.sessionId = json.getString("session"); //$NON-NLS-1$ // this.permalink = json.optString("url", null); //$NON-NLS-1$ // String mapname = json.optString("mapname", null); //$NON-NLS-1$ // if (mapname != null) { // this.viewLink = "http://www.xmind.net/xmind/map/" + userName //$NON-NLS-1$ // + "/" + authToken + "/" + mapname; //$NON-NLS-1$ //$NON-NLS-2$ // } // return ok(); // } catch (IOException e) { // return error(e); // } catch (JSONException e) { // return error(e); // } } /** * Upload file. * <p> * [Request]<br> * Url: http://www.xmindshare.com/_fs/mapfile/{USERNAME}/{SESSION}<br> * Method: POST<br> * Params: map:{MAP FILE} * </p> * <p> * [Response]<br> * 400: Url is invalid, or request is not valid file upload request, or User * cancel uploading process.<br> * 500: Server error.<br> * 200: OK * * @throws IOException */ public IStatus transfer() { setStatus(UPLOADING); debug("[upload][transfer] userName=%s, sessionId=%s, sourceFile=%s", //$NON-NLS-1$ userName, sessionId, sourceFile.getAbsolutePath()); XMindNetRequest request = new XMindNetRequest().multipart(); if (DEBUG) request.debug(); transferRequest = request; request.uri(SESSION_API, userName, sessionId); request.addParameter("map", sourceFile); //$NON-NLS-1$ request.post(); if (request.isAborted()) { setStatus(CANCELED); return ok(); } int code = request.getCode(); debug("[upload][transfer] response code=%s", code); //$NON-NLS-1$ debug("[upload][transfer] response text=%s", request.getResponseText()); //$NON-NLS-1$ if (code == HttpStatus.SC_OK) return ok(); return error(code, request.getException()); // // try { // Part[] parts = new Part[] { new FilePart("map", sourceFile) }; //$NON-NLS-1$ // String url = makeUploadURL(userName, sessionId); // HttpClient client = new HttpClient(); // request.setURI(new URI(url, true, client.getParams() // .getUriCharset())); // request.setRequestEntity(new MultipartRequestEntity(parts, request // .getParams())); // int code = client.executeMethod(request); // if (code != HttpStatus.SC_OK) { // return error(code); // } // return ok(); // } catch (IOException e) { // return error(e); // } } /** * Retrieve uploading progress. * <p> * [Request]<br> * Url: http://www.xmindshare.com/_fs/mapfile/{USERNAME}/{SESSION}<br> * Method: GET<br> * Headers: AuthToken * </p> * <p> * [Response]<br> * 400: Url is invalid<br> * 403: User is allowed only view its own file uploading progress.<br> * 404: Request file uploading progress is not found, maybe finished, * canceled or no exist.<br> * 200: OK<br> * status: <br> * read: {READ}<br> * total: {TOTAL}<br> * items: {ITEMS}<br> * progress: {PROGRESS} // 0 ~ 1 * * @return * @throws IOException * @throws JSONException */ public IStatus retrieveProgress() { debug("[upload][progress] userName=%s, sessionId=%s", //$NON-NLS-1$ userName, sessionId); XMindNetRequest request = new XMindNetRequest(); if (DEBUG) request.debug(); retrieveProgressRequest = request; request.uri(SESSION_API, userName, sessionId); request.setAuthToken(authToken); request.get(); if (request.isAborted()) { setStatus(CANCELED); return ok(); } int code = request.getCode(); IDataStore data = request.getData(); debug("[upload][progress] response code=%s", code); //$NON-NLS-1$ debug("[upload][progress] response text=%s", request.getResponseText()); //$NON-NLS-1$ if (code == HttpStatus.SC_OK && data != null) { String status = data.getString("status"); //$NON-NLS-1$ if (status != null) { debug("[upload][progress] status=%s", status); //$NON-NLS-1$ if ("forbidden".equals(status)) { //$NON-NLS-1$ return error(CODE_VERIFICATION_FAILURE); } else if ("error".equals(status)) { //$NON-NLS-1$ return error(HttpStatus.SC_INTERNAL_SERVER_ERROR); } else if ("finished".equals(status)) { //$NON-NLS-1$ setStatus(COMPLETED); return ok(); } } uploadProgress = data.getDouble("progress"); //$NON-NLS-1$ return ok(); } return error(code, request.getException()); // try { // HttpClient client = new HttpClient(); // request.setURI(new URI(makeUploadURL(userName, sessionId), true, // client.getParams().getUriCharset())); // setTokenAndJson(request, authToken); // int code = client.executeMethod(request); // if (code != HttpStatus.SC_OK) { // return error(code); // } // String respBody = request.getResponseBodyAsString(); // debug("[upload session info] " + respBody); //$NON-NLS-1$ // JSONObject resp = new JSONObject(respBody); // if (resp.has("status")) { //$NON-NLS-1$ // String status = resp.getString("status"); //$NON-NLS-1$ // debug("[upload progress] status=" + status); //$NON-NLS-1$ // if ("forbidden".equals(status)) { //$NON-NLS-1$ // return error(CODE_VERIFICATION_FAILURE); // } else if ("error".equals(status)) { //$NON-NLS-1$ // return error(HttpStatus.SC_INTERNAL_SERVER_ERROR); // } else if ("finished".equals(status)) { //$NON-NLS-1$ // setStatus(COMPLETED); // return ok(); // } // } // uploadProgress = resp.getDouble("progress"); //$NON-NLS-1$ // return ok(); // } catch (IOException e) { // return error(e); // } catch (JSONException e) { // return error(e); // } } /** * Cancel uploading. * <p> * [Request]<br> * Url: http://www.xmindshare.com/_fs/mapfile/{USERNAME}/{SESSION}<br> * Method: DELETE<br> * Headers: AuthToken * </p> * <p> * [Response]<br> * 400: Url is invalid<br> * 403: User is allowed only to cancel his own file<br> * upload process.<br> * 200: OK * * @throws IOException */ public IStatus cancel() { if (prepareRequest != null) prepareRequest.abort(); if (transferRequest != null) transferRequest.abort(); if (retrieveProgressRequest != null) retrieveProgressRequest.abort(); debug("[upload][cancel] userName=%s, sessionId=%s", //$NON-NLS-1$ userName, sessionId); if (sessionId == null) return Status.CANCEL_STATUS; setStatus(CANCELING); XMindNetRequest request = new XMindNetRequest(); if (DEBUG) request.debug(); request.uri(SESSION_API, userName, sessionId); request.setAuthToken(authToken); request.delete(); if (request.isAborted()) { setStatus(CANCELED); return ok(); } int code = request.getCode(); debug("[upload][cancel] response code=%s", code); //$NON-NLS-1$ debug("[upload][cancel] response text=%s", request.getResponseText()); //$NON-NLS-1$ if (code == HttpStatus.SC_OK) { setStatus(CANCELED); return ok(); } return error(code, request.getException()); // try { // DeleteMethod method = new DeleteMethod(makeUploadURL(userName, // sessionId)); // setTokenAndJson(method, authToken); // HttpClient client = new HttpClient(); // int code = client.executeMethod(method); // if (code != HttpStatus.SC_OK) // return error(code); // setStatus(CANCELED); // return ok(); // } catch (IOException e) { // return error(e); // } } private void setStatus(int status) { this.status = status; } private IStatus ok() { if (termination == null) termination = Status.OK_STATUS; return termination; } private IStatus error(int code) { return error(code, null); } private IStatus error(int code, Throwable error) { setError(code, error); return termination; } private void setError(int code, Throwable err) { if (hasError() || status == COMPLETED || status == CANCELED) return; termination = createTermination(code, err); } private static IStatus createTermination(int code, Throwable err) { return new Status(IStatus.ERROR, XmindSharePlugin.PLUGIN_ID, code, null, err); } private static void debug(String message, Object... values) { if (DEBUG) { XmindSharePlugin.log(String.format(message, values)); } } // /** // * http://www.xmind.net/_fs/mapfile/{USERNAME}/{SESSION} // */ // private static String makeUploadURL(String... paths) { // return makeURL(RES_URL, paths); // } // // public static String makeURL(String url, String... paths) { // StringBuilder sb = new StringBuilder(url.length() + paths.length * 10); // sb.append(url); // for (String path : paths) { // if (sb.charAt(sb.length() - 1) != '/') { // sb.append('/'); // } // try { // sb.append(URLEncoder.encode(path, "UTF-8")); //$NON-NLS-1$ // } catch (UnsupportedEncodingException e) { // sb.append(path); // } // } // return sb.toString(); // } // // public static void setTokenAndJson(HttpMethod method, String token) { // method.setRequestHeader("AuthToken", token); //$NON-NLS-1$ // method.setRequestHeader("accept", "application/json"); //$NON-NLS-1$ //$NON-NLS-2$ // } }