im.delight.faceless.Server.java Source code

Java tutorial

Introduction

Here is the source code for im.delight.faceless.Server.java

Source

package im.delight.faceless;

/**
 * Copyright (C) 2014 www.delight.im <info@delight.im>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see {http://www.gnu.org/licenses/}.
 */

import im.delight.android.baselib.Collections;
import im.delight.android.baselib.Data;
import im.delight.android.languages.CustomLanguage;
import im.delight.android.webrequest.WebRequest;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.UUID;
import org.json.JSONArray;
import org.json.JSONObject;
import android.content.Context;
import android.graphics.Color;
import android.preference.PreferenceManager;

public class Server {

    public static final int MODE_FRIENDS = 1;
    public static final int MODE_POPULAR = 2;
    public static final int MODE_LATEST = 3;
    public static final int MODE_FAVORITES = 4;
    public static final int MODE_SUBSCRIPTIONS = 5;
    public static final int STATUS_OK = 1;
    public static final int STATUS_MAINTENANCE = 2;
    public static final int STATUS_BAD_REQUEST = 3;
    public static final int STATUS_OUTDATED_CLIENT = 4;
    public static final int STATUS_NOT_AUTHORIZED = 5;
    public static final int STATUS_TEMPORARILY_BANNED = 6;
    public static final int STATUS_LOGIN_THROTTLED = 7;
    public static final int STATUS_NO_CONNECTION = 8;
    protected static final int MESSAGES_PER_REQUEST = 50;

    public static class Callback {

        // instances of this class are not allowed
        private Callback() {
        }

        public interface MessageEvent {
            public void onReceivedMessages(int status, int mode, int page, boolean reachedEnd,
                    final long latestMessageID, final int subscriptionUpdates, List<Message> messages);

            public void onReceivedDetails(int status, boolean isFavorited, boolean isSubscribed);

            public void onSentMessage(int status, String messageText, String messageTopic, String messageID,
                    long messageTime, String messageColorHex, int messagePatternID, String messageCountryISO3);
        }

        public interface CommentEvent {
            public void onReceivedComments(int status, List<Comment> comments, boolean hasPrivateComments);

            public void onSentComment(int status, String commentText, String commentID, int ownerInThread,
                    int privateRecipientInThread, long commentTime);
        }

        public interface FavoriteEvent {
            public void onChangedFavorite(int status, boolean favorited);
        }

        public interface SubscriptionEvent {
            public void onChangedSubscription(int status, boolean subscribed);

            public void onClearedSubscriptions(int status);
        }

        public interface ConnectionEvent {
            public void onAddedFriend(int status);

            public void onAddedBlock(int status);
        }

        public interface ReportEvent {
            public void onSentReport(int status);
        }

        public interface VerificationEvent {
            public void onLoadVerification();

            public void onPreparedVerification(int status, String apiPhoneNumber, String verificationCode,
                    long validUntil);
        }

    }

    public static class GetMessagesResponse {
        public boolean reachedEnd;
        public long latestMessageID;
        public List<Message> messages;
        public int subscriptionUpdates;
    }

    public static GetMessagesResponse getMessagesSync(final Context context, final int mode, final int page,
            final Set<String> topicsList) {
        WebRequest request = getMessagesRequest(context, mode, page, topicsList);
        final String responseText = request.executeSync();
        final int status = parseStatus(responseText);

        if (status == STATUS_OK) {
            GetMessagesResponse response = parseMessages(context, mode, page, responseText);
            return response;
        } else {
            return null;
        }
    }

    public static void getMessagesAsync(final Context context, final int mode, final int page,
            final Set<String> topicsList, final Callback.MessageEvent callback) {
        WebRequest request = getMessagesRequest(context, mode, page, topicsList);
        request.executeAsync(new WebRequest.Callback() {
            @Override
            public void onSuccess(String responseText) {
                final int status = parseStatus(responseText);
                if (status == STATUS_OK) {
                    GetMessagesResponse response = parseMessages(context, mode, page, responseText);
                    if (callback != null) {
                        callback.onReceivedMessages(status, mode, page, response.reachedEnd,
                                response.latestMessageID, response.subscriptionUpdates, response.messages);
                    }
                } else {
                    if (callback != null) {
                        callback.onReceivedMessages(status, mode, page, true, 0, -1, null);
                    }
                }
            }

            @Override
            public void onError() {
                if (callback != null) {
                    callback.onReceivedMessages(STATUS_NO_CONNECTION, mode, page, true, 0, -1, null);
                }
            }
        });
    }

