com.leanengine.RestService.java Source code

Java tutorial

Introduction

Here is the source code for com.leanengine.RestService.java

Source

/*
 * This software is released under the GNU Lesser General Public License v3.
 * For more information see http://www.gnu.org/licenses/lgpl.html
 *
 * Copyright (c) 2011, Peter Knego & Matjaz Tercelj
 * All rights reserved.
 */

package com.leanengine;

import android.os.AsyncTask;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
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.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.util.EntityUtils;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;

class RestService {

    private static RestService INSTANCE = new RestService();

    private volatile HttpClient client;
    private Configuration configuration = new Configuration(); // default

    public static RestService getInstance() {
        return INSTANCE;
    }

    private HttpClient getClient() {
        if (client == null) {
            synchronized (this) {
                if (client == null) {
                    if (configuration != null) {
                        final HttpParams params = new BasicHttpParams();
                        HttpConnectionParams.setConnectionTimeout(params, configuration.getConnectionTimeout());
                        HttpProtocolParams.setVersion(params, configuration.getHttpVersion());
                        HttpProtocolParams.setContentCharset(params, configuration.getContentCharset());

                        final SchemeRegistry schemeRegistry = new SchemeRegistry();
                        schemeRegistry.register(
                                new Scheme("http", configuration.getPlainFactory(), configuration.getPort()));
                        schemeRegistry.register(
                                new Scheme("https", configuration.getSslFactory(), configuration.getSslPort()));

                        final ClientConnectionManager ccm = configuration.createClientConnectionManager(params,
                                schemeRegistry);

                        client = configuration.createClient(ccm, params);
                    } else {
                        client = new DefaultHttpClient();
                    }
                }
            }
        }
        return client;
    }

    public void setConfiguration(Configuration configuration) {
        this.configuration = configuration;
    }

    /**
     * Dispose http client / its connection manager once done.
     */
    public void dispose() {
        final HttpClient temp = client;
        client = null;
        if (temp != null) {
            final ClientConnectionManager manager = temp.getConnectionManager();
            if (manager != null)
                manager.shutdown();
        }
    }

    private JSONObject doGet(String uri) throws IOException {
        HttpGet httpget = new HttpGet(uri);
        httpget.addHeader("Accept", "application/json");
        httpget.addHeader("Accept-Charset", "UTF-8");

        return getClient().execute(httpget, new RestResponseHandler());
    }

    private JSONObject doPost(String uri, JSONObject json) throws IOException {
        HttpPost httpPost = new HttpPost(uri);
        httpPost.addHeader("Accept", "application/json");
        httpPost.addHeader("Accept-Charset", "UTF-8");
        httpPost.addHeader("Content-Type", "application/json");
        httpPost.setEntity(new StringEntity(json.toString(), "UTF-8"));

        return getClient().execute(httpPost, new RestResponseHandler());
    }

    private void doDelete(String uri) throws IOException {
        HttpDelete httpget = new HttpDelete(uri);
        httpget.addHeader("Content-Type", "application/json");

        getClient().execute(httpget, new DeleteResponseHandler());
    }

    protected LeanEntity getPrivateEntity(final String kind, final Long id)
            throws LeanException, IllegalArgumentException {
        if (!LeanAccount.isUserLoggedIn())
            throw new LeanException(LeanError.Type.NotAuthorizedError);

        String url;
        if (kind != null && id != null) {
            url = LeanEngine.getHostURI() + "/rest/v1/entity/" + kind + "/" + id + "?lean_token="
                    + LeanEngine.getAuthToken();

        } else {
            throw new IllegalArgumentException("Parameters 'kind' and 'id' must not be null.");
        }
        try {
            JSONObject jsonObject = doGet(url);
            return JsonDecode.entityFromJson(jsonObject);
        } catch (IOException e) {
            throw new LeanException(LeanError.Type.NetworkError);
        }
    }

    protected void getPrivateEntityAsync(final String kind, final long id,
            final NetworkCallback<LeanEntity> networkCallback) {

        final RestAsyncTask<LeanEntity[]> aTask = new RestAsyncTask<LeanEntity[]>() {

            // executes on background thread
            @Override
            protected LeanEntity[] doInBackground(Void... lists) {
                try {
                    return new LeanEntity[] { getPrivateEntity(kind, id) };
                } catch (LeanException e) {
                    error = e.getError();
                    return null;
                }
            }

            // executes on UI thread
            @Override
            protected void onPostExecute(LeanEntity[] leanEntities) {
                if (error != null) {
                    networkCallback.onFailure(error);
                    return;
                }
                networkCallback.onResult(leanEntities);
            }
        };

        aTask.execute((Void) null);
    }

    public void deletePrivateEntity(String kind, Long id) throws LeanException {
        if (!LeanAccount.isUserLoggedIn())
            throw new LeanException(LeanError.Type.NotAuthorizedError);

        String url;
        if (kind != null && id != null) {
            url = LeanEngine.getHostURI() + "/rest/v1/entity/" + kind + "/" + id + "?lean_token="
                    + LeanEngine.getAuthToken();
        } else {
            throw new IllegalArgumentException("Parameters 'kind' and 'id' must not be null.");
        }

        try {
            doDelete(url);
        } catch (IOException e) {
            throw new LeanException(LeanError.Type.NetworkError);
        }
    }

