Package ar.com.restba.connectors

Source Code of ar.com.restba.connectors.BaseRestBAConnector$DefaultLegacyFacebookExceptionMapper

package ar.com.restba.connectors;


import static com.restfb.util.StringUtils.isBlank;
import static com.restfb.util.StringUtils.trimToEmpty;
import static com.restfb.util.StringUtils.urlEncode;
import static java.util.Arrays.asList;

import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Logger;

import ar.com.restba.json.JsonException;
import ar.com.restba.json.JsonObject;

import com.restfb.JsonMapper;
import com.restfb.Parameter;
import com.restfb.WebRequestor;
import com.restfb.exception.FacebookException;
import com.restfb.exception.FacebookExceptionMapper;
import com.restfb.exception.FacebookJsonMappingException;
import com.restfb.exception.FacebookOAuthException;
import com.restfb.exception.FacebookResponseStatusException;

/**
* Base class that contains data and functionality common to
* {@link DefaultFacebookClient} and {@link DefaultLegacyFacebookClient}.
*
* @author <a href="http://restfb.com">Mark Allen</a>
* @since 1.5
*/
public abstract class BaseRestBAConnector {
  /**
   * Handles {@code GET}s and {@code POST}s to the Facebook API endpoint.
   */
  protected WebRequestor webRequestor;

  /**
   * Handles mapping Facebook response JSON to Java objects.
   */
  protected JsonMapper jsonMapper;

  /**
   * Knows how to map Old REST API exceptions to formal Java exception types.
   */
  protected FacebookExceptionMapper legacyFacebookExceptionMapper;

  /**
   * Set of parameter names that user must not specify themselves, since we use
   * these parameters internally.
   */
  protected final Set<String> illegalParamNames = new HashSet<String>();

  /**
   * Set of API calls that can use the read-only endpoint for a performance
   * boost.
   */
  protected final Set<String> readOnlyApiCalls = new HashSet<String>();

  /**
   * Legacy API error response 'error_code' attribute name.
   */
  protected static final String LEGACY_ERROR_CODE_ATTRIBUTE_NAME = "error_code";

  /**
   * Legacy API error response 'error_msg' attribute name.
   */
  protected static final String LEGACY_ERROR_MSG_ATTRIBUTE_NAME = "error_msg";

  /**
   * Reserved access token parameter name.
   */
  protected static final String ACCESS_TOKEN_PARAM_NAME = "access_token";

  /**
   * Logger.
   */
  protected final Logger logger = Logger.getLogger(getClass().getName());

  /**
   * Initializes this Facebook client.
   */
  public BaseRestBAConnector() {
    initializeReadOnlyApiCalls();
    legacyFacebookExceptionMapper = createLegacyFacebookExceptionMapper();
  }

  /**
   * Specifies how we map Old REST API exception types/messages to real Java
   * exceptions.
   * <p>
   * Uses an instance of {@link DefaultLegacyFacebookExceptionMapper} by
   * default.
   *
   * @return An instance of the exception mapper we should use.
   * @since 1.6.3
   */
  protected FacebookExceptionMapper createLegacyFacebookExceptionMapper() {
    return new DefaultLegacyFacebookExceptionMapper();
  }

  /**
   * A canned implementation of {@code FacebookExceptionMapper} that maps Old
   * REST API exceptions.
   *
   * @author <a href="http://restfb.com">Mark Allen</a>
   * @since 1.6.3
   */
  protected static class DefaultLegacyFacebookExceptionMapper implements FacebookExceptionMapper {
    /**
     * Invalid OAuth 2.0 Access Token error code.
     * <p>
     * See http://www.takwing.idv.hk/tech/fb_dev/faq/general/gen_10.html
     */
    protected static final int API_EC_PARAM_ACCESS_TOKEN = 190;

    /**
     * @see com.restfb.exception.FacebookExceptionMapper#exceptionForTypeAndMessage(java.lang.Integer,
     *      java.lang.String, java.lang.String)
     */
    @Override
    public FacebookException exceptionForTypeAndMessage(Integer errorCode, String type, String message) {
      if (errorCode == API_EC_PARAM_ACCESS_TOKEN)
        return new FacebookOAuthException(String.valueOf(errorCode), message);

      // Don't recognize this exception type? Just go with the standard
      // FacebookResponseStatusException.
      return new FacebookResponseStatusException(errorCode, message);
    }
  }