    public static void getMessageDetails(final Context context, final String messageID,
            final Callback.MessageEvent callback) {
        WebRequest request = new APIRequest(context).get().to("/messages/details");
        request.auth(Global.Setup.getUsername(), Global.Setup.getPassword());
        request.addParam("messageID", messageID);
        request.executeAsync(new WebRequest.Callback() {
            @Override
            public void onSuccess(String responseText) {
                final int status = parseStatus(responseText);
                if (status == STATUS_OK) {
                    try {
                        final JSONObject responseData = new JSONObject(responseText);
                        final boolean isFavorited = responseData.getBoolean("isFavorited");
                        final boolean isSubscribed = responseData.getBoolean("isSubscribed");
                        if (callback != null) {
                            callback.onReceivedDetails(status, isFavorited, isSubscribed);
                        }
                    } catch (Exception e) {
                        if (callback != null) {
                            callback.onReceivedDetails(status, false, false);
                        }
                    }
                } else {
                    if (callback != null) {
                        callback.onReceivedDetails(status, false, false);
                    }
                }
            }

            @Override
            public void onError() {
                if (callback != null) {
                    callback.onReceivedDetails(STATUS_NO_CONNECTION, false, false);
                }
            }
        });
    }

    public static void saveMessage(final Context context, final String colorHex, final int patternID,
            final String text, final String topic, final Callback.MessageEvent callback) {
        WebRequest request = new APIRequest(context).post().to("/messages/new");
        request.auth(Global.Setup.getUsername(), Global.Setup.getPassword());
        request.addParam("colorHex", colorHex);
        request.addParam("patternID", patternID);
        request.addParam("text", text);
        request.addParam("topic", topic);
        try {
            request.addParam("languageISO3", Locale.getDefault().getISO3Language().toUpperCase(Locale.US));
        } catch (Exception e) {
        }
        String countryIso3 = null;
        try {
            // get the user's country from the preferences
            countryIso3 = PreferenceManager.getDefaultSharedPreferences(context)
                    .getString(ActivitySettings.PREF_COUNTRY, null);
            // if the country is not set in the preferences yet
            if (countryIso3 == null || countryIso3.length() != 3) {
                // use the Locale's country property as the default
                countryIso3 = Locale.getDefault().getISO3Country().toUpperCase(Locale.US);
                if (countryIso3 == null || countryIso3.length() != 3) {
                    Locale originalLocale = CustomLanguage.getOriginalLocale();
                    if (originalLocale != null) {
                        countryIso3 = originalLocale.getISO3Country().toUpperCase(Locale.US);
                    }
                }
            }
            request.addParam("countryISO3", countryIso3);
        } catch (Exception e) {
        }
        final String messageCountryIso3 = countryIso3;
        request.addParam("random", UUID.randomUUID().toString());
        request.executeAsync(new WebRequest.Callback() {
            @Override
            public void onSuccess(String responseText) {
                try {
                    final JSONObject responseData = new JSONObject(responseText);
                    final String messageID = responseData.getString("messageID");
                    final long messageTime = responseData.getInt("messageTime") * 1000L;
                    if (callback != null) {
                        callback.onSentMessage(parseStatus(responseText), text, topic, messageID, messageTime,
                                colorHex, patternID, messageCountryIso3);
                    }
                } catch (Exception e) {
                    if (callback != null) {
                        callback.onSentMessage(STATUS_BAD_REQUEST, null, null, null, 0, null, 0, null);
                    }
                }
            }

            @Override
            public void onError() {
                if (callback != null) {
                    callback.onSentMessage(STATUS_NO_CONNECTION, null, null, null, 0, null, 0, null);
                }
            }
        });
    }

