001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.rest; 014 015import java.io.*; 016import java.util.*; 017 018import javax.servlet.http.*; 019 020import org.apache.juneau.httppart.bean.*; 021import org.apache.juneau.rest.util.*; 022 023/** 024 * A wrapper around a single HttpServletRequest/HttpServletResponse pair. 025 */ 026public class RestCall { 027 028 private HttpServletRequest req; 029 private HttpServletResponse res; 030 private RestRequest rreq; 031 private RestResponse rres; 032 private UrlPathInfo urlPathInfo; 033 private String pathInfoUndecoded; 034 private long startTime = System.currentTimeMillis(); 035 private RestCallLogger logger; 036 private RestCallLoggerConfig loggerConfig; 037 038 /** 039 * Constructor. 040 * 041 * @param req The incoming HTTP servlet request object. 042 * @param res The incoming HTTP servlet response object. 043 */ 044 public RestCall(HttpServletRequest req, HttpServletResponse res) { 045 request(req).response(res); 046 } 047 048 //------------------------------------------------------------------------------------------------------------------ 049 // Request/response objects. 050 //------------------------------------------------------------------------------------------------------------------ 051 052 /** 053 * Overrides the request object on the REST call. 054 * 055 * @param req The new HTTP servlet request. 056 * @return This object (for method chaining). 057 */ 058 public RestCall request(HttpServletRequest req) { 059 this.req = req; 060 this.urlPathInfo = null; 061 this.pathInfoUndecoded = null; 062 return this; 063 } 064 065 /** 066 * Overrides the response object on the REST call. 067 * 068 * @param res The new HTTP servlet response. 069 * @return This object (for method chaining). 070 */ 071 public RestCall response(HttpServletResponse res) { 072 this.res = res; 073 return this; 074 } 075 076 /** 077 * Set the {@link RestRequest} object on this REST call. 078 * 079 * @param rreq The {@link RestRequest} object on this REST call. 080 * @return This object (for method chaining). 081 */ 082 public RestCall restRequest(RestRequest rreq) { 083 request(rreq); 084 this.rreq = rreq; 085 return this; 086 } 087 088 /** 089 * Set the {@link RestResponse} object on this REST call. 090 * 091 * @param rres The {@link RestResponse} object on this REST call. 092 * @return This object (for method chaining). 093 */ 094 public RestCall restResponse(RestResponse rres) { 095 response(rres); 096 this.rres = rres; 097 this.rreq.setResponse(rres); 098 return this; 099 } 100 101 /** 102 * Returns the HTTP servlet request of this REST call. 103 * 104 * @return the HTTP servlet request of this REST call. 105 */ 106 public HttpServletRequest getRequest() { 107 return req; 108 } 109 110 /** 111 * Returns the HTTP servlet response of this REST call. 112 * 113 * @return the HTTP servlet response of this REST call. 114 */ 115 public HttpServletResponse getResponse() { 116 return res; 117 } 118 119 /** 120 * Returns the REST request of this REST call. 121 * 122 * @return the REST request of this REST call. 123 */ 124 public RestRequest getRestRequest() { 125 return rreq; 126 } 127 128 /** 129 * Returns the REST response of this REST call. 130 * 131 * @return the REST response of this REST call. 132 */ 133 public RestResponse getRestResponse() { 134 return rres; 135 } 136 137 //------------------------------------------------------------------------------------------------------------------ 138 // Setters. 139 //------------------------------------------------------------------------------------------------------------------ 140 141 /** 142 * Sets the logger to use when logging this call. 143 * 144 * @param logger The logger to use when logging this call. 145 * @return This object (for method chaining). 146 */ 147 public RestCall logger(RestCallLogger logger) { 148 this.logger = logger; 149 return this; 150 } 151 152 /** 153 * Sets the logging configuration to use when logging this call. 154 * 155 * @param config The logging configuration to use when logging this call. 156 * @return This object (for method chaining). 157 */ 158 public RestCall loggerConfig(RestCallLoggerConfig config) { 159 this.loggerConfig = config; 160 return this; 161 } 162 163 /** 164 * Enables or disabled debug mode on this call. 165 * 166 * @param b The debug flag value. 167 * @return This object (for method chaining). 168 * @throws IOException Occurs if request body could not be cached into memory. 169 */ 170 public RestCall debug(boolean b) throws IOException { 171 if (b) { 172 req = CachingHttpServletRequest.wrap(req); 173 res = CachingHttpServletResponse.wrap(res); 174 } 175 req.setAttribute("Debug", b); 176 return this; 177 } 178 179 /** 180 * Sets the HTTP status on this call. 181 * 182 * @param code The status code. 183 * @return This object (for method chaining). 184 */ 185 public RestCall status(int code) { 186 res.setStatus(code); 187 return this; 188 } 189 190 /** 191 * Identifies that an exception occurred during this call. 192 * 193 * @param e The thrown exception. 194 * @return This object (for method chaining). 195 */ 196 public RestCall exception(Throwable e) { 197 req.setAttribute("Exception", e); 198 return this; 199 } 200 201 /** 202 * Sets metadata about the response. 203 * 204 * @param meta The metadata about the response. 205 * @return This object (for method chaining). 206 */ 207 public RestCall responseMeta(ResponseBeanMeta meta) { 208 if (rres != null) 209 rres.setResponseMeta(meta); 210 return this; 211 } 212 213 /** 214 * Sets the output object to serialize as the response of this call. 215 * 216 * @param output The response output POJO. 217 * @return This object (for method chaining). 218 */ 219 public RestCall output(Object output) { 220 if (rres != null) 221 rres.setOutput(output); 222 return this; 223 } 224 225 //------------------------------------------------------------------------------------------------------------------ 226 // Lifecycle methods. 227 //------------------------------------------------------------------------------------------------------------------ 228 229 /** 230 * Called at the end of a call to finish any remaining tasks such as flushing buffers and logging the response. 231 * 232 * @return This object (for method chaining). 233 */ 234 public RestCall finish() { 235 try { 236 res.flushBuffer(); 237 req.setAttribute("ExecTime", System.currentTimeMillis() - startTime); 238 if (rreq != null) 239 rreq.close(); 240 } catch (Exception e) { 241 exception(e); 242 } 243 if (logger != null) 244 logger.log(loggerConfig, req, res); 245 return this; 246 } 247 248 249 //------------------------------------------------------------------------------------------------------------------ 250 // Pass-through convenience methods. 251 //------------------------------------------------------------------------------------------------------------------ 252 253 /** 254 * Shortcut for calling <c>getRequest().getServletPath()</c>. 255 * 256 * @return The request servlet path. 257 */ 258 public String getServletPath() { 259 return req.getServletPath(); 260 } 261 262 /** 263 * Returns the request path info as a {@link UrlPathInfo} bean. 264 * 265 * @return The request path info as a {@link UrlPathInfo} bean. 266 */ 267 public UrlPathInfo getUrlPathInfo() { 268 if (urlPathInfo == null) 269 urlPathInfo = new UrlPathInfo(getPathInfoUndecoded()); 270 return urlPathInfo; 271 } 272 273 /** 274 * Shortcut for calling <c>getRequest().getPathInfo()</c>. 275 * 276 * @return The request servlet path info. 277 */ 278 public String getPathInfo() { 279 return req.getPathInfo(); 280 } 281 282 /** 283 * Same as {@link #getPathInfo()} but doesn't decode encoded characters. 284 * 285 * @return The undecoded request servlet path info. 286 */ 287 public String getPathInfoUndecoded() { 288 if (pathInfoUndecoded == null) 289 pathInfoUndecoded = RestUtils.getPathInfoUndecoded(req); 290 return pathInfoUndecoded; 291 } 292 293 /** 294 * Returns the HTTP method name. 295 * 296 * @return The HTTP method name, always uppercased. 297 */ 298 public String getMethod() { 299 if (rreq != null) 300 return rreq.getMethod().toUpperCase(Locale.ENGLISH); 301 return req.getMethod().toUpperCase(Locale.ENGLISH); 302 } 303 304 /** 305 * Shortcut for calling <c>getRequest().getStatus()</c>. 306 * 307 * @return The response status code. 308 */ 309 public int getStatus() { 310 return res.getStatus(); 311 } 312 313 /** 314 * Shortcut for calling <c>getRestResponse().hasOutput()</c>. 315 * 316 * @return <jk>true</jk> if response has output. 317 */ 318 public boolean hasOutput() { 319 if (rres != null) 320 return rres.hasOutput(); 321 return false; 322 } 323 324 /** 325 * Shortcut for calling <c>getRestResponse().getOutput()</c>. 326 * 327 * @return The response output. 328 */ 329 public Object getOutput() { 330 if (rres != null) 331 return rres.getOutput(); 332 return null; 333 } 334}