com.mobeelizer.java.connection.MobeelizerConnectionServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.mobeelizer.java.connection.MobeelizerConnectionServiceImpl.java

Source

// 
// MobeelizerConnectionServiceImpl.java
// 
// Copyright (C) 2012 Mobeelizer Ltd. All Rights Reserved.
//
// Mobeelizer SDK is free software; you can redistribute it and/or modify it 
// under the terms of the GNU Affero General Public License as published by 
// the Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
// for more details.
//
// You should have received a copy of the GNU Affero General Public License 
// along with this program; if not, write to the Free Software Foundation, Inc., 
// 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
//

package com.mobeelizer.java.connection;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.mobeelizer.java.api.MobeelizerMode;
import com.mobeelizer.java.api.MobeelizerOperationError;
import com.mobeelizer.java.api.user.MobeelizerUser;
import com.mobeelizer.java.errors.MobeelizerOperationErrorImpl;
import com.mobeelizer.java.errors.MobeelizerOperationStatus;

public class MobeelizerConnectionServiceImpl implements MobeelizerConnectionService {

    private static final String DEFAULT_TEST_URL = "https://cloud.mobeelizer.com/sync/v2";

    private static final String DEFAULT_PRODUCTION_URL = "https://cloud.mobeelizer.com/sync/v2";

    private final MobeelizerConnectionServiceDelegate delegate;

    public MobeelizerConnectionServiceImpl(final MobeelizerConnectionServiceDelegate delegate) {
        this.delegate = delegate;
    }

    @Override
    public MobeelizerAuthenticateResponse authenticate(final String login, final String password) {
        return authenticate(login, password, null, null);
    }

    @Override
    public MobeelizerAuthenticateResponse authenticate(final String login, final String password,
            final String token) {
        return authenticate(login, password, "android", token);
    }

    @Override
    public MobeelizerAuthenticateResponse authenticate(final String login, final String password,
            final String deviceType, final String deviceToken) {
        try {

            String url;
            if (deviceType != null && deviceToken != null) {
                url = getUrl("/authenticate", "deviceToken", deviceToken, "deviceType", deviceType);
            } else {
                url = getUrl("/authenticate");
            }
            HttpGet request = new HttpGet(url);

            setHeaders(request, true, false);

            request.setHeader("mas-user-name", login);
            request.setHeader("mas-user-password", password);

            MobeelizerOperationStatus<String> content = executeAndGetContent(request);
            if (content.getError() != null) {
                return new MobeelizerAuthenticateResponseImpl(null, null, content.getError());
            }
            JSONObject json = new JSONObject(content.getContent());

            return new MobeelizerAuthenticateResponseImpl(json.getString("role"), json.getString("instanceGuid"),
                    null);
        } catch (JSONException e) {
            return new MobeelizerAuthenticateResponseImpl(null, null,
                    MobeelizerOperationErrorImpl.exception(new IOException(e.getMessage())));
        }
    }

    @Override
    public MobeelizerOperationStatus<List<String>> getGroups() {
        try {
            MobeelizerOperationStatus<String> response = executeGetAndGetContent("/client/user/groups");
            if (response.getError() != null) {
                return new MobeelizerOperationStatus<List<String>>(response.getError());
            }
            JSONArray json = new JSONArray(response.getContent());

            List<String> groups = new ArrayList<String>();

            for (int i = 0; i < json.length(); i++) {
                groups.add(json.getJSONObject(i).getString("name"));
            }
            return new MobeelizerOperationStatus<List<String>>(groups);
        } catch (JSONException e) {
            return new MobeelizerOperationStatus<List<String>>(MobeelizerOperationErrorImpl.exception(e));
        }
    }

    @Override
    public MobeelizerOperationStatus<List<MobeelizerUser>> getUsers() {
        try {
            MobeelizerOperationStatus<String> response = executeGetAndGetContent("/client/user/list");
            if (response.getError() != null) {
                return new MobeelizerOperationStatus<List<MobeelizerUser>>(response.getError());
            }

            JSONArray json = new JSONArray(response.getContent());

            List<MobeelizerUser> users = new ArrayList<MobeelizerUser>(json.length());

            for (int i = 0; i < json.length(); i++) {
                users.add(jsonObjectToUser(json.getJSONObject(i)));
            }

            return new MobeelizerOperationStatus<List<MobeelizerUser>>(users);
        } catch (JSONException e) {
            return new MobeelizerOperationStatus<List<MobeelizerUser>>(MobeelizerOperationErrorImpl.exception(e));
        }
    }

