uk.ac.horizon.aestheticodes.controllers.ExperienceListUpdater.java Source code

Java tutorial

Introduction

Here is the source code for uk.ac.horizon.aestheticodes.controllers.ExperienceListUpdater.java

Source

/*
 * uk.ac.horizon.aestheticodes.Aestheticodes recognises a different marker scheme that allows the
 * creation of aesthetically pleasing, even beautiful, codes.
 * Copyright (C) 2015  uk.ac.horizon.aestheticodes.Aestheticodes
 *
 *     This program 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, see <http://www.gnu.org/licenses/>.
 */

package uk.ac.horizon.aestheticodes.controllers;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.util.Log;
import com.google.android.gms.auth.GoogleAuthUtil;
import com.google.gson.Gson;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import uk.ac.horizon.aestheticodes.R;
import uk.ac.horizon.aestheticodes.model.Experience;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class ExperienceListUpdater extends AsyncTask<Void, Experience, Collection<String>> {
    private static final class ExperienceResults {
        @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
        final Map<String, Experience> experiences = new HashMap<>();
    }

    private static final class ExperienceUpdates {
        @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
        final List<Object> experiences = new ArrayList<>();
    }

    private static final class ExperienceOp {
        final String id;
        final Experience.Operation op;
        final Integer version;

        public ExperienceOp(String id, Experience.Operation op) {
            this.id = id;
            this.op = op;
            this.version = null;
        }

        public ExperienceOp(String id, int version) {
            this.id = id;
            this.op = null;
            this.version = version;
        }
    }

    private static final String TAG = ExperienceListController.class.getName();

    public static void save(Context context, ExperienceListController experiences) {
        try {
            final File experienceFile = new File(context.getFilesDir(), "experiences.json");
            final FileWriter writer = new FileWriter(experienceFile);
            final Collection<Experience> saveExperiences = new ArrayList<>();
            for (Experience experience : experiences.get()) {
                if (experience.getOp() != Experience.Operation.temp) {
                    saveExperiences.add(experience);
                }
            }
            Gson gson = ExperienceParser.createParser();
            gson.toJson(saveExperiences, writer);

            writer.flush();
            writer.close();
        } catch (Exception e) {
            Log.e("", e.getMessage(), e);
        }
    }

    private final Context context;
    private final ExperienceListController experiences;

    public ExperienceListUpdater(Context context, ExperienceListController experiences) {
        this.context = context;
        this.experiences = experiences;
    }

    @Override
    protected Collection<String> doInBackground(Void... params) {
        final Gson gson = ExperienceParser.createParser();
        Set<String> removals = new HashSet<>();
        try {
            Collection<Experience> experienceList = experiences.get();
            boolean loaded = false;
            if (experienceList.isEmpty()) {
                Log.i("", "Loading...");
                try {
                    Experience[] experiencesLoaded = null;
                    File experienceFile = new File(context.getFilesDir(), "experiences.json");
                    if (experienceFile.exists()) {
                        try {
                            Log.i("", "Loading " + experienceFile.getAbsolutePath());
                            experiencesLoaded = gson.fromJson(new FileReader(experienceFile), Experience[].class);
                        } catch (Exception e) {
                            Log.w("", e.getMessage(), e);
                        }
                    }

                    if (experiencesLoaded == null) {
                        Log.i("", "Loading default.json");
                        experiencesLoaded = gson.fromJson(
                                new InputStreamReader(context.getAssets().open("default.json")),
                                Experience[].class);
                    }

                    if (experiencesLoaded != null) {
                        Log.i("", "Loaded");
                        publishProgress(experiencesLoaded);
                        experienceList = Arrays.asList(experiencesLoaded);
                    }

                    loaded = true;
                } catch (Exception e) {
                    Log.w(TAG, "Failed to load settings", e);
                }
            }

            Log.i(TAG, "Updating...");
            ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo netInfo = cm.getActiveNetworkInfo();
            if (netInfo != null && netInfo.isConnectedOrConnecting()) {
                boolean changes = false;
                final ExperienceUpdates updates = new ExperienceUpdates();
                for (Experience experience : experienceList) {
                    Log.i("", experience.getId());
                    if (experience.getOp() == null || experience.getOp() == Experience.Operation.retrieve) {
                        updates.experiences.add(new ExperienceOp(experience.getId(), experience.getVersion()));
                    } else if (experience.getOp() == Experience.Operation.remove) {
                        updates.experiences.add(new ExperienceOp(experience.getId(), Experience.Operation.remove));
                        changes = true;
                    } else if (experience.getOp() != Experience.Operation.temp) {
                        updates.experiences.add(experience);
                        changes = true;
                    }

                }

                if (changes || loaded) {
                    HttpResponse response = put(
                            "https://aestheticodes.appspot.com/_ah/api/experiences/v1/experiences",
                            gson.toJson(updates));
                    if (response.getStatusLine().getStatusCode() == 200) {
                        ExperienceResults results = gson.fromJson(
                                new InputStreamReader(response.getEntity().getContent()), ExperienceResults.class);
                        for (String experienceID : results.experiences.keySet()) {
                            Experience experience = results.experiences.get(experienceID);
                            if (experience.getId() == null) {
                                experience.setId(experienceID);
                            }

                            if (!experienceID.equals(experience.getId())) {
                                publishProgress(experience);
                                removals.add(experienceID);
                            } else if (experience.getOp() == Experience.Operation.remove) {
                                removals.add(experience.getId());
                            } else {
                                publishProgress(experience);
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            Log.e(TAG, e.getMessage(), e);
        }

        return removals;
    }

    @Override
    protected void onPostExecute(Collection<String> removals) {
        for (String experienceID : removals) {
            Log.i("", "Removing " + experienceID);
            experiences.remove(experienceID);
        }
        save(context, experiences);
    }

    @Override
    protected void onProgressUpdate(Experience... newExperiences) {
        if (newExperiences == null) {
            return;
        }

        for (Experience experience : newExperiences) {
            synchronized (experiences) {
                experiences.add(experience);
            }
        }
    }

    private HttpResponse put(String url, String data) throws Exception {
        HttpClient client = new DefaultHttpClient();
        HttpPut put = new HttpPut(new URL(url).toURI());
        put.addHeader("content-type", "application/json");
        put.setEntity(new StringEntity(data));

        String token = null;
        try {
            AccountManager accountManager = AccountManager.get(context);
            Account[] accounts = accountManager.getAccountsByType("com.google");
            if (accounts.length >= 1) {
                Log.i("", "Getting token for " + accounts[0].name);
                token = GoogleAuthUtil.getToken(context, accounts[0].name, context.getString(R.string.app_scope));
                put.addHeader("Authorization", "Bearer " + token);
                Log.i("", token);
            }
        } catch (Exception e) {
            Log.e("", e.getMessage(), e);
        }

        Log.i("", "PUT " + url);
        Log.i("", data);
        HttpResponse response = client.execute(put);
        if (response.getStatusLine().getStatusCode() == 401) {
            Log.w("", "Response " + response.getStatusLine().getStatusCode());
            if (token != null) {
                GoogleAuthUtil.invalidateToken(context, token);
            }
        } else if (response.getStatusLine().getStatusCode() != 200) {
            Log.w("", "Response " + response.getStatusLine().getStatusCode() + ": "
                    + response.getStatusLine().getReasonPhrase());
        }

        return response;
    }
}