/** * Copyright (c) 2012-2013 Nokia Corporation. All rights reserved. * Nokia and Nokia Connecting People are registered trademarks of Nokia Corporation. * Oracle and Java are trademarks or registered trademarks of Oracle and/or its * affiliates. Other product and company names mentioned herein may be trademarks * or trade names of their respective owners. * See LICENSE.TXT for license information. */ package com.nokia.example.rlinks.network.operation; import com.nokia.example.rlinks.model.CommentThing; import com.nokia.example.rlinks.network.HttpOperation; import java.util.Vector; import org.json.me.JSONArray; import org.json.me.JSONException; import org.json.me.JSONObject; /** * An HttpOperation that loads comments for a given Reddit link ID. * Uses a listener class to broadcast back the results of the operation. */ public class CommentsLoadOperation extends HttpOperation { protected final LoadCommentsListener listener; protected final String linkId; protected final int limit; /** * Listener interface for methods asynchronously fetching Reddit comments. * * Will be called with a null value if the loading should fail. */ public interface LoadCommentsListener { public void commentsReceived(Vector comments); } /** * Create a CommentsLoadOperation. * * @param linkId The ID of the Link to load comments for * @param limit Maximum number of comments to load, or 0 for no limit * @param listener Listener to call with the results */ public CommentsLoadOperation(String linkId, int limit, LoadCommentsListener listener) { this.linkId = linkId; this.limit = limit; this.listener = listener; } public String getUrl() { String url = BASE_URL + "comments/" + linkId + ".json"; if (limit > 0) { url += "?limit=" + limit; } return url; } public void responseReceived(byte[] response) { if (response == null || response.length == 0) { finished = true; listener.commentsReceived(null); return; } parseComments(new String(response), 0); } /** * Parse a JSON data string into a Vector of CommentThing objects. * * @param commentsJson JSON reply to parse into Comments * @param startLevel Level of hierarchy to start at (most of the time 0) */ protected void parseComments(final String commentsJson, final int startLevel) { Vector comments = new Vector(); JSONObject listingJsonObject; try { // Recurse through any replies and their replies and ... listingJsonObject = new JSONArray(commentsJson).getJSONObject(1); recursivelyAddReplies(comments, listingJsonObject, startLevel); } catch (JSONException e) { System.out.println("Error parsing JSON response: " + e.getMessage()); } // Signal the listener when done finished = true; if (!aborted) { listener.commentsReceived(comments); } } /** * Recursively parse the given listingJsonObject for Comments, adding them * into the Vector specified. Will call itself until the comment tree is * whole (until there are no more child JSON objects to parse). * * @param comments Vector of comments * @param listingJsonObject JSON object (comment listing) to parse * @param level Depth level * @throws JSONException In case of a parsing error */ protected void recursivelyAddReplies(Vector comments, JSONObject listingJsonObject, int level) throws JSONException { JSONArray childrenJsonArray = listingJsonObject .getJSONObject("data") .getJSONArray("children"); // Reuse the same objects to avoid unnecessary overhead JSONObject thingDataObj; CommentThing comment; for (int i = 0, len = childrenJsonArray.length(); i < len && !aborted; i++) { thingDataObj = childrenJsonArray.getJSONObject(i).getJSONObject("data"); try { // Create a comment item and append it to the list comment = CommentThing.fromJson(thingDataObj); comment.setLevel(level); comments.addElement(comment); } catch (JSONException e) { System.out.println("Could not parse comment JSON: " + e.getMessage()); } // Process any further replies JSONObject repliesJsonObject = thingDataObj.optJSONObject("replies"); if (repliesJsonObject != null) { recursivelyAddReplies(comments, repliesJsonObject, level + 1); } } } public String toString() { return "LoadComments(url=" + getUrl() + ")"; } }