  /**
   * Stores off the set of API calls that support the read-only endpoint.
   * <p>
   * This list was cribbed from the <a
   * href="https://github.com/facebook/php-sdk/blob/master/src/facebook.php"
   * target="_blank">Official PHP Facebook API client</a>.
   *
   * @since 1.6.3
   */
  protected void initializeReadOnlyApiCalls() {
    readOnlyApiCalls.addAll(asList(new String[] { "admin.getallocation", "admin.getappproperties",
        "admin.getbannedusers", "admin.getlivestreamvialink", "admin.getmetrics", "admin.getrestrictioninfo",
        "application.getpublicinfo", "auth.getapppublickey", "auth.getsession", "auth.getsignedpublicsessiondata",
        "comments.get", "connect.getunconnectedfriendscount", "dashboard.getactivity", "dashboard.getcount",
        "dashboard.getglobalnews", "dashboard.getnews", "dashboard.multigetcount", "dashboard.multigetnews",
        "data.getcookies", "events.get", "events.getmembers", "fbml.getcustomtags", "feed.getappfriendstories",
        "feed.getregisteredtemplatebundlebyid", "feed.getregisteredtemplatebundles", "fql.multiquery", "fql.query",
        "friends.arefriends", "friends.get", "friends.getappusers", "friends.getlists", "friends.getmutualfriends",
        "gifts.get", "groups.get", "groups.getmembers", "intl.gettranslations", "links.get", "notes.get",
        "notifications.get", "pages.getinfo", "pages.isadmin", "pages.isappadded", "pages.isfan",
        "permissions.checkavailableapiaccess", "permissions.checkgrantedapiaccess", "photos.get", "photos.getalbums",
        "photos.gettags", "profile.getinfo", "profile.getinfooptions", "stream.get", "stream.getcomments",
        "stream.getfilters", "users.getinfo", "users.getloggedinuser", "users.getstandardinfo",
        "users.hasapppermission", "users.isappuser", "users.isverified", "video.getuploadlimits" }));
  }

  /**
   * If the {@code error_code} JSON field is present, we've got a response
   * status error for this API call. Extracts relevant information from the JSON
   * and throws an exception which encapsulates it for end-user consumption.
   *
   * @param json
   *          The JSON returned by Facebook in response to an API call.
   * @throws FacebookResponseStatusException
   *           If the JSON contains an error code.
   * @throws FacebookJsonMappingException
   *           If an error occurs while processing the JSON.
   */
  protected void throwLegacyFacebookResponseStatusExceptionIfNecessary(String json) {
    try {
      // If this is not an object, it's not an error response.
      if (!json.startsWith("{"))
        return;

      JsonObject errorObject = null;

      // We need to swallow exceptions here because it's possible to get a legit
      // Facebook response that contains illegal JSON (e.g.
      // users.getLoggedInUser returning 1240077) - we're only interested in
      // whether or not there's an error_code field present.
      try {
        errorObject = new JsonObject(json);
      } catch (JsonException e) {}

      if (errorObject == null || !errorObject.has(LEGACY_ERROR_CODE_ATTRIBUTE_NAME))
        return;

      throw legacyFacebookExceptionMapper.exceptionForTypeAndMessage(
        errorObject.getInt(LEGACY_ERROR_CODE_ATTRIBUTE_NAME), null,
        errorObject.getString(LEGACY_ERROR_MSG_ATTRIBUTE_NAME));
    } catch (JsonException e) {
      throw new FacebookJsonMappingException("Unable to process the Facebook API response", e);
    }
  }

  /**
   * Appends the given {@code parameter} to the given {@code parameters} array.
   *
   * @param parameter
   *          The parameter value to append.
   * @param parameters
   *          The parameters to which the given {@code parameter} is appended.
   * @return A new array which contains both {@code parameter} and
   *         {@code parameters}.
   */
  protected Parameter[] parametersWithAdditionalParameter(Parameter parameter, Parameter... parameters) {
    Parameter[] updatedParameters = new Parameter[parameters.length + 1];
    System.arraycopy(parameters, 0, updatedParameters, 0, parameters.length);
    updatedParameters[parameters.length] = parameter;
    return updatedParameters;
  }