    public static void getComments(final Context context, final String messageID,
            final Callback.CommentEvent callback) {
        WebRequest request = new APIRequest(context).get().to("/comments/list");
        request.auth(Global.Setup.getUsername(), Global.Setup.getPassword());
        request.addParam("messageID", messageID);
        request.executeAsync(new WebRequest.Callback() {
            @Override
            public void onSuccess(String responseText) {
                final int status = parseStatus(responseText);
                if (status == STATUS_OK) {
                    List<Comment> comments = new LinkedList<Comment>();
                    boolean hasPrivateComments = false;
                    try {
                        final JSONObject responseData = new JSONObject(responseText);
                        final JSONArray responseComments = responseData.getJSONArray("comments");
                        final int responseCommentCount = responseComments.length();
                        int privateRecipientInThread;
                        for (int i = 0; i < responseCommentCount; i++) {
                            JSONObject responseMessage = (JSONObject) responseComments.get(i);
                            privateRecipientInThread = responseMessage.isNull("privateRecipientInThread") ? 0
                                    : responseMessage.getInt("privateRecipientInThread");
                            if (privateRecipientInThread > 0) {
                                hasPrivateComments = true;
                            }
                            comments.add(new Comment(responseMessage.getString("id"),
                                    responseMessage.getString("text"), privateRecipientInThread,
                                    responseMessage.getBoolean("isOwner"), responseMessage.getBoolean("isSelf"),
                                    (responseMessage.isNull("ownerInThread") ? 0
                                            : responseMessage.getInt("ownerInThread")),
                                    responseMessage.getInt("time") * 1000L));
                        }
                    } catch (Exception e) {
                    }
                    if (callback != null) {
                        callback.onReceivedComments(status, comments, hasPrivateComments);
                    }
                } else {
                    if (callback != null) {
                        callback.onReceivedComments(status, null, false);
                    }
                }
            }

            @Override
            public void onError() {
                if (callback != null) {
                    callback.onReceivedComments(STATUS_NO_CONNECTION, null, false);
                }
            }
        });
    }

    public static void addComment(final Context context, final String messageID,
            final String privateReplyToCommentID, final String text, final Callback.CommentEvent callback) {
        WebRequest request = new APIRequest(context).post().to("/comments/new");
        request.auth(Global.Setup.getUsername(), Global.Setup.getPassword());
        request.addParam("messageID", messageID);
        if (privateReplyToCommentID != null) {
            request.addParam("privateReplyToComment", privateReplyToCommentID);
        }
        request.addParam("text", text);
        request.addParam("random", UUID.randomUUID().toString());
        request.executeAsync(new WebRequest.Callback() {
            @Override
            public void onSuccess(String responseText) {
                try {
                    final JSONObject responseData = new JSONObject(responseText);
                    if (callback != null) {
                        callback.onSentComment(parseStatus(responseText), text, responseData.getString("commentID"),
                                (responseData.isNull("ownerInThread") ? 0 : responseData.getInt("ownerInThread")),
                                (responseData.isNull("privateRecipientInThread") ? 0
                                        : responseData.getInt("privateRecipientInThread")),
                                (responseData.getInt("commentTime") * 1000L));
                    }
                } catch (Exception e) {
                    if (callback != null) {
                        callback.onSentComment(STATUS_BAD_REQUEST, null, null, 0, 0, 0);
                    }
                }
            }

            @Override
            public void onError() {
                if (callback != null) {
                    callback.onSentComment(STATUS_NO_CONNECTION, null, null, 0, 0, 0);
                }
            }
        });
    }