    @Override
    public MobeelizerOperationStatus<MobeelizerUser> getUser(final String login) {
        try {
            MobeelizerOperationStatus<String> response = executeGetAndGetContent("/client/user/get", "login",
                    login);
            if (response.getError() != null) {
                return new MobeelizerOperationStatus<MobeelizerUser>(response.getError());
            }
            JSONObject json = new JSONObject(response.getContent());
            return new MobeelizerOperationStatus<MobeelizerUser>(jsonObjectToUser(json));
        } catch (JSONException e) {
            return new MobeelizerOperationStatus<MobeelizerUser>(MobeelizerOperationErrorImpl.exception(e));
        }
    }

    @Override
    public MobeelizerOperationError createUser(final MobeelizerUser user) {
        try {
            return executePostAndGetContent("/client/user/create", userToJsonObject(user)).getError();
        } catch (JSONException e) {
            return MobeelizerOperationErrorImpl.exception(e);
        }
    }

    @Override
    public MobeelizerOperationError updateUser(final MobeelizerUser user) {
        try {
            return executePostAndGetContent("/client/user/update", userToJsonObject(user)).getError();
        } catch (JSONException e) {
            return MobeelizerOperationErrorImpl.exception(e);
        }
    }

    @Override
    public MobeelizerOperationError deleteUser(final String login) {
        return executePostAndGetContent("/client/user/delete", "login", login).getError();
    }

    @Override
    public MobeelizerOperationStatus<String> sendSyncAllRequest() {
        return executePostAndGetContent("/synchronizeAll");
    }

    @Override
    public MobeelizerOperationStatus<String> sendSyncDiffRequest(final File outputFile) {
        return executePostAndGetContent("/synchronize", "file", outputFile);
    }

    @Override
    public MobeelizerOperationError waitUntilSyncRequestComplete(final String ticket) {
        try {
            for (int i = 0; i < 240; i++) {
                MobeelizerOperationStatus<String> checkStatusResult = executeGetAndGetContent("/checkStatus",
                        new String[] { "ticket", ticket });
                if (checkStatusResult.getError() != null) {
                    return checkStatusResult.getError();
                }

                JSONObject json = new JSONObject(checkStatusResult.getContent());

                String status = json.getString("status");

                delegate.logInfo("Check task status: " + status);

                if ("REJECTED".toString().equals(status)) {

                    String message = "Check task status success: " + status + " with result "
                            + json.getString("result") + " and message '" + json.getString("message") + "'";
                    delegate.logInfo(message);
                    return MobeelizerOperationErrorImpl.syncRejected(json.getString("result"),
                            json.getString("message"));
                } else if ("FINISHED".toString().equals(status)) {
                    return null;
                }

                try {
                    Thread.sleep(100 * i + 500);
                } catch (InterruptedException e) {
                    return MobeelizerOperationErrorImpl.other(e.getMessage());
                }
            }
        } catch (JSONException e) {
            return MobeelizerOperationErrorImpl.exception(new IOException(e.getMessage()));
        }
        return null;
    }

    @Override
    public File getSyncData(final String ticket) throws IOException {
        return executeGetForFile("/data", "ticket", ticket);
    }

    @Override
    public File getConflictHistory(String model, String guid) throws IOException {
        return executeGetForFile("/conflictHistory", "model", model, "guid", guid);
    }

    @Override
    public MobeelizerOperationError confirmTask(final String ticket) {
        return executePostAndGetContent("/confirm", "ticket", ticket).getError();
    }

    @Override
    public MobeelizerOperationError registerForRemoteNotifications(final String token) {
        delegate.logInfo("Try to register for remote notifications with token: " + token);
        return executePostAndGetContent("/registerPushToken", "deviceToken", token, "deviceType", "android")
                .getError();
    }

    @Override
    public MobeelizerOperationError unregisterForRemoteNotifications(final String token) {
        delegate.logInfo("Try to unregister for remote notifications with token: " + token);
        return executePostAndGetContent("/unregisterPushToken", "deviceToken", token, "deviceType", "android")
                .getError();
    }

    @Override
    public MobeelizerOperationError sendRemoteNotification(final String device, final String group,
            final List<String> users, final Map<String, String> notification) {
        try {
            JSONObject object = new JSONObject();
            StringBuilder logBuilder = new StringBuilder();
            logBuilder.append("try to send remote notification ").append(notification).append(" to");
            if (device != null) {
                object.put("device", device);
                logBuilder.append(" device: ").append(device);
            }
            if (group != null) {
                object.put("group", group);
                logBuilder.append(" group: ").append(group);
            }
            if (users != null) {
                object.put("users", new JSONArray(users));
                logBuilder.append(" users: ").append(users);
            }
            if (device == null && group == null && users == null) {
                logBuilder.append(" everyone");
            }
            object.put("notification", new JSONObject(notification));
            delegate.logInfo(logBuilder.toString());
            return executePostAndGetContent("/push", object).getError();
        } catch (JSONException e) {
            return MobeelizerOperationErrorImpl.other(e.getMessage());
        }
    }