  /**
   * Given a map of query names to queries, verify that it contains valid data
   * and convert it to a JSON object string.
   *
   * @param queries
   *          The query map to convert.
   * @return The {@code queries} in JSON string format.
   * @throws IllegalArgumentException
   *           If the provided {@code queries} are invalid.
   */
  protected String queriesToJson(Map<String, String> queries) {
    verifyParameterPresence("queries", queries);

    if (queries.keySet().size() == 0)
      throw new IllegalArgumentException("You must specify at least one query.");

    JsonObject jsonObject = new JsonObject();

    for (Entry<String, String> entry : queries.entrySet()) {
      if (isBlank(entry.getKey()) || isBlank(entry.getValue()))
        throw new IllegalArgumentException("Provided queries must have non-blank keys and values. " + "You provided: "
            + queries);

      try {
        jsonObject.put(trimToEmpty(entry.getKey()), trimToEmpty(entry.getValue()));
      } catch (JsonException e) {
        // Shouldn't happen unless bizarre input is provided
        throw new IllegalArgumentException("Unable to convert " + queries + " to JSON.", e);
      }
    }

    return jsonObject.toString();
  }

  /**
   * Gets the URL-encoded version of the given {@code value} for the parameter
   * named {@code name}.
   * <p>
   * Includes special-case handling for access token parameters where we check
   * if the token is already URL-encoded - if so, we don't encode again. All
   * other parameter types are always URL-encoded.
   *
   * @param name
   *          The name of the parameter whose value should be URL-encoded and
   *          returned.
   * @param value
   *          The value of the parameter which should be URL-encoded and
   *          returned.
   * @return The URL-encoded version of the given {@code value}.
   */
  protected String urlEncodedValueForParameterName(String name, String value) {
    // Special handling for access_token -
    // '%7C' is the pipe character and will be present in any access_token
    // parameter that's already URL-encoded. If we see this combination, don't
    // URL-encode. Otherwise, URL-encode as normal.
    return ACCESS_TOKEN_PARAM_NAME.equals(name) && value.contains("%7C") ? value : urlEncode(value);
  }

  /**
   * Given an api call (e.g. "me" or "fql.query"), returns the correct FB API
   * endpoint to use.
   * <p>
   * Useful for returning the read-only API endpoint where possible.
   *
   * @param apiCall
   *          The FB API call (Graph or Old REST API) for which we'd like an
   *          endpoint.
   * @param hasAttachment
   *          Are we including a multipart file when making this API call?
   * @return An absolute endpoint URL to communicate with.
   * @since 1.6.3
   */
  protected abstract String createEndpointForApiCall(String apiCall, boolean hasAttachment);

  /**
   * Returns the base read-only endpoint URL.
   *
   * @return The base read-only endpoint URL.
   * @since 1.6.3
   */
  protected abstract String getFacebookReadOnlyEndpointUrl();

  /**
   * Verifies that the provided parameter names don't collide with the ones we
   * internally pass along to Facebook.
   *
   * @param parameters
   *          The parameters to check.
   * @throws IllegalArgumentException
   *           If there's a parameter name collision.
   */
  protected void verifyParameterLegality(Parameter... parameters) {
    for (Parameter parameter : parameters)
      if (illegalParamNames.contains(parameter.name))
        throw new IllegalArgumentException("Parameter '" + parameter.name + "' is reserved for RestFB use - "
            + "you cannot specify it yourself.");
  }

  /**
   * Ensures that {@code parameter} isn't {@code null} or an empty string.
   *
   * @param parameterName
   *          The name of the parameter (to be used in exception message).
   * @param parameter
   *          The parameter to check.
   * @throws IllegalArgumentException
   *           If {@code parameter} is {@code null} or an empty string.
   */
  protected void verifyParameterPresence(String parameterName, String parameter) {
    verifyParameterPresence(parameterName, (Object) parameter);
    if (parameter.trim().length() == 0)
      throw new IllegalArgumentException("The '" + parameterName + "' parameter cannot be an empty string.");
  }

  /**
   * Ensures that {@code parameter} isn't {@code null}.
   *
   * @param parameterName
   *          The name of the parameter (to be used in exception message).
   * @param parameter
   *          The parameter to check.
   * @throws IllegalArgumentException
   *           If {@code parameter} is {@code null}.
   */
  protected void verifyParameterPresence(String parameterName, Object parameter) {
    if (parameter == null)
      throw new NullPointerException("The '" + parameterName + "' parameter cannot be null.");
  }
}
TOP

Related Classes of ar.com.restba.connectors.BaseRestBAConnector$DefaultLegacyFacebookExceptionMapper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.