    public static void setFavorited(final Context context, final String messageID, final boolean favorited,
            final Callback.FavoriteEvent callback) {
        WebRequest request = new APIRequest(context).post().to("/favorites/set");
        request.auth(Global.Setup.getUsername(), Global.Setup.getPassword());
        request.addParam("messageID", messageID);
        request.addParam("favorited", favorited ? 1 : 0);
        request.executeAsync(new WebRequest.Callback() {
            @Override
            public void onSuccess(String responseText) {
                if (callback != null) {
                    callback.onChangedFavorite(parseStatus(responseText), favorited);
                }
            }

            @Override
            public void onError() {
                if (callback != null) {
                    callback.onChangedFavorite(STATUS_NO_CONNECTION, false);
                }
            }
        });
    }

    public static void setSubscribed(final Context context, final String messageID, final boolean subscribed,
            final Callback.SubscriptionEvent callback) {
        WebRequest request = new APIRequest(context).post().to("/subscriptions/set");
        request.auth(Global.Setup.getUsername(), Global.Setup.getPassword());
        request.addParam("messageID", messageID);
        request.addParam("subscribed", subscribed ? 1 : 0);
        request.executeAsync(new WebRequest.Callback() {
            @Override
            public void onSuccess(String responseText) {
                if (callback != null) {
                    callback.onChangedSubscription(parseStatus(responseText), subscribed);
                }
            }

            @Override
            public void onError() {
                if (callback != null) {
                    callback.onChangedSubscription(STATUS_NO_CONNECTION, false);
                }
            }
        });
    }

    public static void clearSubscriptions(final Context context, final Callback.SubscriptionEvent callback) {
        WebRequest request = new APIRequest(context).post().to("/subscriptions/clear");
        request.auth(Global.Setup.getUsername(), Global.Setup.getPassword());
        request.executeAsync(new WebRequest.Callback() {
            @Override
            public void onSuccess(String responseText) {
                if (callback != null) {
                    callback.onClearedSubscriptions(parseStatus(responseText));
                }
            }

            @Override
            public void onError() {
                if (callback != null) {
                    callback.onClearedSubscriptions(STATUS_NO_CONNECTION);
                }
            }
        });
    }

    public static void setFriends(final Context context, final String usernamesCSV,
            final Callback.ConnectionEvent callback) {
        WebRequest request = new APIRequest(context).post().to("/connections/friend");
        request.auth(Global.Setup.getUsername(), Global.Setup.getPassword());
        request.addParam("userList", usernamesCSV);
        request.executeAsync(new WebRequest.Callback() {
            @Override
            public void onSuccess(String responseText) {
                if (callback != null) {
                    callback.onAddedFriend(parseStatus(responseText));
                }
            }

            @Override
            public void onError() {
                if (callback != null) {
                    callback.onAddedFriend(STATUS_NO_CONNECTION);
                }
            }
        });
    }

    public static int getFriendsCountSync(final Context context) {
        WebRequest request = new APIRequest(context).get().to("/connections/friend/count");
        request.auth(Global.Setup.getUsername(), Global.Setup.getPassword());
        final String responseText = request.executeSync();

        final int status = parseStatus(responseText);
        if (status == STATUS_OK) {
            try {
                final JSONObject responseData = new JSONObject(responseText);
                return responseData.getInt("friends");
            } catch (Exception e) {
                return -1;
            }
        } else {
            return -1;
        }
    }

    public static void setBlocked(final Context context, final String contentType, final String contentID,
            final Callback.ConnectionEvent callback) {
        WebRequest request = new APIRequest(context).post().to("/connections/block");
        request.auth(Global.Setup.getUsername(), Global.Setup.getPassword());
        request.addParam("contentType", contentType);
        request.addParam("contentID", contentID);
        request.executeAsync(new WebRequest.Callback() {
            @Override
            public void onSuccess(String responseText) {
                if (callback != null) {
                    callback.onAddedBlock(parseStatus(responseText));
                }
            }

            @Override
            public void onError() {
                if (callback != null) {
                    callback.onAddedBlock(STATUS_NO_CONNECTION);
                }
            }
        });
    }

