001/*
002 * Copyright (c) 2010-2024 Mark Allen, Norbert Bartels.
003 *
004 * Permission is hereby granted, free of charge, to any person obtaining a copy
005 * of this software and associated documentation files (the "Software"), to deal
006 * in the Software without restriction, including without limitation the rights
007 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
008 * copies of the Software, and to permit persons to whom the Software is
009 * furnished to do so, subject to the following conditions:
010 *
011 * The above copyright notice and this permission notice shall be included in
012 * all copies or substantial portions of the Software.
013 *
014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
017 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
019 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
020 * THE SOFTWARE.
021 */
022package com.restfb.exception;
023
024import static java.lang.String.format;
025
026import java.util.Optional;
027
028import com.restfb.json.JsonObject;
029
030/**
031 * Indicates that the Facebook Graph API endpoint returned JSON which indicates an error condition.
032 * <p>
033 * Example:<code>
034  {
035      "error": {
036        "type": "Exception",
037        "message": "...",
038        "code": 210,
039        "error_subcode": 123,
040        "error_user_title": "A title",
041        "error_user_msg": "A message"
042      }
043  } </code>
044 * 
045 * @author <a href="http://restfb.com">Mark Allen</a>
046 * @since 1.5
047 */
048public class FacebookGraphException extends FacebookErrorMessageException {
049  private static final long serialVersionUID = 1L;
050
051  /**
052   * The Facebook Graph API error type.
053   */
054  private final String errorType;
055
056  /**
057   * The Facebook API error message.
058   */
059  private final String errorMessage;
060
061  /**
062   * The Facebook API error user title.
063   */
064  private final String errorUserTitle;
065
066  /**
067   * The Facebook API error user message.
068   */
069  private final String errorUserMessage;
070
071  /**
072   * The Facebook API error code.
073   */
074  private final Integer errorCode;
075
076  /**
077   * The Facebook API error subcode.
078   */
079  private final Integer errorSubcode;
080
081  /**
082   * The HTTP status code returned by the server.
083   */
084  private final Integer httpStatusCode;
085
086  private final Boolean isTransient;
087
088  /**
089   * Creates an exception with the given error type and message.
090   * 
091   * @param errorType
092   *          Value of the Facebook response attribute {@code error.type}.
093   * @param errorMessage
094   *          Value of the Facebook response attribute {@code error.message}.
095   * @param errorCode
096   *          Value of the Facebook response attribute {@code error.code}.
097   * @param errorSubcode
098   *          Value of the Facebook response attribute {@code error.error_subcode}.
099   * @param httpStatusCode
100   *          The HTTP status code returned by the server, e.g. 500.
101   * @param errorUserTitle
102   *          Value of the Facebook response attribute {@code error.error_user_title}.
103   * @param errorUserMessage
104   *          Value of the Facebook response attribute {@code error.error_user_msg}.
105   * @param isTransient
106   * 
107   */
108  public FacebookGraphException(String errorType, String errorMessage, Integer errorCode, Integer errorSubcode,
109      Integer httpStatusCode, String errorUserTitle, String errorUserMessage, Boolean isTransient,
110      JsonObject rawError) {
111    super(format("Received Facebook error response of type %s: %s (code %s, subcode %s) '%s - %s'", errorType,
112      errorMessage, errorCode, errorSubcode, errorUserTitle, errorUserMessage));
113    this.errorType = errorType;
114    this.errorMessage = errorMessage;
115    this.errorCode = errorCode;
116    this.errorSubcode = errorSubcode;
117    this.httpStatusCode = httpStatusCode;
118    this.errorUserTitle = errorUserTitle;
119    this.errorUserMessage = errorUserMessage;
120    this.isTransient = isTransient;
121    setRawErrorJson(rawError);
122  }
123
124  /**
125   * Gets the Facebook Graph API error type.
126   * 
127   * @return The Facebook Graph API error type.
128   */
129  public String getErrorType() {
130    return errorType;
131  }
132
133  /**
134   * Gets the Facebook Graph API error message.
135   * 
136   * @return The Facebook Graph API error message.
137   */
138  public String getErrorMessage() {
139    return errorMessage;
140  }
141
142  /**
143   * Gets the Facebook API error code.
144   * 
145   * @return The Facebook API error code.
146   */
147  public Integer getErrorCode() {
148    return errorCode;
149  }
150
151  /**
152   * Gets the Facebook API error subcode.
153   * 
154   * @return The Facebook API error subcode.
155   */
156  public Integer getErrorSubcode() {
157    return errorSubcode;
158  }
159
160  /**
161   * Gets the HTTP status code returned by the server.
162   * 
163   * @return The HTTP status code returned by the server.
164   * @since 1.6.10
165   */
166  public Integer getHttpStatusCode() {
167    return httpStatusCode;
168  }
169
170  /**
171   * Gets the Facebook API error user title.
172   * 
173   * @return the Facebook API error user title
174   * @since 1.7.1
175   */
176  public String getErrorUserTitle() {
177    return errorUserTitle;
178  }
179
180  /**
181   * Gets the Facebook API error user message.
182   * 
183   * @return the Facebook API error user message
184   * @since 1.7.1
185   */
186  public String getErrorUserMessage() {
187    return errorUserMessage;
188  }
189
190  public Boolean getIsTransient() {
191    return isTransient;
192  }
193
194  /**
195   * Gets the Facebook API error {@code fbtrace_id}.
196   *
197   * Internal support identifier. When reporting a bug related to a Graph API call, include the fbtrace_id to help us
198   * find log data for debugging.
199   *
200   * @return the Facebook API error {@code fbtrace_id}
201   */
202  public String getFbtraceId() {
203    if (getRawErrorJson() != null && getRawErrorJson().get("error").isObject()) {
204      JsonObject errorJson = getRawErrorJson().get("error").asObject();
205      return errorJson.getString("fbtrace_id", "");
206    }
207
208    return "";
209  }
210
211  /**
212   * returns the error data as defined <a href="https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes/">here</a> as JsonObject.
213   * We use no special object to be future proof and allow other error JSONs to use this.
214   * @return Optional<JsonObject> with the JsonObject
215   */
216  public Optional<JsonObject> getErrorData() {
217    if (getRawErrorJson() != null && getRawErrorJson().get("error").isObject()) {
218      JsonObject errorJson = getRawErrorJson().get("error").asObject();
219      if (errorJson.contains("error_data")) {
220        return Optional.of(errorJson.get("error_data").asObject());
221      }
222    }
223
224    return Optional.empty();
225  }
226
227  /**
228   * special method to get the String result to the given field of the error_data field
229   * @param field field you like to fetch
230   * @return String with the result or empty String if not available
231   */
232  public String getErrorData(String field) {
233    Optional<JsonObject> errorDataOpt = getErrorData();
234    if (errorDataOpt.isPresent()) {
235      return errorDataOpt.get().getString(field, "");
236    }
237
238    return "";
239  }
240}