/** * 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.network.HttpOperation; import com.nokia.example.rlinks.util.UrlEncoder; import javax.microedition.io.HttpConnection; import org.json.me.JSONArray; import org.json.me.JSONObject; /** * An HttpOperation that logs an user into Reddit. * * A successful call will return two items that are required to maintain * a user session (and to successfully use operations that require user * authentication, such as commenting and voting): * * - a "modhash" String * - a "reddit_session" cookie, handled by the HttpClient * * The user account must have been created beforehand (e.g. in www.reddit.com). * * @see https://github.com/reddit/reddit/wiki/API%3A-login */ public class LoginOperation extends HttpOperation { private final String username; private final String password; private final LoginListener listener; /** * Listener interface used to signal the result of the login back to * the caller. */ public interface LoginListener { /** Callback handler for a successful login. */ public void loginSucceeded(String username, String modhash); /** Callback handler for a failed login. */ public void loginFailed(String reason); } /** * Create a LoginOperation. * * @param username Username for login * @param password Password for login * @param listener Listener to signal success or failure to */ public LoginOperation(String username, String password, LoginListener listener) { this.username = username; this.password = password; this.listener = listener; } /** * Format a request body using the data given in the constructor. * * @return A request body understood by the Reddit API */ public String getRequestBody() { return "api_type=json" + "&user=" + UrlEncoder.encode(username) + "&passwd=" + UrlEncoder.encode(password); } /** * This operation uses the HTTP POST method. */ public String getRequestMethod() { return HttpConnection.POST; } public String getUrl() { return BASE_URL + "api/login/" + UrlEncoder.encode(username); } public void responseReceived(byte[] response) { if (response == null || response.length == 0) { finished = true; listener.loginFailed(null); return; } parseResponse(new String(response)); } /** * Parse a login JSON response. * * A successful login response has: * - a modhash in the 'data' object * - an empty 'errors' array * * If the response doensn't meet this criteria, the login is interpreted * as failed. No further error codes are parsed in the scope of this app. * * Example of a failed login: * {"json": {"errors": [["WRONG_PASSWORD", "invalid password", "passwd"]]}} * * @param responseJson Login response as JSON */ private void parseResponse(String responseJson) { String reason = null; String modhash = null; try { JSONObject obj = new JSONObject(responseJson).getJSONObject("json"); JSONArray errors = obj.getJSONArray("errors"); JSONObject data = obj.optJSONObject("data"); if (data != null) { modhash = data.optString("modhash"); } // In case of a successful login, invoke the success callback if (errors.length() == 0 && modhash != null) { finished = true; listener.loginSucceeded(username, modhash); return; } // Otherwise try to interpret errors else if (errors.length() > 0) { String errorCode = errors.getJSONArray(0).getString(0); if ("WRONG_PASSWORD".equals(errorCode)) { reason = "wrong password"; } else if ("RATELIMIT".equals(errorCode)) { reason = "trying too often"; } } } catch (Exception e) { System.out.println("Error parsing JSON response: " + e.getMessage()); } // If the login conditions were met (or the response couldn't be parsed), // invoke the failure callback. finished = true; listener.loginFailed(reason); } }