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; 023 024import static com.restfb.util.StringUtils.isBlank; 025import static com.restfb.util.StringUtils.trimToEmpty; 026import static java.lang.String.format; 027 028import java.io.IOException; 029import java.util.ArrayList; 030import java.util.List; 031import java.util.Optional; 032 033import com.restfb.types.FacebookReelAttachment; 034import com.restfb.util.StringUtils; 035 036/** 037 * Specifies how a class that sends {@code HTTP} requests to the Facebook API endpoint must operate. 038 * 039 * @author <a href="http://restfb.com">Mark Allen</a> 040 */ 041public interface WebRequestor { 042 /** 043 * Encapsulates an HTTP response body and status code. 044 * 045 * @author <a href="http://restfb.com">Mark Allen</a> 046 */ 047 class Response { 048 /** 049 * HTTP response status code (e.g. 200). 050 */ 051 private final Integer statusCode; 052 053 /** 054 * HTTP response body as text. 055 */ 056 private final String body; 057 058 /** 059 * Creates a response with the given HTTP status code and response body as text. 060 * 061 * @param statusCode 062 * The HTTP status code of the response. 063 * @param body 064 * The response body as text. 065 */ 066 public Response(Integer statusCode, String body) { 067 this.statusCode = statusCode; 068 this.body = trimToEmpty(body); 069 } 070 071 /** 072 * Gets the HTTP status code. 073 * 074 * @return The HTTP status code. 075 */ 076 public Integer getStatusCode() { 077 return statusCode; 078 } 079 080 /** 081 * Gets the HTTP response body as text. 082 * 083 * @return The HTTP response body as text. 084 */ 085 public String getBody() { 086 return body; 087 } 088 089 /** 090 * @see java.lang.Object#toString() 091 */ 092 @Override 093 public String toString() { 094 if (isBlank(getBody())) { 095 return format("HTTP status code %d and an empty response body.", getStatusCode()); 096 } 097 return format("HTTP status code %d and response body: %s", getStatusCode(), getBody()); 098 } 099 } 100 101 /** 102 * encapsulates the HTTP Request configuration 103 */ 104 class Request { 105 106 private final String url; 107 108 private final Optional<String> headerAccessToken; 109 110 private String parameters; 111 112 private Body body; 113 114 private List<BinaryAttachment> binaryAttachments; 115 116 /** 117 * Simple http request with url and a header access token 118 * 119 * @param url 120 * the endpoint the request ist directed to 121 * @param headerAccessToken 122 * the HTTP header access token (may be {@code null}) 123 */ 124 public Request(String url, String headerAccessToken) { 125 this(url, headerAccessToken, null); 126 } 127 128 /** 129 * Simple http request with url and a header access token 130 * 131 * @param url 132 * the endpoint the request ist directed to 133 * @param headerAccessToken 134 * the HTTP header access token (may be {@code null}) 135 * @param parameters 136 * the query parameter string 137 */ 138 public Request(String url, String headerAccessToken, String parameters) { 139 this(url, headerAccessToken, parameters, null); 140 } 141 142 /** 143 * Simple http request with url and a header access token 144 * 145 * @param url 146 * the endpoint the request ist directed to 147 * @param headerAccessToken 148 * the HTTP header access token (may be {@code null}) 149 * @param parameters 150 * the query parameter string 151 * @param attachments 152 * list of binary attachments 153 */ 154 public Request(String url, String headerAccessToken, String parameters, List<BinaryAttachment> attachments) { 155 this.url = url; 156 this.headerAccessToken = Optional.ofNullable(headerAccessToken); 157 this.parameters = parameters; 158 setBinaryAttachments(attachments); 159 } 160 161 public String getUrl() { 162 return url; 163 } 164 165 public String getHeaderAccessToken() { 166 return headerAccessToken.orElse(null); 167 } 168 169 public boolean hasHeaderAccessToken() { 170 return headerAccessToken.isPresent(); 171 } 172 173 public String getParameters() { 174 return parameters; 175 } 176 177 public List<BinaryAttachment> getBinaryAttachments() { 178 return Optional.ofNullable(binaryAttachments).orElse(new ArrayList<>()); 179 } 180 181 public void setBinaryAttachments(List<BinaryAttachment> binaryAttachments) { 182 this.binaryAttachments = Optional.ofNullable(binaryAttachments).orElse(new ArrayList<>()); 183 } 184 185 public String getFullUrl() { 186 if (!StringUtils.isBlank(parameters)) { 187 if (url != null && url.contains("?")) { 188 return url + "&" + parameters; 189 } 190 return url + "?" + parameters; 191 } 192 return url; 193 } 194 195 @Override 196 public String toString() { 197 return format("Request to url %s with parameters %s. Header access token: %b", getUrl(), getParameters(), 198 hasHeaderAccessToken()); 199 } 200 201 public void setBody(Body body) { 202 this.body = body; 203 } 204 205 public Body getBody() { 206 return body; 207 } 208 209 public boolean hasBody() { 210 return body != null; 211 } 212 213 public boolean isReelUpload() { 214 List<BinaryAttachment> attachments = getBinaryAttachments(); 215 if (attachments.size() == 1) { 216 return attachments.get(0).isFacebookReel(); 217 } 218 219 return false; 220 } 221 222 public Optional<FacebookReelAttachment> getReel() { 223 if (isReelUpload()) { 224 return Optional.of((FacebookReelAttachment) getBinaryAttachments().get(0)); 225 } 226 227 return Optional.empty(); 228 } 229 } 230 231 /** 232 * Given a Facebook API endpoint URL, execute a {@code GET} against it. 233 * 234 * @param request 235 * The request data for the {@code GET} request 236 * @return HTTP response data. 237 * @throws IOException 238 * If an error occurs while performing the {@code GET} operation. 239 * @since 1.5 240 */ 241 Response executeGet(Request request) throws IOException; 242 243 /** 244 * Given a Facebook API endpoint URL and parameter string, execute a {@code POST} to the endpoint URL. 245 * 246 * @param request 247 * The request data used for the {@code POST} request. 248 * @return HTTP response data. 249 * @throws IOException 250 * If an error occurs while performing the {@code POST}. 251 */ 252 Response executePost(Request request) throws IOException; 253 254 /** 255 * Given a Facebook API endpoint URL and parameter string, execute a {@code DELETE} to the endpoint URL. 256 * 257 * @param request 258 * The request data used for the {@code DELETE} request. 259 * @return HTTP response data. 260 * @throws IOException 261 * If an error occurs while performing the {@code DELETE}. 262 */ 263 Response executeDelete(Request request) throws IOException; 264 265 /** 266 * Provides access to the facebook header information. 267 * <p> 268 * The fields <code>x-fb-rev</code>, <code>x-fb-trace-id</code> and <code>x-fb-debug</code> are checked and returned 269 * in a single container of the type {@link DebugHeaderInfo} 270 * 271 * @return container with the explained facebook debug header information 272 */ 273 DebugHeaderInfo getDebugHeaderInfo(); 274}