ca.zadrox.dota2esportticker.service.UpdateTeamsService.java Source code

Java tutorial

Introduction

Here is the source code for ca.zadrox.dota2esportticker.service.UpdateTeamsService.java

Source

/*
 * Copyright 2014 Nicholas Liu
 *
 * 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.
 */

package ca.zadrox.dota2esportticker.service;

import android.app.IntentService;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.v4.content.LocalBroadcastManager;

import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.IOException;
import java.util.HashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import ca.zadrox.dota2esportticker.data.MatchContract;
import ca.zadrox.dota2esportticker.util.PrefUtils;
import ca.zadrox.dota2esportticker.util.TeamGetter;
import ca.zadrox.dota2esportticker.util.TimeUtils;

import static ca.zadrox.dota2esportticker.util.LogUtils.LOGD;

/**
 * Created by Acco on 11/25/2014.
 */
public class UpdateTeamsService extends IntentService {
    private static final String TAG = UpdateTeamsService.class.getSimpleName();

    public UpdateTeamsService() {
        super(TAG);
    }

    public static final String ACTION_UPDATE_TOP_TEAMS = "ca.zadrox.dota2esportticker.action.ACTION_UPDATE_TOP_TEAMS";

    public static final String ACTION_UPDATE_SEARCHED_TEAMS = "ca.zadrox.dota2esportticker.action.ACTION_UPDATE_SEARCHED_TEAMS";

    public static final String STATUS_UPDATING = "ca.zadrox.dota2esportticker.action.STATUS_UPDATING";

    public static final String STATUS_COMPLETED = "ca.zadrox.dota2esportticker.action.STATUS_UPDATE_COMPLETE";

    public static final String STATUS_NO_CONNECTIVITY = "ca.zadrox.dota2esportticker.action.STATUS_NO_CONNECTIVITY";

    public static final String STATUS_ERROR = "ca.zadrox.dota2esportticker.action.STATUS_ERROR";

    public static final String EXTRA_SEARCH_NAME = "ca.zadrox.dota2esportticker.extra.EXTRA_SEARCH_NAME";

    @Override
    protected void onHandleIntent(Intent intent) {
        final String action = intent.getAction();

        if (ACTION_UPDATE_TOP_TEAMS.equals(action)) {
            updateTopTeams();
        }

        final String searchName = intent.getStringExtra(EXTRA_SEARCH_NAME);

        if (searchName == null) {
            return;
        }

        if (ACTION_UPDATE_SEARCHED_TEAMS.equals(action)) {
            updateSearchedTeams(searchName);
        }
    }

    private void updateTopTeams() {

        LOGD(TAG, "starting update");

        // actually, first, check for connectivity:
        if (!checkForConnectivity()) {
            LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(STATUS_NO_CONNECTIVITY));
            LOGD(TAG, "returning due to no connectivity");
            return;
        }

        // first, check last update time
        long lastUpdate = PrefUtils.lastTeamsUpdate(this);
        long currentTime = TimeUtils.getUTCTime();

