Android Open Source - cs50-final-project-android Http Helper






From Project

Back to project page cs50-final-project-android.

License

The source code is released under:

MIT License

If you think the Android project cs50-final-project-android listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package net.cs50.recipes.util;
//from  w  ww.  j  a v a2 s .  c  o m
import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import net.cs50.recipes.BaseActivity;
import net.cs50.recipes.models.Recipe;
import net.cs50.recipes.provider.RecipeContract;

import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.Log;

// helper class to perform HTTP requests
public class HttpHelper {
    private static final String TAG = "HttpHelper";

    // url paths
    private static final String BASE_URL = "http://nom.hrvd.io/";
    private static final String CREATE_USER_URI = "user/create";
    private static final String AUTHORIZE_USER_URI = "authorize/";
    private static final String RECIPE_URI = "recipe";

    // Network connection timeout, in milliseconds.
    private static final int NET_CONNECT_TIMEOUT_MILLIS = 15000; // 15 seconds

    // Network read timeout, in milliseconds.
    private static final int NET_READ_TIMEOUT_MILLIS = 10000; // 10 seconds

    private static String mAuthToken = null;

    /* app currently does not support user signups via the mobile app
    public static String signUp(String firstName, String lastName, String username, String password)
            throws Exception {
        List<NameValuePair> params = new ArrayList<NameValuePair>(4);
        params.add(new BasicNameValuePair("username", username));
        params.add(new BasicNameValuePair("firstName", firstName));
        params.add(new BasicNameValuePair("lastName", lastName));
        params.add(new BasicNameValuePair("password", password));

        String authToken = null;
        try {
            InputStream stream = getStream(CREATE_USER_URI, "POST", params);

            JSONObject user = (JSONObject) new JSONTokener(getString(stream)).nextValue();
            authToken = user.getString("access_token");

        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return authToken;
    }
  */
    
