pl.sgorecki.facebook.marketing.ads.impl.FacebookAdsErrorHandler.java Source code

Java tutorial

Introduction

Here is the source code for pl.sgorecki.facebook.marketing.ads.impl.FacebookAdsErrorHandler.java

Source

/*
 * Copyright 2015 the original author or authors.
 *
 * 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
 * limitations under the License.
 */
package pl.sgorecki.facebook.marketing.ads.impl;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.social.*;
import org.springframework.social.facebook.api.FacebookError;
import org.springframework.web.client.DefaultResponseErrorHandler;
import pl.sgorecki.facebook.marketing.ads.InvalidCampaignStatusException;
import pl.sgorecki.facebook.marketing.ads.InvalidParameterException;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import static org.springframework.social.facebook.api.FacebookErrors.*;

/**
 * Subclass of {@link DefaultResponseErrorHandler} that handles errors from Facebook's
 * Graph API, interpreting them into appropriate exceptions.
 *
 * @author Craig Walls
 */
class FacebookAdsErrorHandler extends DefaultResponseErrorHandler {

    // Rate limiting errors
    public static final int USER_APP_TOO_MANY_CALLS = 613;
    // Ad Level Rate Limit error
    public static final int AD_CREATION_LIMIT_EXCEEDED = 1487225;

    private static final String FACEBOOK_PROVIDER_ID = "facebook-ads";
    private final static Log logger = LogFactory.getLog(FacebookAdsErrorHandler.class);

    @Override
    public void handleError(ClientHttpResponse response) throws IOException {
        FacebookError error = extractErrorFromResponse(response);
        handleFacebookError(response.getStatusCode(), error);
    }

    /**
     * Examines the error data returned from Facebook and throws the most applicable exception.
     */
    void handleFacebookError(HttpStatus statusCode, FacebookError error) {
        if (error.getCode() != null) {
            int code = error.getCode();

            if (code == UNKNOWN) {
                throw new UncategorizedApiException(FACEBOOK_PROVIDER_ID, error.getMessage(), null);
            } else if (code == SERVICE) {
                throw new ServerException(FACEBOOK_PROVIDER_ID, error.getMessage());
            } else if (code == TOO_MANY_CALLS || code == USER_TOO_MANY_CALLS
                    || code == EDIT_FEED_TOO_MANY_USER_CALLS || code == EDIT_FEED_TOO_MANY_USER_ACTION_CALLS
                    || code == USER_APP_TOO_MANY_CALLS || code == AD_CREATION_LIMIT_EXCEEDED) {
                throw new RateLimitExceededException(FACEBOOK_PROVIDER_ID);
            } else if (code == PERMISSION_DENIED || isUserPermissionError(code)) {
                throw new InsufficientPermissionException(FACEBOOK_PROVIDER_ID);
            } else if (code == PARAM_SESSION_KEY || code == PARAM_SIGNATURE) {
                throw new InvalidAuthorizationException(FACEBOOK_PROVIDER_ID, error.getMessage());
            } else if (code == PARAM_ACCESS_TOKEN && error.getSubcode() == null) {
                throw new InvalidAuthorizationException(FACEBOOK_PROVIDER_ID, error.getMessage());
            } else if (code == PARAM_ACCESS_TOKEN && error.getSubcode() == 463) {
                throw new ExpiredAuthorizationException(FACEBOOK_PROVIDER_ID);
            } else if (code == PARAM_ACCESS_TOKEN) {
                throw new RevokedAuthorizationException(FACEBOOK_PROVIDER_ID, error.getMessage());
            } else if (code == MESG_DUPLICATE) {
                throw new DuplicateStatusException(FACEBOOK_PROVIDER_ID, error.getMessage());
            } else if (code == DATA_OBJECT_NOT_FOUND || code == PATH_UNKNOWN) {
                throw new ResourceNotFoundException(FACEBOOK_PROVIDER_ID, error.getMessage());
            } else if (code == PARAM && error.getSubcode() != null && error.getSubcode() == 1487564) {
                throw new InvalidCampaignStatusException(FACEBOOK_PROVIDER_ID, error.getUserMessage());
            } else if (code == PARAM && error.getSubcode() != null) {
                throw new InvalidParameterException(FACEBOOK_PROVIDER_ID, error.getUserMessage());
            } else {
                throw new UncategorizedApiException(FACEBOOK_PROVIDER_ID, error.getMessage(), null);
            }
        }

    }

    private FacebookError extractErrorFromResponse(ClientHttpResponse response) throws IOException {
        String json = readResponseJson(response);
        try {
            ObjectMapper mapper = new ObjectMapper(new JsonFactory());
            JsonNode jsonNode = mapper.readValue(json, JsonNode.class);
            if (jsonNode.has("error")) {
                JsonNode errorNode = jsonNode.get("error");
                Integer code = errorNode.has("code") ? errorNode.get("code").intValue() : null;
                String type = errorNode.has("type") ? errorNode.get("type").asText() : null;
                String message = errorNode.has("message") ? errorNode.get("message").asText() : null;
                Integer subcode = errorNode.has("error_subcode") ? errorNode.get("error_subcode").intValue() : null;
                String userMessage = errorNode.has("error_user_msg") ? errorNode.get("error_user_msg").asText()
                        : null;
                String userTitle = errorNode.has("error_user_title") ? errorNode.get("error_user_title").asText()
                        : null;

                FacebookError error = new FacebookError(code, type, message, subcode, userMessage, userTitle);
                if (logger.isDebugEnabled()) {
                    logger.debug("Facebook error: ");
                    logger.debug("   CODE        : " + error.getCode());
                    logger.debug("   TYPE        : " + error.getType());
                    logger.debug("   SUBCODE     : " + error.getSubcode());
                    logger.debug("   MESSAGE     : " + error.getMessage());
                    logger.debug("   USER TITLE  : " + error.getUserTitle());
                    logger.debug("   USER MESSAGE: " + error.getUserMessage());
                }
                return error;
            }
        } catch (JsonParseException e) {
            return null;
        }
        return null;
    }

    private String readResponseJson(ClientHttpResponse response) throws IOException {
        String json = readFully(response.getBody());
        if (logger.isDebugEnabled()) {
            logger.debug("Error from Facebook: " + json);
        }
        return json;
    }

    private String readFully(InputStream in) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        StringBuilder sb = new StringBuilder();
        while (reader.ready()) {
            sb.append(reader.readLine());
        }
        return sb.toString();
    }
}