    public static void sendReport(final Context context, final String contentType, final String contentID,
            final int reason, final Callback.ReportEvent callback) {
        WebRequest request = new APIRequest(context).post().to("/reports/new");
        request.auth(Global.Setup.getUsername(), Global.Setup.getPassword());
        request.addParam("contentType", contentType);
        request.addParam("contentID", contentID);
        request.addParam("reason", reason);
        request.executeAsync(new WebRequest.Callback() {
            @Override
            public void onSuccess(String responseText) {
                if (callback != null) {
                    callback.onSentReport(parseStatus(responseText));
                }
            }

            @Override
            public void onError() {
                if (callback != null) {
                    callback.onSentReport(STATUS_NO_CONNECTION);
                }
            }
        });
    }

    public static void prepareVerification(final Context context, final Callback.VerificationEvent callback) {
        WebRequest request = new APIRequest(context).post().to("/verifications/prepare");
        request.auth(Global.Setup.getUsername(), Global.Setup.getPassword());
        request.executeAsync(new WebRequest.Callback() {
            @Override
            public void onSuccess(String responseText) {
                final int status = parseStatus(responseText);
                if (status == STATUS_OK) {
                    String apiPhoneNumber = null;
                    String verificationCode = null;
                    long validUntil = 0;
                    try {
                        final JSONObject responseData = new JSONObject(responseText);
                        apiPhoneNumber = responseData.getString("apiPhoneNumber");
                        verificationCode = responseData.getString("verificationCode");
                        validUntil = responseData.getLong("validUntil");
                    } catch (Exception e) {
                    }
                    if (callback != null) {
                        callback.onPreparedVerification(status, apiPhoneNumber, verificationCode, validUntil);
                    }
                } else {
                    if (callback != null) {
                        callback.onPreparedVerification(status, null, null, 0);
                    }
                }
            }

            @Override
            public void onError() {
                if (callback != null) {
                    callback.onPreparedVerification(STATUS_NO_CONNECTION, null, null, 0);
                }
            }
        });
    }

    protected static WebRequest getMessagesRequest(final Context context, final int mode, final int page,
            final Set<String> topicsList) {
        // add meta category to list of topics as this should be visible to all users
        topicsList.add("meta");

        WebRequest request = new APIRequest(context).get().to("/messages/list");
        request.auth(Global.Setup.getUsername(), Global.Setup.getPassword());
        if (mode == MODE_FRIENDS) {
            request.addParam("mode", "friends");
        } else if (mode == MODE_POPULAR) {
            request.addParam("mode", "popular");
        } else if (mode == MODE_LATEST) {
            request.addParam("mode", "latest");
        } else if (mode == MODE_FAVORITES) {
            request.addParam("mode", "favorites");
        } else if (mode == MODE_SUBSCRIPTIONS) {
            request.addParam("mode", "subscriptions");
        } else {
            throw new RuntimeException("Unknown mode: " + mode);
        }
        request.addParam("page", page);
        request.addParam("topicsList", Collections.implode(topicsList, ","));
        try {
            request.addParam("languageISO3", Locale.getDefault().getISO3Language().toUpperCase(Locale.US));
        } catch (Exception e) {
        }
        return request;
    }

