com.appjma.appdeployer.service.Downloader.java Source code

Java tutorial

Introduction

Here is the source code for com.appjma.appdeployer.service.Downloader.java

Source

/*
 * Copyright (C) 2013 Jacek Marchwicki <jacek.marchwicki@gmail.com>
 *
 * 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 com.appjma.appdeployer.service;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.HTTP;
import org.json.JSONException;
import org.json.JSONObject;

import android.annotation.TargetApi;
import android.app.DownloadManager;
import android.app.DownloadManager.Request;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;

import com.appjma.appdeployer.AppPreferences;
import com.appjma.appdeployer.content.AppContract;
import com.appunite.auhttp.HTTPUtils;
import com.appunite.auhttp.HTTPUtils.GetBuilder;
import com.appunite.auhttp.HTTPUtils.WrongHttpResponseCode;

import static com.google.common.base.Preconditions.*;

public class Downloader {

    public static class TooManyRecords extends Exception {
        private static final long serialVersionUID = 1L;

        public TooManyRecords() {
            super("Too many records while quering");
        }
    }

    public static class UnauthorizedResponseCode extends Exception {
        private int mStatusCode;
        private final String mToken;

        public UnauthorizedResponseCode(HttpResponse response, String token) {
            super(String.format("Unauthorized response from server: %d", response.getStatusLine().getStatusCode()));
            mToken = token;
            mStatusCode = response.getStatusLine().getStatusCode();
        }

        public String getToken() {
            return mToken;
        }

        public int getStatusCode() {
            return mStatusCode;
        }

        private static final long serialVersionUID = 1L;

    }

    private static final String BASE_API_URL = "https://app-deployer.appspot.com/_ah/api/appdeployer/v1";
    // private static final String BASE_API_URL =
    // "http://192.168.111.149:8888/_ah/api/appdeployer/v1";
    private static final int MAX_LAST_TOTKEN_REPETANCE = 10;
    public static final String SCOPE = "oauth2:https://www.googleapis.com/auth/userinfo.email";

    private ParserResult mParserResult;
    private Parser mParser;
    private HttpClient mHttpClient;
    private ContentResolver mCr;
    private AppPreferences mAppPreferences;
    private Context mContext;

    public Downloader(Context context) {
        mParserResult = new ProviderParserResult(context);
        mParser = new Parser(mParserResult);
        mCr = context.getContentResolver();
        mAppPreferences = new AppPreferences(context);
        mContext = context;
    }

    private HttpClient getHttpClient() {
        if (mHttpClient != null) {
            return mHttpClient;
        }
        mHttpClient = new DefaultHttpClient();
        return mHttpClient;
    }

    public void syncApps(String token, Uri uri) throws ClientProtocolException, IOException, JSONException,
            TooManyRecords, WrongHttpResponseCode, UnauthorizedResponseCode {
        String selection = AppContract.Apps.SYNCED + " = 0";
        String[] PROJECTION = new String[] { AppContract.Apps.APP_ID, AppContract.Apps.GUID, AppContract.Apps.NAME,
                AppContract.Apps.DELETED };
        Cursor cursor = mCr.query(uri, PROJECTION, selection, null, null);
        try {
            for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
                String id = cursor.getString(0);
                String guid = cursor.getString(1);
                String name = cursor.getString(2);
                boolean deleted = cursor.getInt(3) == 0 ? false : true;
                if (deleted == true) {
                    checkState(guid != null, "Row could not be marked as deleted if it is not synced");
                    deleteApp(token, id, guid);
                } else if (guid == null) {
                    insertApp(token, id, name);
                } else {
                    updateApp(token, id, guid, name);
                }
            }
        } finally {
            cursor.close();
        }
    }

    private void deleteApp(String token, String id, String guid)
            throws ClientProtocolException, IOException, UnauthorizedResponseCode, WrongHttpResponseCode {
        String url = new GetBuilder(BASE_API_URL).appendPathSegment("apps").appendPathSegment(guid).build();
        HttpDelete request = new HttpDelete(url);
        setupDefaultHeaders(request, token);
        HttpResponse response = getHttpClient().execute(request);
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == HttpStatus.SC_UNAUTHORIZED) {
            throw new UnauthorizedResponseCode(response, token);
        }
        if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_NOT_FOUND) {
            // if not (deleted or already deleted)
            throw new WrongHttpResponseCode(response);
        }
        try {
            mParserResult.deleteApp(id);
            mParserResult.apply();
        } finally {
            mParserResult.clear();
        }
    }

    private void updateApp(String token, String id, String guid, String name) throws ClientProtocolException,
            IOException, UnauthorizedResponseCode, WrongHttpResponseCode, JSONException {
        String url = new GetBuilder(BASE_API_URL).appendPathSegment("apps").appendPathSegment(guid).build();
        HttpPut request = new HttpPut(url);
        try {
            JSONObject obj = new JSONObject();
            obj.put("name", name);
            request.setEntity(getJsonEntity(obj));
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
        setupDefaultHeaders(request, token);
        HttpResponse response = getHttpClient().execute(request);
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == HttpStatus.SC_UNAUTHORIZED) {
            throw new UnauthorizedResponseCode(response, token);
        }
        if (statusCode != HttpStatus.SC_OK) {
            throw new WrongHttpResponseCode(response);
        }
        JSONObject json = HTTPUtils.getJsonFromResponse(response);
        try {
            mParser.parseApp(id, json);
            mParserResult.apply();
        } finally {
            mParserResult.clear();
        }
    }

    private void insertApp(String token, String id, String name) throws WrongHttpResponseCode,
            UnauthorizedResponseCode, ClientProtocolException, IOException, JSONException {
        String url = new GetBuilder(BASE_API_URL).appendPathSegment("apps").build();
        HttpPost request = new HttpPost(url);
        try {
            JSONObject obj = new JSONObject();
            obj.put("name", name);
            request.setEntity(getJsonEntity(obj));
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
        setupDefaultHeaders(request, token);
        HttpResponse response = getHttpClient().execute(request);
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == HttpStatus.SC_UNAUTHORIZED) {
            throw new UnauthorizedResponseCode(response, token);
        }
        if (statusCode != HttpStatus.SC_OK) {
            throw new WrongHttpResponseCode(response);
        }
        JSONObject json = HTTPUtils.getJsonFromResponse(response);
        try {
            mParser.parseApp(id, json);
            mParserResult.apply();
        } finally {
            mParserResult.clear();
        }
    }

    public void downloadApps(String token) throws ClientProtocolException, IOException, JSONException,
            TooManyRecords, WrongHttpResponseCode, UnauthorizedResponseCode {
        String nextToken = null;
        int repetance = 0;
        while (true) {
            String url = new GetBuilder(BASE_API_URL).appendPathSegment("apps").addParam("limit", "10")
                    .addParamIf(nextToken != null, "next_token", nextToken)
                    .addParam("fields", "items(created_at,guid,name,token,updated_at),next_token").build();
            HttpGet request = new HttpGet(url);
            setupDefaultHeaders(request, token);
            HttpResponse response = getHttpClient().execute(request);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == HttpStatus.SC_UNAUTHORIZED) {
                throw new UnauthorizedResponseCode(response, token);
            }
            if (statusCode != HttpStatus.SC_OK) {
                throw new WrongHttpResponseCode(response);
            }
            JSONObject json = HTTPUtils.getJsonFromResponse(response);
            try {
                mParser.parseApps(json);
                if (nextToken == null) {
                    mParserResult.clearOldApps();
                }
                mParserResult.apply();
            } finally {
                mParserResult.clear();
            }
            nextToken = mAppPreferences.getAppsNextToken();
            if (nextToken == null) {
                return;
            }
            if (repetance++ > MAX_LAST_TOTKEN_REPETANCE) {
                throw new TooManyRecords();
            }
        }
    }

    private void setupDefaultHeaders(HttpRequestBase request, String token) {
        HTTPUtils.setupDefaultHeaders(request);
        request.setHeader("Accept", "application/json");
        if (token != null) {
            request.addHeader("Authorization", "Bearer " + token);
        }
    }

    public void downloadApp(Uri uri, String token) throws ClientProtocolException, IOException, JSONException {
        String guid = getAppGuid(uri);
        if (guid == null) {
            // We do no have guid for this element - its mean that is not
            // yet synced to server - this mean that we can not download it
            return;
        }
        String url = new GetBuilder(BASE_API_URL).appendPathSegment("apps").appendPathSegment(guid)
                .addParam("fields", "items(created_at,guid,name,token,updated_at),next_token").build();
        HttpGet request = new HttpGet(url);
        setupDefaultHeaders(request, token);
        HttpResponse response = getHttpClient().execute(request);
        JSONObject json = HTTPUtils.getJsonFromResponse(response);
        try {
            mParser.parseApp(null, json);
            mParserResult.apply();
        } finally {
            mParserResult.clear();
        }
    }

    private String getAppGuid(Uri uri) {
        String guid;
        Cursor cursor = mCr.query(uri, new String[] { AppContract.Apps.GUID }, null, null, null);
        try {
            if (!cursor.moveToFirst()) {
                return null;
            }
            guid = cursor.getString(0);
        } finally {
            cursor.close();
        }
        return guid;
    }

    public void downloadAppVersions(String appId, String token)
            throws ClientProtocolException, IOException, JSONException {
        String appGuid = getAppGuid(Uri.withAppendedPath(AppContract.Apps.CONTENT_URI, appId));
        if (appGuid == null) {
            // We do no have appGuid for this element - its mean that is not
            // yet synced to server - this mean that we can not download it
            return;
        }
        String url = new GetBuilder(BASE_API_URL).appendPathSegment("apps").appendPathSegment(appGuid)
                .appendPathSegment("versions").build();
        HttpGet request = new HttpGet(url);
        setupDefaultHeaders(request, token);
        HttpResponse response = getHttpClient().execute(request);
        JSONObject json = HTTPUtils.getJsonFromResponse(response);
        try {
            mParser.parseAppVersions(appId, json);
            mParserResult.clearOldAppVersions(appId);
            mParserResult.apply();
        } finally {
            mParserResult.clear();
        }
    }

    private HttpEntity getJsonEntity(JSONObject object) {
        StringEntity entity;
        try {
            entity = new StringEntity(object.toString(), HTTP.UTF_8);
            entity.setContentType("application/json; charset=utf-8");
            return entity;
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException();
        }
    }

    public void downloadFile(String appVersion, String token) {
        String url;
        String name;
        String version;
        Cursor cursor = mCr.query(
                AppContract.AppVersions.CONTENT_URI.buildUpon().appendPath(appVersion)
                        .appendQueryParameter("limit", "1").build(),
                new String[] { AppContract.AppVersions.VERSION, AppContract.Apps.NAME,
                        AppContract.AppVersions.DOWNLOAD_URL },
                null, null, null);
        try {
            if (!cursor.moveToFirst()) {
                return;
            }
            version = cursor.getString(0);
            name = cursor.getString(1);
            url = cursor.getString(2);

        } finally {
            cursor.close();
        }
        if (url == null) {
            return;
        }
        Uri uri = Uri.parse(url);
        DownloadManager downloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
        String title = String.format("%s (%s)", name, version);
        Request request = new DownloadManager.Request(uri).addRequestHeader("Authorization", "Bearer " + token)
                .setTitle(title).setVisibleInDownloadsUi(true)
                .setMimeType("application/vnd.android.package-archive");
        setRequestNotificationStatus(request);
        downloadManager.enqueue(request);
    }

    @SuppressWarnings("deprecation")
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void setRequestNotificationStatus(Request request) {
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) {
            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        } else {
            request.setShowRunningNotification(true);
        }
    }

    @SuppressWarnings("unused")
    private String getOneFieldOrNull(Uri uri, String id, String field) {
        Cursor cursor = mCr.query(uri.buildUpon().appendPath(id).appendQueryParameter("limit", "1").build(),
                new String[] { field }, null, null, null);
        try {
            if (!cursor.moveToFirst()) {
                return null;
            }
            return cursor.getString(0);
        } finally {
            cursor.close();
        }
    }

}