        // if last update is less than 1 hour old, boot user to cursorloader op.
        if (currentTime - lastUpdate < 60000 * 60) {
            LOGD(TAG, "returnning due to too soon");
            LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(STATUS_COMPLETED));
            return;
        }

        // else
        // use local broadcast manager to show loading indicator
        LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(STATUS_UPDATING));

        final String BASE_URL = "http://www.gosugamers.net/dota2/rankings";
        final String TEAM_LINK_BASE_URL = "http://www.gosugamers.net/dota2/teams/";

        // we see what teams are in top 50. (httpreq -> gosugamers)
        try {

            String rawHtml = new OkHttpClient().newCall(new Request.Builder().url(BASE_URL).build()).execute()
                    .body().string();

            String processedHtml = rawHtml.substring(rawHtml.indexOf("<div id=\"col1\" class=\"rows\">"),
                    rawHtml.indexOf("<div id=\"col2\" class=\"rows\">"));

            Elements teamRows = Jsoup.parse(processedHtml).getElementsByClass("ranking-link");

            ExecutorService executorService = Executors.newFixedThreadPool(10);
            ContentValues[] teamRanks = new ContentValues[50];

            HashMap<ContentValues, Future<String>> newTeamInfo = new HashMap<ContentValues, Future<String>>();
            HashMap<ContentValues, Future<String>> updateTeamInfo = new HashMap<ContentValues, Future<String>>();

            int i = 0;

            for (Element teamRow : teamRows) {
                ContentValues contentValues = new ContentValues();

                String teamId = teamRow.attr("data-id");
                contentValues.put(MatchContract.TeamEntry._ID, teamId);

                String untrimmedTeamName = teamRow.getElementsByTag("h4").first().text();
                String teamUrl = TEAM_LINK_BASE_URL + teamId + "-"
                        + untrimmedTeamName.replaceAll("[\\W]?[\\W][\\W]*", "-").toLowerCase();
                contentValues.put(MatchContract.TeamEntry.COLUMN_TEAM_URL, teamUrl);

                String teamName = untrimmedTeamName.replaceAll(" ?\\.?\\-?-?Dot[aA][\\s]?2", "");
                contentValues.put(MatchContract.TeamEntry.COLUMN_TEAM_NAME, teamName);

                if (teamUrl.charAt(teamUrl.length() - 1) == '-') {
                    teamUrl = teamUrl.substring(0, teamUrl.length() - 2);
                }

                // then, we query db for id of the team (
                Cursor cursor = getContentResolver().query(
                        MatchContract.TeamEntry.buildTeamUri(Long.parseLong(teamId)), new String[] {
                                MatchContract.TeamEntry.COLUMN_TEAM_NAME, MatchContract.TeamEntry.COLUMN_TEAM_URL },
                        null, null, null);

                // -> if present, and data remains unchanged, continue.
                // -> if present, but data is changed, add to update queue.
                if (cursor.moveToFirst()) {
                    LOGD(TAG, "Have team already?");
                    if (!cursor.getString(0).contentEquals(teamName)
                            || !cursor.getString(1).contentEquals(teamUrl)) {
                        LOGD(TAG, "Team has updated values.");
                        updateTeamInfo.put(contentValues, executorService.submit(new TeamGetter(teamUrl)));
                    }
                }
                // -> if not present, add to update queue.
                else {
                    LOGD(TAG, "Do team update");
                    newTeamInfo.put(contentValues, executorService.submit(new TeamGetter(teamUrl)));
                }

                //                LOGD(TAG, "\n" +
                //                        "data-id: " + teamId + "\n" +
                //                        "team-name: " + teamName + "\n" +
                //                        "team-url: " + teamUrl);

                teamRanks[i] = new ContentValues();
                teamRanks[i].put(MatchContract.TeamRankEntry._ID, i + 1);
                teamRanks[i].put(MatchContract.TeamRankEntry.COLUMN_TEAM_ID, teamId);

                cursor.close();
                i++;
            }

            executorService.shutdown();
            executorService.awaitTermination(20, TimeUnit.SECONDS);

            for (ContentValues contentValues : newTeamInfo.keySet()) {
                try {
                    String teamLogo = newTeamInfo.get(contentValues).get();
                    contentValues.put(MatchContract.TeamEntry.COLUMN_TEAM_LOGO_URL, teamLogo);

                } catch (ExecutionException e) {
                    LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(STATUS_ERROR));
                    e.printStackTrace();
                }
            }

            for (ContentValues contentValues : updateTeamInfo.keySet()) {
                try {
                    String teamLogo = updateTeamInfo.get(contentValues).get();
                    contentValues.put(MatchContract.TeamEntry.COLUMN_TEAM_LOGO_URL, teamLogo);

                    String teamId = contentValues.getAsString(MatchContract.TeamEntry._ID);
                    contentValues.remove(MatchContract.TeamEntry._ID);

                    int updatedRows = getContentResolver().update(MatchContract.TeamEntry.CONTENT_URI,
                            contentValues,
                            MatchContract.TeamEntry.TABLE_NAME + "." + MatchContract.TeamEntry._ID + " = ?",
                            new String[] { teamId });

                    LOGD(TAG, "updatedRows: " + updatedRows);

                } catch (ExecutionException e) {
                    LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(STATUS_ERROR));
                    e.printStackTrace();
                }
            }

            getContentResolver().bulkInsert(MatchContract.TeamEntry.CONTENT_URI,
                    newTeamInfo.keySet().toArray(new ContentValues[newTeamInfo.size()]));
            getContentResolver().bulkInsert(MatchContract.TeamRankEntry.CONTENT_URI, teamRanks);

        } catch (IOException e) {
            LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(STATUS_ERROR));
            e.printStackTrace();
        } catch (InterruptedException e2) {
            LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(STATUS_ERROR));
            e2.printStackTrace();
        }

        //        String[] projection = new String[]{
        //                MatchContract.TeamEntry.TABLE_NAME + "." + MatchContract.TeamEntry._ID,
        //                MatchContract.TeamEntry.COLUMN_TEAM_NAME,
        //                MatchContract.TeamEntry.COLUMN_TEAM_URL,
        //                MatchContract.TeamEntry.COLUMN_TEAM_LOGO_URL,
        //                MatchContract.TeamEntry.COLUMN_TEAM_STARRED,
        //                MatchContract.TeamRankEntry.TABLE_NAME + "." + MatchContract.TeamRankEntry._ID
        //        };
        //
        //        String sortOrder =
        //                MatchContract.TeamRankEntry.TABLE_NAME + "." +
        //                        MatchContract.TeamRankEntry._ID + " ASC";
        //
        //        Cursor c = getContentResolver().query(
        //                MatchContract.TeamEntry.TOP_50_URI,
        //                projection,
        //                null,
        //                null,
        //                sortOrder
        //        );
        //
        //        while (c.moveToNext()) {
        //            String teamPrintOut =
        //                    "Rank: " + c.getInt(5) + "\n" +
        //                            "teamId: " + c.getInt(0) + " teamName: " + c.getString(1) + "\n" +
        //                            "teamUrl: " + c.getString(2) + "\n" +
        //                            "teamLogoUrl: " + c.getString(3) + "\n" +
        //                            "isFavourited: " + (c.getInt(4) == 0 ? "false" : "true");
        //            LOGD(TAG + "/UTT", teamPrintOut);
        //        }
        //
        //        c.close();

        // use local broadcast manager to hide loading indicator
        // and signal that cursorloader for top50 can happen.
        PrefUtils.setLastTeamUpdate(this, currentTime);
        LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(STATUS_COMPLETED));
    }

    private void updateSearchedTeams(String searchName) {

        LOGD(TAG, "starting search update");

        // actually, first, check for connectivity:
        if (!checkForConnectivity()) {
            LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(STATUS_NO_CONNECTIVITY));
            LOGD(TAG, "returning due to no connectivity");
            return;
        }

        LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(STATUS_UPDATING));

        final String BASE_URL = "http://www.gosugamers.net/dota2/rankings" + "?tname="
                + searchName.replace(' ', '+') + "&tunranked=0#team";
        final String TEAM_LINK_BASE_URL = "http://www.gosugamers.net/dota2/teams/";

        try {

            String rawHtml = new OkHttpClient().newCall(new Request.Builder().url(BASE_URL).build()).execute()
                    .body().string();

            String processedHtml = rawHtml.substring(rawHtml.indexOf("<div id=\"col1\" class=\"rows\">"),
                    rawHtml.indexOf("<div id=\"col2\" class=\"rows\">"));

            Elements teamRows = Jsoup.parse(processedHtml).getElementsByClass("ranking-link");

            ExecutorService executorService = Executors.newFixedThreadPool(10);

            HashMap<ContentValues, Future<String>> newTeamInfo = new HashMap<ContentValues, Future<String>>();
            HashMap<ContentValues, Future<String>> updateTeamInfo = new HashMap<ContentValues, Future<String>>();

            for (Element teamRow : teamRows) {
                ContentValues contentValues = new ContentValues();

                String teamId = teamRow.attr("data-id");
                contentValues.put(MatchContract.TeamEntry._ID, teamId);

                String untrimmedTeamName = teamRow.getElementsByTag("h4").first().text();
                String teamUrl = TEAM_LINK_BASE_URL + teamId + "-"
                        + untrimmedTeamName.replaceAll("[\\W]?[\\W][\\W]*", "-").toLowerCase();
                contentValues.put(MatchContract.TeamEntry.COLUMN_TEAM_URL, teamUrl);

                String teamName = untrimmedTeamName.replaceAll(" ?\\.?\\-?-?Dot[aA][\\s]?2", "");
                contentValues.put(MatchContract.TeamEntry.COLUMN_TEAM_NAME, teamName);

                if (teamUrl.charAt(teamUrl.length() - 1) == '-') {
                    teamUrl = teamUrl.substring(0, teamUrl.length() - 2);
                }

                // then, we query db for id of the team (
                Cursor cursor = getContentResolver().query(
                        MatchContract.TeamEntry.buildTeamUri(Long.parseLong(teamId)), new String[] {
                                MatchContract.TeamEntry.COLUMN_TEAM_NAME, MatchContract.TeamEntry.COLUMN_TEAM_URL },
                        null, null, null);

                // -> if present, and data remains unchanged, continue.
                // -> if present, but data is changed, add to update queue.
                if (cursor.moveToFirst()) {
                    LOGD(TAG, "Team in DB, determining if values need updating");
                    if (!cursor.getString(0).contentEquals(teamName)
                            || !cursor.getString(1).contentEquals(teamUrl)) {
                        LOGD(TAG, "Team has updated values, double checking logo & writing to DB");
                        updateTeamInfo.put(contentValues, executorService.submit(new TeamGetter(teamUrl)));
                    }
                }
                // -> if not present, add to update queue.
                else {
                    LOGD(TAG, "Team not in DB. Grabbing logo & writing to DB");
                    newTeamInfo.put(contentValues, executorService.submit(new TeamGetter(teamUrl)));
                }

                //                LOGD(TAG, "\n" +
                //                        "data-id: " + teamId + "\n" +
                //                        "team-name: " + teamName + "\n" +
                //                        "team-url: " + teamUrl);
                //
                cursor.close();
            }

            executorService.shutdown();
            executorService.awaitTermination(20, TimeUnit.SECONDS);

            for (ContentValues contentValues : newTeamInfo.keySet()) {
                try {
                    String teamLogo = newTeamInfo.get(contentValues).get();
                    contentValues.put(MatchContract.TeamEntry.COLUMN_TEAM_LOGO_URL, teamLogo);

                } catch (ExecutionException e) {
                    LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(STATUS_ERROR));
                    e.printStackTrace();
                }
            }

            for (ContentValues contentValues : updateTeamInfo.keySet()) {
                try {
                    String teamLogo = newTeamInfo.get(contentValues).get();
                    contentValues.put(MatchContract.TeamEntry.COLUMN_TEAM_LOGO_URL, teamLogo);

                    String teamId = contentValues.getAsString(MatchContract.TeamEntry._ID);
                    contentValues.remove(MatchContract.TeamEntry._ID);

                    int updatedRows = getContentResolver().update(MatchContract.TeamEntry.CONTENT_URI,
                            contentValues,
                            MatchContract.TeamEntry.TABLE_NAME + "." + MatchContract.TeamEntry._ID + " = ?",
                            new String[] { teamId });

                    LOGD(TAG, "updatedRows: " + updatedRows);

                } catch (ExecutionException e) {
                    LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(STATUS_ERROR));
                    e.printStackTrace();
                }
            }

            getContentResolver().bulkInsert(MatchContract.TeamEntry.CONTENT_URI,
                    newTeamInfo.keySet().toArray(new ContentValues[newTeamInfo.size()]));

        } catch (IOException e) {
            LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(STATUS_ERROR));
            e.printStackTrace();
        } catch (InterruptedException e2) {
            LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(STATUS_ERROR));
            e2.printStackTrace();
        }

        //        String[] projection = new String[]{
        //                MatchContract.TeamEntry.TABLE_NAME + "." + MatchContract.TeamEntry._ID,
        //                MatchContract.TeamEntry.COLUMN_TEAM_NAME,
        //                MatchContract.TeamEntry.COLUMN_TEAM_URL,
        //                MatchContract.TeamEntry.COLUMN_TEAM_LOGO_URL,
        //                MatchContract.TeamEntry.COLUMN_TEAM_STARRED,
        //        };
        //
        //        String sortOrder =
        //                MatchContract.TeamEntry.COLUMN_TEAM_NAME + " ASC";
        //
        //        Cursor c = getContentResolver().query(
        //                MatchContract.TeamEntry.CONTENT_URI,
        //                projection,
        //                MatchContract.TeamEntry.COLUMN_TEAM_NAME + " LIKE '%" + searchName + "%'",
        //                null,
        //                sortOrder
        //        );
        //
        //        LOGD(TAG+"/UST", "Starting Printout: ");
        //        int i = 0;
        //        while (c.moveToNext()) {
        //            String teamPrintOut =
        //                            "teamId: " + c.getInt(0) + " teamName: " + c.getString(1) + "\n" +
        //                            "teamUrl: " + c.getString(2) + "\n" +
        //                            "teamLogoUrl: " + c.getString(3) + "\n" +
        //                            "isFavourited: " + (c.getInt(4) == 0 ? "false" : "true");
        //            LOGD(TAG + "/UST", teamPrintOut);
        //            i++;
        //        }
        //        LOGD(TAG+"/UST", "Stopping Printout. Count: " + i);
        //
        //        c.close();

        // use local broadcast manager to hide loading indicator
        // and signal that cursorloader for top50 can happen.
        LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(STATUS_COMPLETED));
    }

    private boolean checkForConnectivity() {
        ConnectivityManager cm = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);

        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();

        return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
    }
}