    // authorize the user, return the auth token
    public static String authorize(String username, String password) {
        List<NameValuePair> params = new ArrayList<NameValuePair>(2);
        params.add(new BasicNameValuePair("username", username));
        params.add(new BasicNameValuePair("password", password));

        String authToken = null;
        try {
            InputStream stream = getStream(AUTHORIZE_USER_URI, "POST", params);

            JSONObject res = (JSONObject) new JSONTokener(getString(stream)).nextValue();
            if (res.has("access_token")) {
                authToken = res.getString("access_token");

                mAuthToken = authToken;
                Log.i(TAG, authToken);
            }

        } catch (JSONException e) {
            Log.e(TAG, "Error parsing JSON: " + e.toString());
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return authToken;
    }

    // like the given recipe
    public static boolean like(String id) {
        try {
            InputStream stream = getStream(RECIPE_URI + "/" + id + "/like", "POST", true);

            if (getString(stream).equals("true")) {
                return true;
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return false;
    }

    // unlike the given recipe
    public static boolean unlike(String id) {
        try {
            InputStream stream = getStream(RECIPE_URI + "/" + id + "/like", "DELETE", true);

            if (getString(stream).equals("true")) {
                return true;
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return false;
    }
    
    // add a given comment a notify data change via content resolver
    public static boolean addComment(ContentResolver cr, Uri recipeUri, String recipeId,
            String content) {
        List<NameValuePair> params = new ArrayList<NameValuePair>(1);
        params.add(new BasicNameValuePair("content", content));

        try {
            InputStream stream = getStream(RECIPE_URI + "/" + recipeId + "/addComment", "POST",
                    params, true);

            JSONArray array = new JSONArray(getString(stream));
            stream.close();

            ContentValues cv = new ContentValues();
            cv.put(RecipeContract.Recipe.COLUMN_NAME_COMMENTS, array.toString());

            cr.update(recipeUri, cv, null, null);
            cr.notifyChange(RecipeContract.Recipe.CONTENT_URI, null, false);
        } catch (Exception e) {
            Log.e(TAG, "Error occured in addComment", e);
        }

        return false;
    }

    // get HTTP stream (cascading function, see below)
    public static InputStream getStream(String uri, String requestMethod,
            List<NameValuePair> params, boolean includeAuthToken) throws IOException {
      
      // helpful logging for debugging
        Log.i(TAG, "Uri: " + uri);
        Log.i(TAG, "Request Method: " + requestMethod);
        Log.i(TAG, "Include Auth Token: " + includeAuthToken);
        
        // setup URL connection
        URL url = new URL(BASE_URL + uri);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setReadTimeout(NET_READ_TIMEOUT_MILLIS);
        conn.setConnectTimeout(NET_CONNECT_TIMEOUT_MILLIS);
        conn.setRequestMethod(requestMethod);
        conn.setDoInput(true);

        // set up request parameters, if needed
        if (params != null || includeAuthToken) {
            conn.setDoOutput(true);

            if (includeAuthToken) {
              // add auth token to parameters to be sent
                if (params == null) {
                    params = new ArrayList<NameValuePair>(1);
                }
                params.add(new BasicNameValuePair("access_token", BaseActivity.getAccessToken()));
            }

            Log.i(TAG, "Params: " + params.toString());

            // write parameters to output stream
            OutputStream os = conn.getOutputStream();
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
            writer.write(URLEncodedUtils.format(params, "UTF-8"));
            writer.flush();
            writer.close();
            os.close();
        }

        // connect to server
        conn.connect();

        Log.i(TAG, conn.getHeaderFields().toString());

        // return input stream for further processing
        return new BufferedInputStream(conn.getInputStream());
    }

    // simplified version of getStream(), allows for a specific request method
    public static InputStream getStream(String uri, String requestMethod) throws IOException {
        return getStream(uri, requestMethod, null);
    }

    // simplified version of getStream(), allows for setting request method and parameters
    public static InputStream getStream(String uri, String requestMethod, List<NameValuePair> params)
            throws IOException {
        return getStream(uri, requestMethod, params, false);
    }

   // simplified version of getStream(), allows for specific request method and the inclusion of an auth token
    public static InputStream getStream(String uri, String requestMethod, boolean includeAuthToken)
            throws IOException {
        return getStream(uri, requestMethod, null, includeAuthToken);
    }

   // simplified version of getStream(), just perform a GET request on URL
    public static InputStream getStream(String uri) throws IOException {
        return getStream(uri, "GET");
    }

    // convert InputString to String
    public static String getString(InputStream in) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[4096];
        int read;
        while ((read = in.read(buffer, 0, 4096)) > 0) {
            out.write(buffer, 0, read);
        }
        return new String(out.toByteArray());
    }

    // perform a POST request to upload recipe
    public static boolean uploadRecipe(ContentResolver cr, Bitmap bitmap, String name,
            List<String> ingredients, List<String> instructions) {
      
      // setup params
        List<NameValuePair> params = new ArrayList<NameValuePair>(2);
        params.add(new BasicNameValuePair("userId", Integer.toString(1)));
        params.add(new BasicNameValuePair("name", name));
        for (int i = 0; i < ingredients.size(); i++) {
            params.add(new BasicNameValuePair("ingredients[" + i + "]", ingredients.get(i)));
        }
        for (int i = 0; i < instructions.size(); i++) {
            params.add(new BasicNameValuePair("instructions[" + i + "]", instructions.get(i)));
        }

        try {
          // perform POST
            InputStream is = getStream(RECIPE_URI + "/create", "POST", params, true);

            JSONObject o = new JSONObject(getString(is));
            is.close();

            Recipe r = RecipeHelper.getRecipe(o);

            // next step: upload image
            return uploadImage(cr, r.getRecipeId(), bitmap);
        } catch (Exception e) {
            Log.e(TAG, "Error occured while uploading recipe", e);
            return false;
        }
    }

    // constants for performing our form upload
    private static final String ATTACHMENT_NAME = "image";
    private static final String ATTACHMENT_FILE_NAME = "image.png";
    private static final String CRLF = "\r\n";
    private static final String TWO_HYPHENS = "--";
    private static final String BOUNDARY = "----NomAndroid";

    // upload image -- based on tutorials below:
    // http://sunil-android.blogspot.com/2013/03/image-upload-on-server.html
    // http://stackoverflow.com/questions/11766878/sending-files-using-post-with-httpurlconnection
    private static boolean uploadImage(ContentResolver cr, String id, Bitmap image) {
        try {
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            image.compress(Bitmap.CompressFormat.PNG, 90, stream);
            stream.close();
            byte[] bytes = stream.toByteArray();

            // setup HTTPURLConnection
            HttpURLConnection httpUrlConnection = null;
            URL url = new URL(BASE_URL + RECIPE_URI + "/" + id + "/uploadImages?access_token="
                    + BaseActivity.getAccessToken());
            httpUrlConnection = (HttpURLConnection) url.openConnection();
            httpUrlConnection.setUseCaches(false);
            httpUrlConnection.setDoOutput(true);
            httpUrlConnection.setRequestMethod("POST");
            httpUrlConnection.setRequestProperty("Connection", "Keep-Alive");
            httpUrlConnection.setRequestProperty("Cache-Control", "no-cache");
            httpUrlConnection.setRequestProperty("Content-Type", "multipart/form-data; boundary="
                    + BOUNDARY);

            // begin output
            DataOutputStream request = new DataOutputStream(httpUrlConnection.getOutputStream());

            // begin content
            request.writeBytes(TWO_HYPHENS + BOUNDARY + CRLF);
            request.writeBytes("Content-Disposition: form-data; name=\"" + ATTACHMENT_NAME
                    + "\";filename=\"" + ATTACHMENT_FILE_NAME + "\"" + CRLF);
            request.writeBytes(CRLF);

            // write image to stream
            request.write(bytes);

            // end content
            request.writeBytes(CRLF);
            request.writeBytes(TWO_HYPHENS + BOUNDARY + TWO_HYPHENS + CRLF);

            request.flush();
            request.close();

            Log.i(TAG, httpUrlConnection.getHeaderFields().toString());

            // get response from server
            InputStream is = new BufferedInputStream(httpUrlConnection.getInputStream());

            JSONObject o = new JSONObject(getString(is));
            is.close();

            Recipe r = RecipeHelper.getRecipe(o);

            // set up content to be inserted into local database via content provider
            ContentValues cv = new ContentValues();
            cv.put(RecipeContract.Recipe.COLUMN_NAME_RECIPE_ID, r.getRecipeId());
            cv.put(RecipeContract.Recipe.COLUMN_NAME_NAME, r.getName());
            cv.put(RecipeContract.Recipe.COLUMN_NAME_INGREDIENTS, r.getIngredientsJSONString());
            cv.put(RecipeContract.Recipe.COLUMN_NAME_INSTRUCTIONS, r.getInstructionsJSONString());
            cv.put(RecipeContract.Recipe.COLUMN_NAME_COMMENTS, r.getCommentsJSONString());
            cv.put(RecipeContract.Recipe.COLUMN_NAME_LIKES, r.getNumLikes());
            cv.put(RecipeContract.Recipe.COLUMN_NAME_PRIMARY_IMAGE_URL, r.getImage(0));
            cv.put(RecipeContract.Recipe.COLUMN_NAME_CREATED_AT, r.getCreatedAt());
            cv.put(RecipeContract.Recipe.COLUMN_NAME_UPDATED_AT, r.getUpdatedAt());

            // insert new recipe
            cr.insert(RecipeContract.Recipe.CONTENT_URI, cv);
            
            // notify listeners that change has occurred
            cr.notifyChange(RecipeContract.Recipe.CONTENT_URI, null, false);
            return true;
        } catch (Exception e) {
            Log.e(TAG, "Error occured while uploading image", e);
            return false;
        }
    }

    // task to add recipe asynchronously
    public static class AddRecipeAsyncTask extends AsyncTask<Object, Void, Boolean> {
        @SuppressWarnings("unchecked")
        @Override
        protected Boolean doInBackground(Object... params) {
            return uploadRecipe((ContentResolver) params[0], (Bitmap) params[1],
                    (String) params[2], (List<String>) params[3], (List<String>) params[4]);
        }
    }

    // task to add comment asynchronously
    public static class AddCommentAsyncTask extends AsyncTask<Object, Void, Boolean> {
        @Override
        protected Boolean doInBackground(Object... params) {
            return addComment((ContentResolver) params[0], (Uri) params[1], (String) params[2],
                    (String) params[3]);
        }
    }

    // task to like recipe asynchronously
    public static class LikeAsyncTask extends AsyncTask<String, Void, Boolean> {
        @Override
        protected Boolean doInBackground(String... params) {
            return like(params[0]);
        }
    }

    // task to unlike recipe asynchronously
    public static class UnlikeAsyncTask extends AsyncTask<String, Void, Boolean> {
        @Override
        protected Boolean doInBackground(String... params) {
            return unlike(params[0]);
        }
    }

}




Java Source Code List

net.cs50.recipes.AboutFragment.java
net.cs50.recipes.BaseActivity.java
net.cs50.recipes.BaseDrawerActivity.java
net.cs50.recipes.CreateActivity.java
net.cs50.recipes.CreateDialog.java
net.cs50.recipes.MainActivity.java
net.cs50.recipes.RecipeListFragment.java
net.cs50.recipes.ViewRecipeActivity.java
net.cs50.recipes.accounts.AccountService.java
net.cs50.recipes.accounts.AuthenticatorActivity.java
net.cs50.recipes.models.Comment.java
net.cs50.recipes.models.Recipe.java
net.cs50.recipes.models.User.java
net.cs50.recipes.provider.RecipeContract.java
net.cs50.recipes.provider.RecipeProvider.java
net.cs50.recipes.sync.SyncAdapter.java
net.cs50.recipes.sync.SyncService.java
net.cs50.recipes.util.HttpHelper.java
net.cs50.recipes.util.ImageHelper.java
net.cs50.recipes.util.RecipeHelper.java
net.cs50.recipes.util.SelectionBuilder.java
net.cs50.recipes.util.SyncUtils.java