Android Open Source - Crowdsource Reddit Request






From Project

Back to project page Crowdsource.

License

The source code is released under:

Apache License

If you think the Android project Crowdsource 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

/**
 *//from ww  w .ja  v a2 s .com
 * Copyright 2014 Cody Huzarski (chuzarski.net)
 *
 * 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
 *
 */

package net.chuzarski.crowdednews.utils.reddit;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import timber.log.Timber;

public class RedditRequest {
    //filters
    public static final int FILTER_HOT = 1;
    public static final int FILTER_NEW = 2;
    public static final int FILTER_RISING = 3;
    public static final int FILTER_CONTROVERSIAL = 4;
    public static final int FILTER_TOP = 5;


    private URL requestURL;
    private String urlString;
    private String targetReddit;
    private int requestFilter;

    //URL Params
    private int limit;
    private int count;
    private String requestPostsBefore;
    private String requestPostsAfter;


    public static class Builder {

        //ABSOLUTELY REQUIRED
        private String targetReddit; //sub or multi

        private int requestFilter;
        //remaining can have default values
        //misc URL parameters
        private int limit;

        private int count;
        private String after;
        private String before;


        public Builder(String targetReddit, int requestFilter) {
            this.targetReddit = targetReddit;
            this.requestFilter = requestFilter;
        }

        public Builder setLimit(int limit) {
            this.limit = limit;
            return this;
        }


        public Builder setCount(int count) {
            this.count = count;
            return this;
        }

        public Builder setAfter(String after) {
            this.after = after;
            return this;
        }

        public Builder setBefore(String before) {
            this.before = before;
            return this;
        }

        public RedditRequest build() throws MalformedURLException { return new RedditRequest(this); }
    }

    private RedditRequest(Builder b) throws MalformedURLException {

        //need a logger
        Timber.tag("RedditRequest");

        //set the values
        setCount(b.count);
        setLimit(b.limit);
        setRequestPostsAfter(b.after);
        setRequestPostsBefore(b.before);
        setRequestFilter(b.requestFilter);
        setTargetReddit(b.targetReddit);

        //build the URL string
        this.urlString = buildURL();

        //create the url object
        requestURL = new URL(this.getUrlString());

    }


    /**
     * Builds URL from Request parameters
     * @return URL String
     */
    private String buildURL() {
        String theURL = "http://www.reddit.com/";

        //add the target
        theURL += getTargetReddit();

        //need a filter
        switch(getRequestFilter()) {
            case FILTER_HOT:
                theURL += "/hot";
                break;
            case FILTER_NEW:
                theURL += "/new";
                break;
            case FILTER_RISING:
                theURL += "/rising";
                break;
            case FILTER_CONTROVERSIAL:
                theURL += "/controversial";
                break;
            case FILTER_TOP:
                theURL += "/top";
                break;
        }

        //of course we're working with JSON
        theURL += ".json?";

        theURL += "limit=" + String.valueOf(getLimit()) + "&";
        theURL += "count=" + String.valueOf(getCount()) + "&";

        //after and before can be empty
        if(!(getRequestPostsAfter() == null)) {
            theURL += "after=" + getRequestPostsAfter() + "&";
        }

        if(!(getRequestPostsBefore() == null)) {
            theURL += "before=" + getRequestPostsBefore();
        }

        return theURL;
    }

    /**
     * Makes the request to Reddit
     * @return RedditResponse Object
     * @throws IOException
     * @throws RedditException
     */
    public RedditResponse fireRequest() throws IOException, RedditException {
        //create a connection
        HttpURLConnection connection = null;
        RedditResponse response = null;
        InputStream in;

        connection = (HttpURLConnection) getRequestURL().openConnection();
        in = new BufferedInputStream(connection.getInputStream());

        //create the response object
        response = parseRedditData(IOUtils.toString(in));

        //sever the connection
        connection.disconnect();

        return response;
    }

    /**
     * Parses JSON from the reponse from Reddit, creates RedditResponse object
     * @param json The JSON String from Reddit
     * @return RedditResponse
     * @throws RedditException
     */
    private RedditResponse parseRedditData(String json) throws RedditException {

        JSONObject data;
        String postsBefore;
        String postsAfter;
        int redditError;
        boolean additionalPages;

        List<RedditPost> posts;

        try {
            data = new JSONObject(json).getJSONObject("data");
        } catch (JSONException e) {
            Timber.e("Data object could not be created");
            throw new RedditException(RedditErrors.REDDIT_PARSE_ERROR);
        }

        if(data.length() == 1) {
            //this looks like an error?
            try {
                redditError = data.getInt("error");
            } catch (JSONException e) {
                Timber.e("Expected an error to pop up, got something else");
                throw new RedditException(RedditErrors.REDDIT_PARSE_ERROR);
            }

            switch(redditError) {
                case RedditErrors.REDDIT_404:
                    throw new RedditException(RedditErrors.REDDIT_404);
                case RedditErrors.REDDIT_500:
                    throw new RedditException(RedditErrors.REDDIT_500);
            }
        }

        //continue on if errors are out of the way, set posts before and after
        try {
            postsAfter = data.getString("after");
            postsBefore = data.getString("before");
        } catch (JSONException e) {
            Timber.e("Posts before and after could not be parsed");
            throw new RedditException(RedditErrors.REDDIT_PARSE_ERROR);
        }

        //create posts
        try {
            posts = createPostList(data.getJSONArray("children"));
        } catch (JSONException e) {
            Timber.e("Failed to create the post array from \"children\"");
            throw new RedditException(RedditErrors.REDDIT_PARSE_ERROR);
        }

        //should be ready to create the Response
        return new RedditResponse(posts, postsBefore, postsAfter);

    }

