eu.codeplumbers.cosi.services.CosiExpenseService.java Source code

Java tutorial

Introduction

Here is the source code for eu.codeplumbers.cosi.services.CosiExpenseService.java

Source

/*
 *     Cos android client for Cozy Cloud
 *
 *     Copyright (C)  2016 Hamza Abdelkebir
 *
 *     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/>.
 */

package eu.codeplumbers.cosi.services;

import android.app.IntentService;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.v4.content.WakefulBroadcastReceiver;
import android.support.v7.app.NotificationCompat;
import android.util.Base64;
import android.util.Log;

import com.activeandroid.query.Delete;

import org.apache.commons.io.IOUtils;
import org.greenrobot.eventbus.EventBus;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.util.List;

import eu.codeplumbers.cosi.R;
import eu.codeplumbers.cosi.db.models.Device;
import eu.codeplumbers.cosi.db.models.Expense;
import eu.codeplumbers.cosi.db.models.Receipt;
import eu.codeplumbers.cosi.services.events.ExpenseSyncEvent;

import static eu.codeplumbers.cosi.utils.Constants.REFRESH;
import static eu.codeplumbers.cosi.utils.Constants.SERVICE_ERROR;
import static eu.codeplumbers.cosi.utils.Constants.SYNC_MESSAGE;

/**
 * Created by thor on 10/29/16.
 */

public class CosiExpenseService extends IntentService {

    private String authHeader;
    private String designUrl;
    private String syncUrl;

    private int notification_id = 1376;
    private NotificationManager mNotifyManager;
    private NotificationCompat.Builder mBuilder;
    private boolean mSyncRunning;
    private boolean stopSync;
    private String errorMessage;

    public CosiExpenseService() {
        super("CosiExpenseService");

        mSyncRunning = false;
    }

    public CosiExpenseService(String name) {
        super(name);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        // Do the task here
        Log.i(CosiExpenseService.class.getName(), "Cosi Service running");

        // Release the wake lock provided by the WakefulBroadcastReceiver.
        WakefulBroadcastReceiver.completeWakefulIntent(intent);

        // delete local expenses
        new Delete().from(Receipt.class).execute();
        new Delete().from(Expense.class).execute();

        Device device = Device.registeredDevice();

        // cozy register device url
        designUrl = device.getUrl() + "/ds-api/request/expense/all/";
        syncUrl = device.getUrl() + "/ds-api/data/";

        // concatenate username and password with colon for authentication
        final String credentials = device.getLogin() + ":" + device.getPassword();
        authHeader = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);

        showNotification();