    public void deletePrivateEntityAsync(final String kind, final long id,
            final NetworkCallback<Void> networkCallback) throws LeanException {

        final RestAsyncTask<Void> aTask = new RestAsyncTask<Void>() {

            // executes on background thread
            @Override
            protected Void doInBackground(Void... lists) {
                try {
                    deletePrivateEntity(kind, id);
                    return null;
                } catch (LeanException e) {
                    error = e.getError();
                    return null;
                }
            }

            // executes on UI thread
            @Override
            protected void onPostExecute(Void anything) {
                if (error != null) {
                    networkCallback.onFailure(error);
                    return;
                }
                networkCallback.onResult((Void) null);
            }
        };

        aTask.execute((Void) null);

    }

    protected LeanEntity[] getPrivateEntities(final String kind) throws LeanException {
        if (!LeanAccount.isUserLoggedIn())
            throw new LeanException(LeanError.Type.NotAuthorizedError);

        String url;
        if (kind != null) {
            url = LeanEngine.getHostURI() + "/rest/v1/entity/" + kind + "?lean_token=" + LeanEngine.getAuthToken();
        } else {
            url = LeanEngine.getHostURI() + "/rest/v1/entity?lean_token=" + LeanEngine.getAuthToken();
        }

        try {
            JSONObject jsonObject = doGet(url);
            return JsonDecode.entityListFromJson(jsonObject);
        } catch (IOException e) {
            throw new LeanException(LeanError.Type.NetworkError);
        }
    }

    protected void getPrivateEntitiesAsync(final String kind, final NetworkCallback<LeanEntity> networkCallback) {

        final RestAsyncTask<LeanEntity[]> aTask = new RestAsyncTask<LeanEntity[]>() {

            // executes on background thread
            @Override
            protected LeanEntity[] doInBackground(Void... lists) {
                try {
                    return getPrivateEntities(kind);
                } catch (LeanException e) {
                    error = e.getError();
                    return null;
                }
            }

            // executes on UI thread
            @Override
            protected void onPostExecute(LeanEntity[] leanEntities) {
                if (error != null) {
                    networkCallback.onFailure(error);
                    return;
                }
                networkCallback.onResult(leanEntities);
            }
        };

        aTask.execute((Void) null);
    }

    protected long putPrivateEntity(final LeanEntity entity) throws LeanException {
        if (!LeanAccount.isUserLoggedIn())
            throw new LeanException(LeanError.Type.NotAuthorizedError);
        //todo externalize URLs (and token insertion)
        String url = LeanEngine.getHostURI() + "/rest/v1/entity/" + entity.kind + "?lean_token="
                + LeanEngine.getAuthToken();
        try {
            JSONObject param = JsonEncode.entityToJson(entity);
            JSONObject jsonObject = doPost(url, param);
            return idFromJson(jsonObject);
        } catch (IOException e) {
            throw new LeanException(LeanError.Type.NetworkError);
        }
    }

    protected void putPrivateEntityAsync(final LeanEntity entity, final NetworkCallback<Long> networkCallback) {
        RestAsyncTask<Long> aTask = new RestAsyncTask<Long>() {

            // executes on background thread
            @Override
            protected Long doInBackground(Void... lists) {
                try {
                    return putPrivateEntity(entity);
                } catch (LeanException e) {
                    error = e.getError();
                    return -1l;
                }
            }

            // executes on UI thread
            @Override
            protected void onPostExecute(Long entityID) {
                if (error != null) {
                    networkCallback.onFailure(error);
                    return;
                }
                networkCallback.onResult(entityID);
            }
        };

        aTask.execute((Void) null);
    }

    protected LeanEntity[] queryPrivate(final LeanQuery query) throws LeanException {
        if (!LeanAccount.isUserLoggedIn())
            throw new LeanException(LeanError.Type.NotAuthorizedError);

        String url = LeanEngine.getHostURI() + "/rest/v1/query?lean_token=" + LeanEngine.getAuthToken();

        try {
            JSONObject queryJson = JsonEncode.queryToJson(query);
            JSONObject jsonObject = doPost(url, queryJson);

            // update the Query's cursor - used in fetching next results
            String cursor = jsonObject.optString("cursor");
            if (cursor.length() != 0)
                query.setCursor(cursor);

            return JsonDecode.entityListFromJson(jsonObject);
        } catch (IOException e) {
            throw new LeanException(LeanError.Type.NetworkError);
        }
    }