    private MobeelizerUser jsonObjectToUser(final JSONObject json) throws JSONException {
        MobeelizerUser user = new MobeelizerUser();
        user.setLogin(json.getString("login"));
        user.setGroup(json.getString("group"));
        user.setMail(json.getString("mail"));
        user.setAdmin("true".equals(json.getString("admin")));
        return user;
    }

    private JSONObject userToJsonObject(final MobeelizerUser user) throws JSONException {
        JSONObject json = new JSONObject();
        json.put("login", user.getLogin());
        json.put("group", user.getGroup());
        json.put("password", user.getPassword());
        json.put("mail", user.getMail());
        json.put("admin", user.isAdmin() ? "true" : "false");
        return json;
    }

    private MobeelizerOperationStatus<String> executeGetAndGetContent(final String path, final String... params) {
        HttpGet request = new HttpGet(getUrl(path, params));
        setHeaders(request, true, true);
        return executeAndGetContent(request);
    }

    private MobeelizerOperationStatus<String> executePostAndGetContent(final String path, final String... params) {
        HttpPost request = new HttpPost(getUrl(path, params));
        setHeaders(request, true, true);
        return executeAndGetContent(request);
    }

    private File executeGetForFile(final String path, final String... params) throws IOException {
        HttpGet request = new HttpGet(getUrl(path, params));
        setHeaders(request, true, true);
        return executeAndGetFile(request);
    }