        if (isNetworkAvailable()) {
            try {
                EventBus.getDefault().post(new ExpenseSyncEvent(SYNC_MESSAGE, "Getting expenses from Cozy..."));
                getRemoteExpenses();
                mNotifyManager.cancel(notification_id);
                sendChangesToCozy();
                EventBus.getDefault().post(new ExpenseSyncEvent(REFRESH, "Sync OK"));
            } catch (Exception e) {
                e.printStackTrace();
                mSyncRunning = false;
                EventBus.getDefault().post(new ExpenseSyncEvent(SERVICE_ERROR, e.getLocalizedMessage()));
            }
        } else {
            mSyncRunning = false;
            EventBus.getDefault().post(new ExpenseSyncEvent(SERVICE_ERROR, "No Internet connection"));
            mBuilder.setContentText("Sync failed because no Internet connection was available");
            mNotifyManager.notify(notification_id, mBuilder.build());
        }
    }

    /**
     * Make remote request to get all loyalty cards stored in Cozy
     */
    public String getRemoteExpenses() {
        URL urlO = null;
        try {
            urlO = new URL(designUrl);
            HttpURLConnection conn = (HttpURLConnection) urlO.openConnection();
            conn.setConnectTimeout(5000);
            conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
            conn.setRequestProperty("Authorization", authHeader);
            conn.setDoInput(true);
            conn.setRequestMethod("POST");

            // read the response
            int status = conn.getResponseCode();
            InputStream in = null;

            if (status >= HttpURLConnection.HTTP_BAD_REQUEST) {
                in = conn.getErrorStream();
            } else {
                in = conn.getInputStream();
            }

            StringWriter writer = new StringWriter();
            IOUtils.copy(in, writer, "UTF-8");
            String result = writer.toString();

            JSONArray jsonArray = new JSONArray(result);

            if (jsonArray != null) {
                if (jsonArray.length() == 0) {
                    EventBus.getDefault()
                            .post(new ExpenseSyncEvent(SYNC_MESSAGE, "Your Cozy has no expenses stored."));
                    Expense.setAllUnsynced();
                } else {
                    for (int i = 0; i < jsonArray.length(); i++) {
                        try {

                            EventBus.getDefault().post(new ExpenseSyncEvent(SYNC_MESSAGE,
                                    "Reading expenses on Cozy " + i + "/" + jsonArray.length() + "..."));
                            JSONObject expenseJson = jsonArray.getJSONObject(i).getJSONObject("value");
                            Expense expense = Expense.getByRemoteId(expenseJson.get("_id").toString());
                            if (expense == null) {
                                expense = new Expense(expenseJson);
                            } else {
                                expense.setRemoteId(expenseJson.getString("_id"));
                                expense.setAmount(expenseJson.getDouble("amount"));
                                expense.setCategory(expenseJson.getString("category"));
                                expense.setDate(expenseJson.getString("date"));

                                if (expenseJson.has("deviceId")) {
                                    expense.setDeviceId(expenseJson.getString("deviceId"));
                                } else {
                                    expense.setDeviceId(Device.registeredDevice().getLogin());
                                }
                            }
                            expense.save();

                            if (expenseJson.has("receipts")) {
                                JSONArray receiptsArray = expenseJson.getJSONArray("receipts");

                                for (int j = 0; j < receiptsArray.length(); j++) {
                                    JSONObject recJsonObject = receiptsArray.getJSONObject(i);
                                    Receipt receipt = new Receipt();
                                    receipt.setBase64(recJsonObject.getString("base64"));
                                    receipt.setExpense(expense);
                                    receipt.setName("");
                                    receipt.save();
                                }
                            }
                        } catch (JSONException e) {
                            EventBus.getDefault()
                                    .post(new ExpenseSyncEvent(SERVICE_ERROR, e.getLocalizedMessage()));
                            stopSelf();
                        }
                    }
                }
            } else {
                errorMessage = new JSONObject(result).getString("error");
                EventBus.getDefault().post(new ExpenseSyncEvent(SERVICE_ERROR, errorMessage));
                stopSelf();
            }

            in.close();
            conn.disconnect();

        } catch (MalformedURLException e) {
            EventBus.getDefault().post(new ExpenseSyncEvent(SERVICE_ERROR, e.getLocalizedMessage()));
            stopSelf();
        } catch (ProtocolException e) {
            EventBus.getDefault().post(new ExpenseSyncEvent(SERVICE_ERROR, e.getLocalizedMessage()));
            stopSelf();
        } catch (IOException e) {
            EventBus.getDefault().post(new ExpenseSyncEvent(SERVICE_ERROR, e.getLocalizedMessage()));
            stopSelf();
        } catch (JSONException e) {
            EventBus.getDefault().post(new ExpenseSyncEvent(SERVICE_ERROR, e.getLocalizedMessage()));
            stopSelf();
        }
        return errorMessage;
    }

    public void sendChangesToCozy() {
        List<Expense> unSyncedExpenses = Expense.getAllUnsynced();
        int i = 0;
        for (Expense expense : unSyncedExpenses) {
            URL urlO = null;
            try {
                JSONObject jsonObject = expense.toJsonObject();
                mBuilder.setProgress(unSyncedExpenses.size(), i + 1, false);
                mBuilder.setContentText("Syncing " + jsonObject.getString("docType") + ":");
                mNotifyManager.notify(notification_id, mBuilder.build());
                EventBus.getDefault().post(
                        new ExpenseSyncEvent(SYNC_MESSAGE, getString(R.string.lbl_expense_status_read_phone)));
                String remoteId = jsonObject.getString("remoteId");
                String requestMethod = "";

                if (remoteId.isEmpty()) {
                    urlO = new URL(syncUrl);
                    requestMethod = "POST";
                } else {
                    urlO = new URL(syncUrl + remoteId + "/");
                    requestMethod = "PUT";
                }

                HttpURLConnection conn = (HttpURLConnection) urlO.openConnection();
                conn.setConnectTimeout(5000);
                conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
                conn.setRequestProperty("Authorization", authHeader);
                conn.setDoOutput(true);
                conn.setDoInput(true);

                conn.setRequestMethod(requestMethod);

                // set request body
                jsonObject.remove("remoteId");
                long objectId = jsonObject.getLong("id");
                jsonObject.remove("id");
                OutputStream os = conn.getOutputStream();
                os.write(jsonObject.toString().getBytes("UTF-8"));
                os.flush();

                // read the response
                InputStream in = new BufferedInputStream(conn.getInputStream());

                StringWriter writer = new StringWriter();
                IOUtils.copy(in, writer, "UTF-8");
                String result = writer.toString();

                JSONObject jsonObjectResult = new JSONObject(result);

                if (jsonObjectResult != null && jsonObjectResult.has("_id")) {
                    result = jsonObjectResult.getString("_id");
                    expense.setRemoteId(result);
                    expense.save();
                }

                in.close();
                conn.disconnect();

            } catch (MalformedURLException e) {
                EventBus.getDefault().post(new ExpenseSyncEvent(SERVICE_ERROR, e.getLocalizedMessage()));
                e.printStackTrace();
                stopSelf();
            } catch (ProtocolException e) {
                EventBus.getDefault().post(new ExpenseSyncEvent(SERVICE_ERROR, e.getLocalizedMessage()));
                e.printStackTrace();
                stopSelf();
            } catch (IOException e) {
                EventBus.getDefault().post(new ExpenseSyncEvent(SERVICE_ERROR, e.getLocalizedMessage()));
                e.printStackTrace();
                stopSelf();
            } catch (JSONException e) {
                EventBus.getDefault().post(new ExpenseSyncEvent(SERVICE_ERROR, e.getLocalizedMessage()));
                e.printStackTrace();
                stopSelf();
            }
            i++;
        }
    }

    private boolean isNetworkAvailable() {
        ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(
                Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
        return activeNetworkInfo != null && activeNetworkInfo.isConnected();
    }

    public void showNotification() {
        mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        mBuilder = new NotificationCompat.Builder(this);
        mBuilder.setContentTitle(getString(R.string.lbl_expenses))
                .setContentText(getString(R.string.lbl_contacts_ongoing_sync)).setSmallIcon(R.drawable.ic_fa_file)
                .setOngoing(true);
    }
}