    protected static GetMessagesResponse parseMessages(final Context context, final int mode, final int page,
            final String responseText) {
        List<Message> messages = new LinkedList<Message>();
        long oldestMessageTime = System.currentTimeMillis();
        long latestMessageID = 0;
        int subscriptionUpdates = -1;
        if (!Config.DEMO_ACTIVE) {
            try {
                final JSONObject responseData = new JSONObject(responseText);
                final JSONArray responseMessages = responseData.getJSONArray("messages");
                final int responseMessageCount = responseMessages.length();

                long responseMessageTime;
                for (int i = 0; i < responseMessageCount; i++) {
                    JSONObject responseMessage = (JSONObject) responseMessages.get(i);
                    responseMessageTime = responseMessage.getInt("time") * 1000L;
                    if (responseMessageTime < oldestMessageTime) {
                        oldestMessageTime = responseMessageTime;
                    }
                    try {
                        latestMessageID = Math.max(latestMessageID,
                                Message.getIDNumber(responseMessage.getString("id")));
                    } catch (Exception e) {
                    }
                    messages.add(new Message(responseMessage.getString("id"), responseMessage.getInt("degree"),
                            responseMessage.getString("colorHex"), responseMessage.getInt("patternID"),
                            responseMessage.getString("text"), responseMessage.getString("topic"),
                            responseMessageTime, responseMessage.getInt("favoritesCount"),
                            responseMessage.getInt("commentsCount"), responseMessage.getString("countryISO3")));
                }

                subscriptionUpdates = responseData.getInt("subscriptionUpdates");
            } catch (Exception e) {
                GetMessagesResponse out = new GetMessagesResponse();
                out.reachedEnd = true;
                out.latestMessageID = latestMessageID;
                out.messages = messages;
                out.subscriptionUpdates = subscriptionUpdates;
                return out;
            }
        } else {
            // pretend to have some subscription updates for demo purposes
            subscriptionUpdates = 7;
        }
        // count messages that have been returned from the server
        final int messageCount = messages.size();
        // if users have not enough messages in their feed yet
        if (messageCount < MESSAGES_PER_REQUEST && page == 0 && mode != MODE_SUBSCRIPTIONS
                && mode != MODE_FAVORITES) {
            // get some example messages
            List<Message> exampleMessages = getExampleMessages(context, (MESSAGES_PER_REQUEST - messageCount),
                    oldestMessageTime);
            // add the examples to the response
            messages.addAll(exampleMessages);
        }

        GetMessagesResponse out = new GetMessagesResponse();
        out.reachedEnd = messageCount < MESSAGES_PER_REQUEST;
        out.latestMessageID = latestMessageID;
        out.messages = messages;
        out.subscriptionUpdates = subscriptionUpdates;

        return out;
    }

    protected static List<Message> getExampleMessages(Context context, int number, long startTime) {
        final List<Message> out = new LinkedList<Message>();
        final String[] exampleMessages = context.getResources().getStringArray(R.array.example_messages);
        number = Math.min(number, exampleMessages.length);

        int degree;
        int color;
        String colorHex;
        long messageTime;
        int comments;
        for (int i = 0; i < number; i++) {
            // create arbitrary but constant (on subsequent requests) colors
            color = getExampleColor(i);
            // turn color into hex value
            colorHex = Data.colorToHex(color);
            // create arbitrary but constant (on subsequent requests) message timestamps
            messageTime = startTime - ((i + 1) * 3600L * 12L * 1000L);
            if (Config.DEMO_ACTIVE) {
                degree = (i + 1) % 4;
            } else {
                degree = -1;
            }
            comments = 12 - (i * 3);
            if (comments < 0) {
                comments = 0;
            }
            out.add(new Message(null, degree, colorHex, i, exampleMessages[i], "life", messageTime, 4, comments,
                    null));
        }

        return out;
    }

    protected static int getExampleColor(int n) {
        // don't start with a color that is too dark (value produces nice colors and has been retrieved experimentally)
        n = n + 9;
        // use RGB values between 42 and 214 to prevent black and white
        // use different slopes for R/G/B to prevent grayscale colors
        return Color.rgb((42 + ((n * 45) % 172)), (42 + ((n * 75) % 172)), (42 + ((n * 105) % 172)));
    }

    protected static int parseStatus(String responseText) {
        try {
            JSONObject json = new JSONObject(responseText);
            final String status = json.getString("status");
            if (status.equals("ok")) {
                return STATUS_OK;
            } else if (status.equals("maintenance")) {
                return STATUS_MAINTENANCE;
            } else if (status.equals("bad_request")) {
                return STATUS_BAD_REQUEST;
            } else if (status.equals("outdated_client")) {
                return STATUS_OUTDATED_CLIENT;
            } else if (status.equals("not_authorized")) {
                return STATUS_NOT_AUTHORIZED;
            } else if (status.equals("temporarily_banned")) {
                return STATUS_TEMPORARILY_BANNED;
            } else if (status.equals("login_throttled")) {
                return STATUS_LOGIN_THROTTLED;
            }
        } catch (Exception e) {
        }
        return STATUS_NO_CONNECTION;
    }

}