com.snaptic.api.SnapticAPI.java Source code

Java tutorial

Introduction

Here is the source code for com.snaptic.api.SnapticAPI.java

Source

package com.snaptic.api;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParserException;

import android.os.Build;
import android.text.format.Time;
import android.util.Log;
import android.util.TimeFormatException;

import com.android.http.multipart.FilePart;
import com.android.http.multipart.MultipartEntity;
import com.android.http.multipart.Part;
/*
 * Copyright (c) 2010 Snaptic, Inc
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * http://snaptic.com Java Android library
 * 
 * Hugh Johnson   <hugh@snaptic.com>
 * Harry Tormey   <harry@snaptic.com>
 */

/**
 * @author Hugh Johnson
 * @author Harry Tormey
 * @version 0.1
 * 
 * A library that provides a Java interface to the Snaptic API
 */

public class SnapticAPI {
    public static final int RESULT_ERROR = 0;
    public static final int RESULT_OK = 1;
    public static final int RESULT_UNAUTHORIZED = 2;
    public static final int RESULT_ERROR_PARSER = 3;
    public static final int RESULT_ERROR_RESPONSE = 4;

    private static final String ENCODING = "UTF-8";
    private static final String USER_AGENT = "SnapticAPI; Java; (Android)";
    private String defaultSource = "android-lib";
    private static final String API_ENDPOINT_PASSWORD_RESET = "/forgotPassword.action";
    private static final String SNAPTIC_BASE_URL = "https://api.snaptic.com";
    private static final String API_ENDPOINT_ACCOUNT_INFO = "/v1/user";
    private static final String API_ENDPOINT_NOTES = "/v1/notes";
    private static final String API_ENDPOINT_IMAGES = "/v1/images";
    private static final String API_ENDPOINT_SEARCH = "/v1/search.xml";
    // Enable this for extra API call tracing output in the logcat.
    private static final boolean API_TRACING_OUTPUT_ENABLED = true;//false;
    private static final String LOGCAT_NAME = "SnapticAPI";

    private String basicUserAuth;
    private HttpClient httpClient;
    private Time timestamper;