    private MobeelizerOperationStatus<String> executePostAndGetContent(final String path, final JSONObject body) {
        HttpPost request = new HttpPost(getUrl(path, new String[0]));
        try {
            request.setEntity(new StringEntity(body.toString(), "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            return new MobeelizerOperationStatus<String>(MobeelizerOperationErrorImpl.exception(e));
        }

        setHeaders(request, true, true);

        return executeAndGetContent(request);
    }

    private MobeelizerOperationStatus<String> executePostAndGetContent(final String path, final String name,
            final File file) {
        HttpPost request = new HttpPost(getUrl(path, new String[0]));

        String boundary = "---------------------------14737809831466499882746641449";

        request.setHeader("content-type", "multipart/form-data; boundary=" + boundary);

        String boundaryBegin = "\r\n--" + boundary + "\r\n";
        String boundaryEnd = "\r\n--" + boundary + "--\r\n";
        String contentDisposition = "content-disposition: form-data; name=\"file\"; filename=\"file\"\r\n";
        String contentType = "content-type: application/octet-stream\r\n\r\n";

        ByteArrayOutputStream out = new ByteArrayOutputStream();

        try {
            out.write(boundaryBegin.getBytes("UTF-8"), 0, boundaryBegin.length());
            out.write(contentDisposition.getBytes("UTF-8"), 0, contentDisposition.length());
            out.write(contentType.getBytes("UTF-8"), 0, contentType.length());
        } catch (UnsupportedEncodingException e) {
            throw new IllegalStateException(e.getMessage(), e);
        }

        byte[] buffer = new byte[1024];
        int bytesRead = 0;

        BufferedInputStream in = null;

        try {
            in = new BufferedInputStream(new FileInputStream(file));
            while ((bytesRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
            }
        } catch (FileNotFoundException e) {
            throw new IllegalStateException(e.getMessage(), e);
        } catch (IOException e) {
            throw new IllegalStateException(e.getMessage(), e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                // ignore
            }
        }

        try {
            out.write(boundaryEnd.getBytes("UTF-8"), 0, boundaryEnd.length());
        } catch (UnsupportedEncodingException e) {
            throw new IllegalStateException(e.getMessage(), e);
        }

        ByteArrayEntity entity = new ByteArrayEntity(out.toByteArray());

        request.setEntity(entity);

        setHeaders(request, false, true);

        return executeAndGetContent(request);
    }

    private void setHeaders(final HttpRequestBase request, final boolean setJsonContentType,
            final boolean setUserPassword) {
        if (setJsonContentType) {
            request.setHeader("content-type", "application/json");
        }
        request.setHeader("mas-vendor-name", delegate.getVendor());
        request.setHeader("mas-application-name", delegate.getApplication());
        request.setHeader("mas-application-instance-name", delegate.getInstance());
        request.setHeader("mas-definition-digest", delegate.getVersionDigest());
        request.setHeader("mas-device-name", delegate.getDevice());
        request.setHeader("mas-device-identifier", delegate.getDeviceIdentifier());
        if (setUserPassword) {
            request.setHeader("mas-user-name", delegate.getUser());
            request.setHeader("mas-user-password", delegate.getPassword());
        }
        request.setHeader("mas-sdk-version", delegate.getSdkVersion());
    }

    private String getUrl(final String path, final String... params) {
        return getUrl() + path + createQuery(params);
    }

    private String getUrl() {
        if (delegate.getUrl() != null) {
            return delegate.getUrl();
        } else if (delegate.getMode().equals(MobeelizerMode.PRODUCTION)) {
            return DEFAULT_PRODUCTION_URL;
        } else {
            return DEFAULT_TEST_URL;
        }
    }

    private String createQuery(final String[] params) {
        if (params.length > 0) {
            List<NameValuePair> qparams = new ArrayList<NameValuePair>();
            for (int i = 0; i < params.length; i += 2) {
                qparams.add(new BasicNameValuePair(params[i], params[i + 1]));
            }
            return "?" + URLEncodedUtils.format(qparams, "UTF-8");
        } else {
            return "";
        }
    }

    private HttpClient httpClient() {
        HttpParams params = new BasicHttpParams();
        HttpConnectionParams.setConnectionTimeout(params, 60000);
        HttpConnectionParams.setSoTimeout(params, 60000);
        return new DefaultHttpClient(params);
    }

    private MobeelizerOperationStatus<String> executeAndGetContent(final HttpRequestBase request) {
        HttpClient client = httpClient();

        InputStream is = null;
        Reader reader = null;

        if (!delegate.isNetworkAvailable()) {
            return new MobeelizerOperationStatus<String>(MobeelizerOperationErrorImpl.missingConnectionError());
        }

        delegate.setProxyIfNecessary(request);

        MobeelizerOperationError error = null;

        try {
            HttpResponse response = client.execute(request);

            int status = response.getStatusLine().getStatusCode();

            HttpEntity entity = response.getEntity();
            if (entity == null) {
                return new MobeelizerOperationStatus<String>(MobeelizerOperationErrorImpl.connectionError());
            }
            is = entity.getContent();
            Writer writer = new StringWriter();
            char[] buffer = new char[1024];
            reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
            int n;
            while ((n = reader.read(buffer)) != -1) {
                writer.write(buffer, 0, n);
            }
            String content = writer.toString().trim();

            if (status == HttpStatus.SC_OK) {
                return new MobeelizerOperationStatus<String>(content);
            } else if (status == HttpStatus.SC_INTERNAL_SERVER_ERROR && content.trim().length() > 0) {
                JSONObject json = new JSONObject(content);
                error = MobeelizerOperationErrorImpl.serverError(json);
            } else {
                error = MobeelizerOperationErrorImpl.connectionError(status);
            }

        } catch (JSONException e) {
            error = MobeelizerOperationErrorImpl.exception(e);
        } catch (IOException e) {
            error = MobeelizerOperationErrorImpl.exception(e);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    delegate.logDebug(e.getMessage());
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    delegate.logDebug(e.getMessage());
                }
            }
            client.getConnectionManager().shutdown();
        }
        return new MobeelizerOperationStatus<String>(error);
    }

    private File executeAndGetFile(final HttpRequestBase request) throws IOException {
        HttpClient client = httpClient();

        BufferedInputStream in = null;
        BufferedOutputStream out = null;

        if (!delegate.isNetworkAvailable()) {
            throw new IOException("Cannot execute HTTP request, network connection not available");
        }

        delegate.setProxyIfNecessary(request);

        try {
            HttpResponse response = client.execute(request);

            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                HttpEntity entity = response.getEntity();

                if (entity == null) {
                    throw new IOException("Connection failure: entity not found.");
                }

                in = new BufferedInputStream(entity.getContent());

                File file = File.createTempFile("mobeelizer", "response");

                out = new BufferedOutputStream(new FileOutputStream(file));

                byte[] buffer = new byte[4096];
                int n = -1;

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

                return file;
            } else {
                throw new IOException("Connection failure: " + response.getStatusLine().getStatusCode() + ".");
            }
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    delegate.logDebug(e.getMessage());
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    delegate.logDebug(e.getMessage());
                }
            }
            client.getConnectionManager().shutdown();
        }
    }

}