    /**
     * Creates an ArrayList using a JSONArray
     * @param postsJSON JSONArray of Reddit data
     * @return ArrayList of RedditPost objects
     * @throws RedditException
     */
    private List<RedditPost> createPostList(JSONArray postsJSON) throws RedditException {

        List<RedditPost> posts = new ArrayList<RedditPost>();

        //fill the list
        for(int i = 0; i < postsJSON.length(); i++) {
            try {
                posts.add(createSingleRedditPost(postsJSON.getJSONObject(i).getJSONObject("data")));
            } catch (JSONException e) {
                Timber.e("Could not create Reddit post");
                throw new RedditException(RedditErrors.REDDIT_PARSE_ERROR);
            } catch(RedditException e) {
                if((e.getRedditErrorCode() == RedditErrors.REDDIT_SELF_POST)) {
                    //good job, well done
                    Timber.i("Caught self post");

                } else {
                    throw new RedditException(RedditErrors.REDDIT_PARSE_ERROR);
                }
            }
        }

        return posts;
    }

    /**
     * Creates a single RedditPost object from the given index of the postsJSONArray
     * @return RedditPost
     * @throws JSONException
     */
    public RedditPost createSingleRedditPost(JSONObject postObj) throws JSONException, RedditException {

        RedditPost post;

        //all data in a post
        String title;
        String url;
        String name;
        String id;
        String domain;

        long createdUTC;
        boolean stickied;

        title = StringEscapeUtils.unescapeHtml4(postObj.getString("title"));
        name = postObj.getString("name");
        url = postObj.getString("url");
        id = postObj.getString("id");
        stickied = postObj.getBoolean("stickied");
        createdUTC = postObj.getLong("created_utc");
        domain = postObj.getString("domain");

        //meet our conditions
        if(domain.contains("self.")) {
            throw new RedditException(RedditErrors.REDDIT_SELF_POST);
        }

        post = new RedditPost.Builder(title, url)
                .redditName(name)
                .redditId(id)
                .isStickied(stickied)
                .timeCreated(createdUTC)
                .linkDomain(domain)
                .build();

        return post;
    }

    public void setCount(int count) {
        if(count > 100) {
            this.count = 100;
            Timber.w("The post count was over 100, set to default of 100");
        } else if (limit < 0) {
            this.limit = 0;
            Timber.w("A post count less than 0 was passed, set to the default of zero");
        } else {
            this.count = count;
        }
    }

    public String getRequestPostsBefore() {
        return requestPostsBefore;
    }

    public void setRequestPostsBefore(String requestPostsBefore) {
        this.requestPostsBefore = requestPostsBefore;
    }

    public String getRequestPostsAfter() {
        return requestPostsAfter;
    }

    public void setRequestPostsAfter(String requestPostsAfter) {
        this.requestPostsAfter = requestPostsAfter;
    }

    public String getUrlString() {
        return this.urlString;
    }

    public URL getRequestURL() {
        return this.requestURL;
    }

    public String getTargetReddit() {
        return targetReddit;
    }

    private void setTargetReddit(String targetReddit) {
        this.targetReddit = targetReddit;
    }

    public int getRequestFilter() {
        return requestFilter;
    }

    public void setRequestFilter(int requestFilter) {
        this.requestFilter = requestFilter;
    }

    public int getLimit() {
        return limit;
    }

    public void setLimit(int limit) {
        if(limit > 100) {
            this.limit = 100;
            Timber.w("The request limit passed was higher than 100, limit set to 100");
        } else if(limit < 0) {
            this.limit = 20;
            Timber.w("The request limit passed was less than 0, set to default of 20");
        } else if(limit == 0) {
            this.limit = 20;
            Timber.w("The request limit passed was 0, set to the default of 20");
        } else {
            this.limit = limit;
        }
    }

    public int getCount() {
        return count;
    }
}




Java Source Code List

net.chuzarski.crowdednews.ApplicationTest.java
net.chuzarski.crowdednews.CrowdedNewsApplication.java
net.chuzarski.crowdednews.activities.ArticleViewActivity.java
net.chuzarski.crowdednews.activities.LicenseActivity.java
net.chuzarski.crowdednews.activities.MainActivity.java
net.chuzarski.crowdednews.activities.SettingsActivity.java
net.chuzarski.crowdednews.adapters.PostsAdapter.java
net.chuzarski.crowdednews.events.ArticleLoadCompleteEvent.java
net.chuzarski.crowdednews.events.RedditRetrieveCompletedEvent.java
net.chuzarski.crowdednews.jobs.RedditRetrieveJob.java
net.chuzarski.crowdednews.jobs.util.RedditJobParams.java
net.chuzarski.crowdednews.utils.AppSession.java
net.chuzarski.crowdednews.utils.ProductionTree.java
net.chuzarski.crowdednews.utils.RedditSources.java
net.chuzarski.crowdednews.utils.reddit.RedditErrors.java
net.chuzarski.crowdednews.utils.reddit.RedditException.java
net.chuzarski.crowdednews.utils.reddit.RedditPost.java
net.chuzarski.crowdednews.utils.reddit.RedditRequest.java
net.chuzarski.crowdednews.utils.reddit.RedditResponse.java