    /**
     * Java Android interface to the Snaptic API.
     *
     * @param String user snaptic username.
     * @param String password password for account.
     */
    public SnapticAPI(String user, String password) {
        String auth = user + ':' + password;
        basicUserAuth = "Basic " + new String(Base64.encodeBase64(auth.getBytes()));
        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setUserAgent(params, USER_AGENT);
        HttpProtocolParams.setContentCharset(params, "UTF-8");
        httpClient = new DefaultHttpClient(params);

        try {
            @SuppressWarnings("unused")
            Field field = Build.VERSION.class.getDeclaredField("SDK_INT");

            if (Build.VERSION.SDK_INT >= 6) {
                // We can use Time & TimeFormatException on Android 2.0.1
                // (API level 6) or greater. It crashes the VM otherwise.
                timestamper = new Time();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Get information about a users account (i.e user name, date created, etc).
     * 
      * @param  SnapticAccount data structure containing username/password.
      * @return int returnCode enum code indicating whether call was successful or not.
     */
    public int getAccountInfo(SnapticAccount account) {
        int returnCode = RESULT_ERROR;

        if (account == null) {
            return returnCode;
        }

        HttpResponse response = null;
        response = performGET(API_ENDPOINT_ACCOUNT_INFO, null);

        if (response != null) {
            if (isResponseOK(response)) {
                boolean parseResult = false;

                try {
                    JSONObject json = new JSONObject(istreamToString(response.getEntity().getContent()));
                    JSONObject user = json.getJSONObject("user");
                    account.id = user.getLong("id");
                    account.username = user.getString("user_name");
                    account.email = user.getString("email");
                    //account.password = password;
                    account.accountCreatedOn = parse3339(user.getString("created_at"));
                    parseResult = true;
                } catch (JSONException e) {
                    log("caught a JSONException processing response from GET " + API_ENDPOINT_ACCOUNT_INFO);
                    e.printStackTrace();
                } catch (IOException e) {
                    log("caught an IOException processing response from GET " + API_ENDPOINT_ACCOUNT_INFO);
                    e.printStackTrace();
                }

                returnCode = (parseResult == true) ? RESULT_OK : RESULT_ERROR_RESPONSE;
            } else if (isResponseUnauthorized(response)) {
                returnCode = RESULT_UNAUTHORIZED;
            }

            consumeResponse(response);
        }

        return returnCode;
    }

    /**
     * Get notes from users account that match query string.
     *  
     * @param String query search for notes that match this string.
     * @param ArrayList<SnapticNote> notes reference to an array of SnapticNote where fetched
     * notes will be placed.
     * @return int returnCode enum code indicating whether call was successful or not.
     * */
    public int searchNotes(String query, ArrayList<SnapticNote> notes) {
        int returnCode = RESULT_ERROR;

        if (notes == null || query == null) {
            return returnCode;
        }

        String endpoint = API_ENDPOINT_SEARCH;
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        params.add(new BasicNameValuePair("q", query));
        HttpResponse response = performGET(endpoint, params);

        if (response != null) {
            if (isResponseOK(response)) {
                boolean parseResult = false;

                try {
                    SnapticNotesXmlParser xmlParser = new SnapticNotesXmlParser();
                    xmlParser.parseNotesXml(response, notes);
                    sync_trace("parsed " + notes.size() + " notes");
                    parseResult = true;
                } catch (IllegalArgumentException e) {
                    log("caught an IllegalArgumentException processing response from GET " + endpoint);
                    e.printStackTrace();
                } catch (XmlPullParserException e) {
                    log("caught an XmlPullParserException processing response from GET " + endpoint);
                    e.printStackTrace();
                } catch (IOException e) {
                    log("caught an IOException processing response from GET " + endpoint);
                    e.printStackTrace();
                }

                returnCode = (parseResult == true) ? RESULT_OK : RESULT_ERROR_RESPONSE;
            } else if (isResponseUnauthorized(response)) {
                returnCode = RESULT_UNAUTHORIZED;
            }

            consumeResponse(response);
        }

        return returnCode;
    }

    /**
     * Get notes from users account.
     *
     * @param ArrayList<SnapticNote> notes reference to an array of SnapticNote where fetched
     * notes will be placed.
     * @return int returnCode enum code indicating whether call was successful or not.
     */
    public int getNotes(ArrayList<SnapticNote> notes) {
        int returnCode = RESULT_ERROR;

        if (notes == null) {
            return returnCode;
        }

        String endpoint = API_ENDPOINT_NOTES + ".xml";
        HttpResponse response = performGET(endpoint, null);

        if (response != null) {
            if (isResponseOK(response)) {
                boolean parseResult = false;

                try {
                    SnapticNotesXmlParser xmlParser = new SnapticNotesXmlParser();
                    xmlParser.parseNotesXml(response, notes);
                    sync_trace("parsed " + notes.size() + " notes");
                    parseResult = true;
                } catch (IllegalArgumentException e) {
                    log("caught an IllegalArgumentException processing response from GET " + endpoint);
                    e.printStackTrace();
                } catch (XmlPullParserException e) {
                    log("caught an XmlPullParserException processing response from GET " + endpoint);
                    e.printStackTrace();
                } catch (IOException e) {
                    log("caught an IOException processing response from GET " + endpoint);
                    e.printStackTrace();
                }

                returnCode = (parseResult == true) ? RESULT_OK : RESULT_ERROR_RESPONSE;
            } else if (isResponseUnauthorized(response)) {
                returnCode = RESULT_UNAUTHORIZED;
            }

            consumeResponse(response);
        }

        return returnCode;
    }

    /**
     * Get image data associated with Id number.
     * 
      * @param long id of image to be returned.
      * @param File image image file returned from call.
     * @return int returnCode enum code indicating whether call was successful or not.
     */
    public int getImage(long id, File image) {
        int returnCode = RESULT_ERROR;

        if (image == null || !image.canWrite()) {
            return returnCode;
        }

        String endpoint = API_ENDPOINT_IMAGES + '/' + id;

        try {
            HttpResponse response = performGET(endpoint, null);

            if (response != null) {
                if (isResponseOK(response)) {
                    // Copy the response data containing the image to the File
                    // specified by the caller.
                    if (!image.exists()) {
                        image.createNewFile();
                    }

                    InputStream in = response.getEntity().getContent();
                    OutputStream out = new FileOutputStream(image);

                    byte[] b = new byte[8 * 1024];
                    int read;

                    while ((read = in.read(b)) != -1) {
                        out.write(b, 0, read);
                    }

                    out.flush();
                    out.close();
                    in.close();
                    returnCode = RESULT_OK;
                } else if (isResponseUnauthorized(response)) {
                    returnCode = RESULT_UNAUTHORIZED;
                }

                consumeResponse(response);
            }
        } catch (FileNotFoundException e) {
            log("caught a FileNotFoundException in addImage() for image file: " + image.getAbsolutePath());
            e.printStackTrace();
        } catch (IOException e) {
            log("caught a IOException in getImage() for " + endpoint);
            e.printStackTrace();

            // File is likely no good.
            if (image.exists()) {
                image.delete();
            }
        }

        return returnCode;
    }

    /**
     * Post a new note.
     *
     * @param SnapticNote note to be posted.
     * @return int returnCode enum code indicating whether call was successful or not.
     */
    public int addNote(SnapticNote note) {
        int returnCode = RESULT_ERROR;

        if (note == null) {
            return returnCode;
        }

        String source = defaultSource;

        if (note.source != null && note.source.length() > 0) {
            source = note.source.toString();
        }

        List<NameValuePair> params = new ArrayList<NameValuePair>();
        params.add(new BasicNameValuePair("text", note.text.toString()));
        params.add(new BasicNameValuePair("source", source));
        params.add(new BasicNameValuePair("created_at", Long.toString(note.creationTime)));
        params.add(new BasicNameValuePair("modified_at", Long.toString(note.modificationTime)));
        params.add(new BasicNameValuePair("reminder_at", Long.toString(note.reminderTime)));
        params.add(new BasicNameValuePair("latitude", Double.toString(note.latitude)));
        params.add(new BasicNameValuePair("longitude", Double.toString(note.longitude)));
        params.add(new BasicNameValuePair("altitude", Double.toString(note.altitude)));
        params.add(new BasicNameValuePair("speed", Double.toString(note.speed)));
        params.add(new BasicNameValuePair("bearing", Double.toString(note.bearing)));
        params.add(new BasicNameValuePair("accuracy_position", Double.toString(note.accuracyPosition)));
        params.add(new BasicNameValuePair("accuracy_altitude", Double.toString(note.accuracyAltitude)));

        String endpoint = API_ENDPOINT_NOTES + ".xml";
        HttpResponse response = performPOST(endpoint, params, null);

        if (response != null) {
            if (isResponseOK(response)) {
                boolean parseResult = false;

                try {
                    SnapticNotesXmlParser xmlParser = new SnapticNotesXmlParser();
                    ArrayList<SnapticNote> notes = new ArrayList<SnapticNote>(1);
                    xmlParser.parseNotesXml(response, notes);

                    if (notes.size() > 0 && notes.get(0) != null) {
                        // Copy the returned note values into the original note object
                        note.copy(notes.get(0));
                        parseResult = true;
                    }
                } catch (IllegalArgumentException e) {
                    log("caught an IllegalArgumentException processing response from POST " + endpoint);
                    e.printStackTrace();
                } catch (XmlPullParserException e) {
                    log("caught an XmlPullParserException processing response from POST " + endpoint);
                    e.printStackTrace();
                } catch (IOException e) {
                    log("caught an IOException processing response from POST " + endpoint);
                    e.printStackTrace();
                }

                returnCode = (parseResult == true) ? RESULT_OK : RESULT_ERROR_RESPONSE;
            } else if (isResponseUnauthorized(response)) {
                returnCode = RESULT_UNAUTHORIZED;
            }

            consumeResponse(response);
        }

        return returnCode;
    }

    /**
     * Add image to a given note.
     *
     * @param long id of note to append image to.
     * @param File image file to be appended. 
     * @return int returnCode enum code indicating whether call was successful or not.
     */
    public int addImage(long id, File image) {
        int returnCode = RESULT_ERROR;

        if (image == null) {
            return returnCode;
        }

        try {
            String endpoint = API_ENDPOINT_IMAGES + '/' + id;
            Part[] parts = { new FilePart("image", image, "image/jpeg", null) };

            HttpResponse response = performPOST(endpoint, null, parts);

            if (response != null) {
                if (isResponseOK(response)) {
                    returnCode = RESULT_OK;
                } else if (isResponseUnauthorized(response)) {
                    returnCode = RESULT_UNAUTHORIZED;
                }

                consumeResponse(response);
            }
        } catch (FileNotFoundException e) {
            log("caught a FileNotFoundException in addImage() for image file: " + image.getAbsolutePath());
            e.printStackTrace();
        }

        return returnCode;
    }

    /**
     * Edit an existing note.
     *
     * @param SnapticNote note to be updated. note.id must be a valid existing note id.
     * @return int returnCode enum code indicating whether call was successful or not.
     */
    public int editNote(SnapticNote note) {
        int returnCode = RESULT_ERROR;

        if (note == null) {
            return returnCode;
        }

        String source = defaultSource;

        if (note.source != null && note.source.length() > 0) {
            source = note.source.toString();
        }

        List<NameValuePair> params = new ArrayList<NameValuePair>();
        params.add(new BasicNameValuePair("text", note.text.toString()));
        params.add(new BasicNameValuePair("source", source));
        params.add(new BasicNameValuePair("created_at", Long.toString(note.creationTime)));
        params.add(new BasicNameValuePair("modified_at", Long.toString(note.modificationTime)));
        params.add(new BasicNameValuePair("reminder_at", Long.toString(note.reminderTime)));
        params.add(new BasicNameValuePair("latitude", Double.toString(note.latitude)));
        params.add(new BasicNameValuePair("longitude", Double.toString(note.longitude)));
        params.add(new BasicNameValuePair("altitude", Double.toString(note.altitude)));
        params.add(new BasicNameValuePair("speed", Double.toString(note.speed)));
        params.add(new BasicNameValuePair("bearing", Double.toString(note.bearing)));
        params.add(new BasicNameValuePair("accuracy_position", Double.toString(note.accuracyPosition)));
        params.add(new BasicNameValuePair("accuracy_altitude", Double.toString(note.accuracyAltitude)));

        String endpoint = API_ENDPOINT_NOTES + '/' + note.id + ".xml";
        HttpResponse response = performPOST(endpoint, params, null);

        if (response != null) {
            if (isResponseOK(response)) {
                boolean parseResult = false;

                try {
                    SnapticNotesXmlParser xmlParser = new SnapticNotesXmlParser();
                    ArrayList<SnapticNote> notes = new ArrayList<SnapticNote>(1);
                    xmlParser.parseNotesXml(response, notes);

                    if (notes.size() > 0 && notes.get(0) != null) {
                        // Copy the returned note values into the original note object
                        note.copy(notes.get(0));
                        parseResult = true;
                    }
                } catch (IllegalArgumentException e) {
                    log("caught an IllegalArgumentException processing response from POST " + endpoint);
                    e.printStackTrace();
                } catch (XmlPullParserException e) {
                    log("caught an XmlPullParserException processing response from POST " + endpoint);
                    e.printStackTrace();
                } catch (IOException e) {
                    log("caught an IOException processing response from POST " + endpoint);
                    e.printStackTrace();
                }

                returnCode = (parseResult == true) ? RESULT_OK : RESULT_ERROR_RESPONSE;
            } else if (isResponseUnauthorized(response)) {
                returnCode = RESULT_UNAUTHORIZED;
            }

            consumeResponse(response);
        }

        return returnCode;
    }

    /**
     * Delete a note.
     *
     * @param lond id of note to be deleted.
     * @return int returnCode enum code indicating whether call was successful or not.
     */
    public int deleteNote(long id) {
        int returnCode = RESULT_ERROR;
        HttpResponse response = performDELETE(API_ENDPOINT_NOTES + '/' + id);

        if (response != null) {
            if (isResponseOK(response)) {
                returnCode = RESULT_OK;
            } else if (isResponseUnauthorized(response)) {
                returnCode = RESULT_UNAUTHORIZED;
            }

            consumeResponse(response);
        }

        return returnCode;
    }

    public int resetPassword(String email) {
        int returnCode = RESULT_ERROR;
        HttpResponse response = null;

        if (email != null && email.length() > 0) {
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("email", email));
            response = performPOST(API_ENDPOINT_PASSWORD_RESET, params, null);

            if (response != null) {
                if (isResponseOK(response)) {
                    returnCode = RESULT_OK;
                }

                consumeResponse(response);
            }
        }

        return returnCode;
    }

    /**
     * Delete a image.
     *
     * @param lond id of image to be deleted.
     * @return int returnCode enum code indicating whether call was successful or not.
     */
    public int deleteImage(long id) {
        int returnCode = RESULT_ERROR;
        HttpResponse response = performDELETE(API_ENDPOINT_IMAGES + '/' + id);

        if (response != null) {
            if (isResponseOK(response)) {
                returnCode = RESULT_OK;
            } else if (isResponseUnauthorized(response)) {
                returnCode = RESULT_UNAUTHORIZED;
            }

            consumeResponse(response);
        }

        return returnCode;
    }

    private HttpResponse performGET(String method, List<NameValuePair> httpParams) {
        HttpGet httpget;

        if (httpParams == null || httpParams.isEmpty()) {
            httpget = new HttpGet(SNAPTIC_BASE_URL + method);
        } else {
            httpget = new HttpGet(SNAPTIC_BASE_URL + method + '?' + URLEncodedUtils.format(httpParams, "UTF-8"));
        }

        httpget.addHeader("Authorization", basicUserAuth);
        HttpResponse response = null;

        try {
            response = httpClient.execute(httpget);
        } catch (ClientProtocolException e) {
            log("caught ClientProtocolException performing GET " + httpget.getURI());
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            log("caught IOException performing GET " + httpget.getURI());
            e.printStackTrace();
            return null;
        }

        sync_trace("GET " + httpget.getURI() + " returned " + response.getStatusLine().getStatusCode() + ' '
                + response.getStatusLine().getReasonPhrase());
        return response;
    }

    private HttpResponse performPOST(String method, List<NameValuePair> parameters, Part[] parts) {
        HttpPost httppost = new HttpPost(SNAPTIC_BASE_URL + method);
        httppost.addHeader("Authorization", basicUserAuth);

        if (parameters != null && !parameters.isEmpty()) {
            try {
                httppost.setEntity(new UrlEncodedFormEntity(parameters, HTTP.UTF_8));
            } catch (UnsupportedEncodingException e) {
                log("caught UnsupportedEncodingException performing POST " + httppost.getURI());
                e.printStackTrace();
                return null;
            }
        } else if (parts != null) {
            HttpProtocolParams.setUseExpectContinue(httppost.getParams(), false);
            httppost.setEntity(new MultipartEntity(parts, httppost.getParams()));
        }

        HttpResponse response = null;

        try {
            response = httpClient.execute(httppost);
        } catch (ClientProtocolException e) {
            log("caught ClientProtocolException performing POST " + httppost.getURI());
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            log("caught IOException performing POST " + httppost.getURI());
            e.printStackTrace();
            return null;
        }

        sync_trace("POST " + httppost.getURI() + " returned " + response.getStatusLine().getStatusCode() + ' '
                + response.getStatusLine().getReasonPhrase());
        return response;
    }

    private HttpResponse performDELETE(String method) {
        HttpDelete httpdelete = new HttpDelete(SNAPTIC_BASE_URL + method);
        httpdelete.addHeader("Authorization", basicUserAuth);
        HttpResponse response = null;

        try {
            response = httpClient.execute(httpdelete);
        } catch (ClientProtocolException e) {
            log("caught ClientProtocolException performing DELETE " + httpdelete.getURI());
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            log("caught IOException performing DELETE " + httpdelete.getURI());
            e.printStackTrace();
            return null;
        }

        sync_trace("DELETE " + httpdelete.getURI() + " returned " + response.getStatusLine().getStatusCode() + ' '
                + response.getStatusLine().getReasonPhrase());
        return response;
    }

    private boolean isResponseOK(HttpResponse response) {
        return (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK);
    }

    private boolean isResponseUnauthorized(HttpResponse response) {
        return (response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED);
    }

    private void consumeResponse(HttpResponse response) {
        if (response != null && response.getEntity() != null) {
            try {
                response.getEntity().consumeContent();
            } catch (IOException e) {
                log("caught an IOException attempting to consume the content of an HttpResponse");
                e.printStackTrace();
            }
        }
    }

    private long parse3339(String time) {
        if (time == null || time.length() == 0) {
            return 0;
        }

        if (timestamper != null) {
            try {
                timestamper.parse3339(time);
            } catch (TimeFormatException e) {
                log("caught a TimeFormatException parsing timestamp: \"" + time + '"');
                e.printStackTrace();
                return 0;
            }

            return timestamper.normalize(false);
        } else {
            Date timestamp = new Date();

            SimpleDateFormat rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
            rfc3339.setLenient(true);

            try {
                timestamp = rfc3339.parse(time);
            } catch (ParseException e) {
                log("caught a ParseException parsing timestamp: \"" + time + '"');
                e.printStackTrace();
                return 0;
            }

            return timestamp.getTime();
        }
    }

    // from Translate.java
    /*
     * Copyright (C) 2008 Google Inc.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    private static String istreamToString(InputStream inputStream) throws IOException {
        StringBuilder outputBuilder = new StringBuilder();
        String string;

        if (inputStream != null) {
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, ENCODING));

            while (null != (string = reader.readLine())) {
                outputBuilder.append(string).append('\n');
            }

            reader.close();
        }

        return outputBuilder.toString();
    }

    // Helper function to log error messages.
    private void log(String msg) {
        Log.e(LOGCAT_NAME, msg);
    }

    // Helper function to log tracing messages.
    private void sync_trace(String msg) {
        if (API_TRACING_OUTPUT_ENABLED) {
            Log.d(LOGCAT_NAME, msg);
        }
    }

    /**
     * Helper function to turn internal function return codes into readable text.
     *
     * @param int code enum code indicating whether call was successful or not.
     * @return String code converted into readable string.
     */
    public static String resultToString(int code) {
        switch (code) {
        case RESULT_ERROR:
            return "RESULT_ERROR";
        case RESULT_OK:
            return "RESULT_OK";
        case RESULT_UNAUTHORIZED:
            return "RESULT_UNAUTHORIZED";
        case RESULT_ERROR_PARSER:
            return "RESULT_ERROR_PARSER";
        case RESULT_ERROR_RESPONSE:
            return "RESULT_ERROR_RESPONSE";
        default:
            return "UNKNOWN (" + code + ")";
        }
    }
}