    protected void queryPrivateAsync(final LeanQuery query, final NetworkCallback<LeanEntity> networkCallback) {

        final RestAsyncTask<LeanEntity[]> aTask = new RestAsyncTask<LeanEntity[]>() {

            // executes on background thread
            @Override
            protected LeanEntity[] doInBackground(Void... lists) {
                try {
                    return queryPrivate(query);
                } catch (LeanException e) {
                    error = e.getError();
                    return null;
                }
            }

            // executes on UI thread
            @Override
            protected void onPostExecute(LeanEntity[] leanEntities) {
                if (error != null) {
                    networkCallback.onFailure(error);
                    return;
                }
                networkCallback.onResult(leanEntities);
            }
        };

        aTask.execute((Void) null);
    }

    protected Boolean logout() throws LeanException {
        if (!LeanAccount.isUserLoggedIn())
            throw new LeanException(LeanError.Type.NotAuthorizedError);

        String url = LeanEngine.getHostURI() + "/rest/v1/public/logout?lean_token=" + LeanEngine.getAuthToken();

        try {
            JSONObject jsonObject = doGet(url);
            boolean result = resultFromJson(jsonObject);

            // after the request is made we must also clear local data
            LeanEngine.resetAuthToken();
            LeanEngine.clearCookies();
            return result;
        } catch (IOException e) {
            throw new LeanException(LeanError.Type.NetworkError);
        }
    }

    public void logoutAsync(final NetworkCallback<Boolean> callback) {
        final RestAsyncTask<Boolean[]> aTask = new RestAsyncTask<Boolean[]>() {

            // executes on background thread
            @Override
            protected Boolean[] doInBackground(Void... lists) {
                try {
                    return new Boolean[] { logout() };
                } catch (LeanException e) {
                    error = e.getError();
                    return null;
                }
            }

            // executes on UI thread
            @Override
            protected void onPostExecute(Boolean[] result) {
                if (error != null) {
                    callback.onFailure(error);
                    return;
                }
                callback.onResult(result);
            }
        };

        aTask.execute((Void) null);
    }

    public LeanAccount getCurrentAccountData() throws LeanException {
        if (!LeanAccount.isUserLoggedIn())
            throw new LeanException(LeanError.Type.NotAuthorizedError);

        String url = LeanEngine.getHostURI() + "/rest/v1/public/account?lean_token=" + LeanEngine.getAuthToken();

        try {
            JSONObject jsonObject = doGet(url);
            return JsonDecode.accountFromJson(jsonObject);
        } catch (IOException e) {
            throw new LeanException(LeanError.Type.NetworkError);
        }
    }

    public void getCurrentAccountDataAsync(final NetworkCallback<LeanAccount> networkCallback)
            throws LeanException {
        final RestAsyncTask<LeanAccount[]> aTask = new RestAsyncTask<LeanAccount[]>() {

            // executes on background thread
            @Override
            protected LeanAccount[] doInBackground(Void... lists) {
                try {
                    return new LeanAccount[] { getCurrentAccountData() };
                } catch (LeanException e) {
                    error = e.getError();
                    return null;
                }
            }

            // executes on UI thread
            @Override
            protected void onPostExecute(LeanAccount[] leanAccounts) {
                if (error != null) {
                    networkCallback.onFailure(error);
                    return;
                }
                networkCallback.onResult(leanAccounts);
            }
        };

        aTask.execute((Void) null);
    }

    protected static abstract class RestAsyncTask<Result> extends AsyncTask<Void, Void, Result> {
        protected LeanError error;
    }

    protected static class RestResponseHandler implements ResponseHandler<JSONObject> {

        @Override
        public JSONObject handleResponse(HttpResponse response) throws LeanException {
            StatusLine statusLine = response.getStatusLine();

            HttpEntity entity = response.getEntity();
            String result;
            try {
                result = entity != null ? EntityUtils.toString(entity, "UTF-8") : null;
            } catch (IOException e) {
                throw new LeanException(LeanError.Type.NetworkError);
            }

            if (statusLine.getStatusCode() >= 300) {
                throw new LeanException(LeanError.fromJSON(result));
            }

            if (result != null) {
                try {
                    return new JSONObject(result);
                } catch (JSONException e) {
                    throw new LeanException(LeanError.Type.ServerError, "Malformed JSON reply: " + e.getMessage());
                }
            } else {
                throw new LeanException(LeanError.Type.ServerError, "Malformed JSON reply.");
            }
        }
    }

    protected static class DeleteResponseHandler implements ResponseHandler<Void> {

        @Override
        public Void handleResponse(HttpResponse response) throws LeanException {
            StatusLine statusLine = response.getStatusLine();

            if (statusLine.getStatusCode() >= 300) {
                throw new LeanException(LeanError.Type.ServerError);
            }

            return null;
        }
    }

    private static Long idFromJson(JSONObject json) throws LeanException {
        try {
            return json.getLong("id");
        } catch (JSONException e) {
            throw new LeanException(LeanError.Type.ServerError, "Malformed JSON reply: missing field 'id'.");
        }
    }

    private static boolean resultFromJson(JSONObject json) throws LeanException {
        try {
            return json.getBoolean("result");
        } catch (JSONException e) {
            throw new LeanException(LeanError.Type.ServerError, "Malformed JSON reply: missing field 'result'.");
        }
    }
}