/* ****************************************************************************** * 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.signin.internal; import static net.xmind.signin.internal.EncodingUtils.urlEncode; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; import net.xmind.signin.IDataStore; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpMethodBase; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.httpclient.URI; import org.apache.commons.httpclient.methods.ByteArrayRequestEntity; import org.apache.commons.httpclient.methods.DeleteMethod; import org.apache.commons.httpclient.methods.EntityEnclosingMethod; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.PutMethod; import org.apache.commons.httpclient.methods.RequestEntity; import org.apache.commons.httpclient.methods.multipart.FilePart; import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; import org.apache.commons.httpclient.methods.multipart.Part; import org.apache.commons.httpclient.methods.multipart.StringPart; import org.json.JSONException; import org.json.JSONObject; public class XMindNetRequest { private static final String DEFAULT_DOMAIN = "www.xmind.net"; //$NON-NLS-1$ public static final int ERROR = 599; private static class Parameter { public String name; public Object value; public Parameter(String name, Object value) { this.name = name; this.value = value; } public String getValue() { return value == null ? "" : value.toString(); //$NON-NLS-1$ } } private static final String DEFAULT_CONTENT_TYPE = "application/x-www-form-urlencoded; charset=UTF-8"; //$NON-NLS-1$ private boolean useHTTPS; private HttpMethodBase method = null; private String uri = null; private List<NameValuePair> headers = new ArrayList<NameValuePair>(); private List<Parameter> params = new ArrayList<Parameter>(); private String domain = DEFAULT_DOMAIN; private boolean multipart = false; private int code = 0; private IDataStore data = null; private String responseText = null; private boolean aborted = false; private Throwable exception = null; private boolean debugging = System .getProperty("org.xmind.debug.httprequests") != null; //$NON-NLS-1$ public XMindNetRequest() { this(false); } public XMindNetRequest(boolean useHTTPS) { this.useHTTPS = useHTTPS; } public int getCode() { return code; } public IDataStore getData() { return data; } public XMindNetRequest uri(String api, Object... values) { this.uri = EncodingUtils.format(api, values); return this; } public XMindNetRequest domain(String domain) { this.domain = domain; return this; } public XMindNetRequest useHTTPS() { this.useHTTPS = true; return this; } public XMindNetRequest multipart() { this.multipart = true; return this; } public XMindNetRequest setAuthToken(String authToken) { return this.addHeader("AuthToken", authToken); //$NON-NLS-1$ } public XMindNetRequest addHeader(String name, String value) { headers.add(new NameValuePair(name, value)); return this; } public XMindNetRequest addParameter(String name, Object value) { params.add(new Parameter(name, value)); return this; } protected HttpMethodBase getMethod() { return method; } public void abort() { if (method != null) method.abort(); aborted = true; } public boolean isAborted() { return aborted; } public XMindNetRequest get() { this.method = new GetMethod(); return execute(); } public XMindNetRequest put() { this.method = new PutMethod(); return execute(); } public XMindNetRequest delete() { this.method = new DeleteMethod(); return execute(); } public XMindNetRequest post() { this.method = new PostMethod(); return execute(); } protected XMindNetRequest execute() { if (isAborted()) return this; prepare(); try { parseResponse(new HttpClient().executeMethod(method)); } catch (Exception e) { parseResponse(ERROR); } return this; } public String getResponseText() { return responseText; } public String getResponseHeader(String name) { Header header = method.getResponseHeader(name); return header == null ? null : header.getValue(); } public Throwable getException() { return exception; } protected void prepare() { setHeaders(); String uri = this.uri; if (!params.isEmpty()) { if (method instanceof EntityEnclosingMethod) { RequestEntity entity = generateRequestEntity(); if (entity != null) { ((EntityEnclosingMethod) method).setRequestEntity(entity); } } else { uri = generateQueryString(uri, "?"); //$NON-NLS-1$ } } StringBuffer sb = new StringBuffer(); if (useHTTPS) { sb.append("https://"); //$NON-NLS-1$ } else { sb.append("http://"); //$NON-NLS-1$ } sb.append(domain); sb.append(uri); uri = sb.toString(); if (debugging) { Activator.log(String.format( "Request: method=%s, uri='%s', headers=%s", //$NON-NLS-1$ method.getClass().getSimpleName(), uri, headers)); } try { method.setURI(new URI(uri, false)); } catch (Exception e) { //should not happen } } private void setHeaders() { for (NameValuePair header : headers) { method.setRequestHeader(header.getName(), header.getValue()); } if (method.getRequestHeader("Accept") == null) { //$NON-NLS-1$ method.setRequestHeader("Accept", "application/json"); //$NON-NLS-1$ //$NON-NLS-2$ } } private RequestEntity generateRequestEntity() { if (multipart) { List<Part> parts = new ArrayList<Part>(params.size()); for (Parameter param : params) { if (param.value instanceof File) { try { parts.add(new FilePart(param.name, (File) param.value)); } catch (FileNotFoundException e) { } } else { parts.add(new StringPart(param.name, param.getValue(), "utf-8")); //$NON-NLS-1$ } } return new MultipartRequestEntity(parts.toArray(new Part[parts .size()]), method.getParams()); } else { String query = generateQueryString(); try { return new ByteArrayRequestEntity( query.getBytes("utf-8"), DEFAULT_CONTENT_TYPE); //$NON-NLS-1$ } catch (UnsupportedEncodingException e) { //should not happen } } return null; } protected String generateQueryString(String... prefix) { StringBuffer sb = new StringBuffer(params.size() * 15); for (String p : prefix) { sb.append(p); } for (int i = 0; i < params.size(); i++) { Parameter param = params.get(i); if (i > 0) { sb.append('&'); } sb.append(urlEncode(param.name)); sb.append('='); sb.append(urlEncode(param.getValue())); } return sb.toString(); } protected void parseResponse(int rawCode) { this.code = rawCode; this.data = null; if (rawCode == ERROR) { this.responseText = null; } else { this.responseText = extractResponseText(); if (this.responseText != null) { String respType = getResponseHeader("Content-Type"); //$NON-NLS-1$ if (respType != null && respType.indexOf("application/json") >= 0) { //$NON-NLS-1$ try { this.data = new JSONStore(new JSONObject( this.responseText)); } catch (JSONException e) { exception = e; } if (this.data != null) { if (rawCode == HttpStatus.SC_OK && this.data.has("_code")) { //$NON-NLS-1$ this.code = this.data.getInt("_code"); //$NON-NLS-1$ } } } } } if (debugging) { Activator.log(String.format("Response: code=%s, text='%s'", //$NON-NLS-1$ code, responseText)); } } private String extractResponseText() { try { return method.getResponseBodyAsString(); } catch (IOException e) { exception = e; return null; } } public XMindNetRequest debug() { this.debugging = true; return this; } }