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.client2; 014 015import org.apache.juneau.parser.*; 016 017import static org.apache.juneau.httppart.HttpPartType.*; 018 019import java.lang.reflect.*; 020import java.text.*; 021import java.util.*; 022import java.util.logging.*; 023 024import org.apache.http.*; 025import org.apache.http.message.*; 026import org.apache.http.params.*; 027import org.apache.http.util.*; 028import org.apache.juneau.*; 029import org.apache.juneau.assertions.*; 030import org.apache.juneau.http.header.*; 031import org.apache.juneau.httppart.*; 032import org.apache.juneau.httppart.bean.*; 033import org.apache.juneau.internal.*; 034import org.apache.juneau.utils.*; 035 036/** 037 * Represents a response from a remote REST resource. 038 * 039 * <p> 040 * Instances of this class are created by calling the {@link RestRequest#run()} method. 041 * 042 * <ul class='seealso'> 043 * <li class='jc'>{@link RestClient} 044 * <li class='link'>{@doc juneau-rest-client} 045 * </ul> 046 */ 047public class RestResponse implements HttpResponse { 048 049 private final RestClient client; 050 private final RestRequest request; 051 private final HttpResponse response; 052 private final Parser parser; 053 HttpPartParserSession partParser; 054 private RestResponseBody responseBody; 055 private boolean isClosed; 056 057 /** 058 * Constructor. 059 * 060 * @param client The RestClient that created this response. 061 * @param request The REST request. 062 * @param response The HTTP response. Can be <jk>null</jk>. 063 * @param parser The overridden parser passed into {@link RestRequest#parser(Parser)}. 064 */ 065 protected RestResponse(RestClient client, RestRequest request, HttpResponse response, Parser parser) { 066 this.client = client; 067 this.request = request; 068 this.parser = parser; 069 this.response = response == null ? new BasicHttpResponse(null, 0, null) : response; 070 this.responseBody = new RestResponseBody(client, request, this, parser); 071 this.partParser = client.getPartParserSession(); 072 } 073 074 /** 075 * Returns the request object that created this response object. 076 * 077 * @return The request object that created this response object. 078 */ 079 public RestRequest getRequest() { 080 return request; 081 } 082 083 //------------------------------------------------------------------------------------------------------------------ 084 // Setters 085 //------------------------------------------------------------------------------------------------------------------ 086 087 /** 088 * Consumes the response body. 089 * 090 * <p> 091 * This is equivalent to closing the input stream. 092 * 093 * @return This object (for method chaining). 094 * @throws RestCallException If one of the {@link RestCallInterceptor RestCallInterceptors} threw an exception. 095 */ 096 public RestResponse consume() throws RestCallException { 097 close(); 098 return this; 099 } 100 101 //------------------------------------------------------------------------------------------------------------------ 102 // Status line 103 //------------------------------------------------------------------------------------------------------------------ 104 105 /** 106 * Same as {@link #getStatusLine()} but sets the value in a mutable for fluent calls. 107 * 108 * @param m The mutable to set the status line in. 109 * @return This object (for method chaining). 110 */ 111 public RestResponse getStatusLine(Mutable<StatusLine> m) { 112 m.set(getStatusLine()); 113 return this; 114 } 115 116 /** 117 * Returns the status code of the response. 118 * 119 * Shortcut for calling <code>getStatusLine().getStatusCode()</code>. 120 * 121 * @return The status code of the response. 122 */ 123 public int getStatusCode() { 124 return getStatusLine().getStatusCode(); 125 } 126 127 /** 128 * Same as {@link #getStatusCode()} but sets the value in a mutable for fluent calls. 129 * 130 * @param m The mutable to set the status code in. 131 * @return This object (for method chaining). 132 */ 133 public RestResponse getStatusCode(Mutable<Integer> m) { 134 m.set(getStatusCode()); 135 return this; 136 } 137 138 /** 139 * Returns the status line reason phrase of the response. 140 * 141 * Shortcut for calling <code>getStatusLine().getReasonPhrase()</code>. 142 * 143 * @return The status line reason phrase of the response. 144 */ 145 public String getReasonPhrase() { 146 return getStatusLine().getReasonPhrase(); 147 } 148 149 /** 150 * Same as {@link #getReasonPhrase()} but sets the value in a mutable for fluent calls. 151 * 152 * @param m The mutable to set the status line reason phrase in. 153 * @return This object (for method chaining). 154 */ 155 public RestResponse getReasonPhrase(Mutable<String> m) { 156 m.set(getReasonPhrase()); 157 return this; 158 } 159 160 //------------------------------------------------------------------------------------------------------------------ 161 // Status line assertions 162 //------------------------------------------------------------------------------------------------------------------ 163 164 /** 165 * Provides the ability to perform fluent-style assertions on the response {@link StatusLine} object. 166 * 167 * <h5 class='section'>Examples:</h5> 168 * <p class='bcode w800'> 169 * MyBean <jv>bean</jv> = <jv>client</jv> 170 * .get(<jsf>URI</jsf>) 171 * .run() 172 * .assertStatus().code().is(200) 173 * .getBody().as(MyBean.<jk>class</jk>); 174 * </p> 175 * 176 * @return A new fluent assertion object. 177 * @throws RestCallException If REST call failed. 178 */ 179 public RestResponseStatusLineAssertion assertStatus() throws RestCallException { 180 return new RestResponseStatusLineAssertion(getStatusLine(), this); 181 } 182 183 /** 184 * Provides the ability to perform fluent-style assertions on the response status code. 185 * 186 * <h5 class='section'>Examples:</h5> 187 * <p class='bcode w800'> 188 * MyBean <jv>bean</jv> = <jv>client</jv> 189 * .get(<jsf>URI</jsf>) 190 * .run() 191 * .assertCode().is(200) 192 * .getBody().as(MyBean.<jk>class</jk>); 193 * </p> 194 * 195 * @return A new fluent assertion object. 196 * @throws RestCallException If REST call failed. 197 */ 198 public FluentIntegerAssertion<RestResponse> assertCode() throws RestCallException { 199 return assertStatus().code(); 200 } 201 202 //------------------------------------------------------------------------------------------------------------------ 203 // Headers 204 //------------------------------------------------------------------------------------------------------------------ 205 206 /** 207 * Shortcut for calling <code>getHeader(name).asString()</code>. 208 * 209 * @param name The header name. 210 * @return The header value, or <jk>null</jk> if header was not found. 211 */ 212 public String getStringHeader(String name) { 213 return getHeader(name).asString(); 214 } 215 216 /** 217 * Shortcut for calling <code>getHeader(name).asStringOrElse(def)</code>. 218 * 219 * @param name The header name. 220 * @param def The default value if the header was not found. 221 * @return The header value, or the default if header was not found. 222 */ 223 public String getStringHeader(String name, String def) { 224 return getHeader(name).asStringOrElse(def); 225 } 226 227 /** 228 * Returns the last header with the specified name. 229 * 230 * Unlike {@link #getFirstHeader(String)} and {@link #getLastHeader(String)}, this method returns an empty 231 * {@link RestResponseHeader} object instead of returning <jk>null</jk>. This allows it to be used more easily 232 * in fluent calls. 233 * 234 * @param name The header name. 235 * @return The header. Never <jk>null</jk>. 236 */ 237 public RestResponseHeader getHeader(String name) { 238 return new RestResponseHeader(request, this, getLastHeader(name)).parser(partParser); 239 } 240 241 /** 242 * Shortcut for retrieving the response charset from the <l>Content-Type</l> header. 243 * 244 * @return The response charset. 245 * @throws RestCallException If REST call failed. 246 */ 247 public String getCharacterEncoding() throws RestCallException { 248 String s = getContentType().getParameter("charset"); 249 return StringUtils.isEmpty(s) ? "utf-8" : s; 250 } 251 252 /** 253 * Shortcut for retrieving the response content type from the <l>Content-Type</l> header. 254 * 255 * <p> 256 * This is equivalent to calling <c>getHeader(<js>"Content-Type"</js>).as(ContentType.<jk>class</jk>)</c>. 257 * 258 * @return The response charset. 259 * @throws RestCallException If REST call failed. 260 */ 261 public ContentType getContentType() throws RestCallException { 262 return getHeader("Content-Type").as(ContentType.class); 263 } 264 265 /** 266 * Provides the ability to perform fluent-style assertions on a response header. 267 * 268 * <h5 class='section'>Examples:</h5> 269 * <p class='bcode w800'> 270 * <jc>// Validates the content type header is provided.</jc> 271 * <jv>client</jv> 272 * .get(<jsf>URI</jsf>) 273 * .run() 274 * .assertHeader(<js>"Content-Type"</js>).exists(); 275 * 276 * <jc>// Validates the content type is JSON.</jc> 277 * <jv>client</jv> 278 * .get(<jsf>URI</jsf>) 279 * .run() 280 * .assertHeader(<js>"Content-Type"</js>).is(<js>"application/json"</js>); 281 * 282 * <jc>// Validates the content type is JSON using test predicate.</jc> 283 * <jv>client</jv> 284 * .get(<jsf>URI</jsf>) 285 * .run() 286 * .assertHeader(<js>"Content-Type"</js>).passes(<jv>x</jv> -> <jv>x</jv>.equals(<js>"application/json"</js>)); 287 * 288 * <jc>// Validates the content type is JSON by just checking for substring.</jc> 289 * <jv>client</jv> 290 * .get(<jsf>URI</jsf>) 291 * .run() 292 * .assertHeader(<js>"Content-Type"</js>).contains(<js>"json"</js>); 293 * 294 * <jc>// Validates the content type is JSON using regular expression.</jc> 295 * <jv>client</jv> 296 * .get(<jsf>URI</jsf>) 297 * .run() 298 * .assertHeader(<js>"Content-Type"</js>).matches(<js>".*json.*"</js>); 299 * 300 * <jc>// Validates the content type is JSON using case-insensitive regular expression.</jc> 301 * <jv>client</jv> 302 * .get(<jsf>URI</jsf>) 303 * .run() 304 * .assertHeader(<js>"Content-Type"</js>).matches(<js>".*json.*"</js>, <jsf>CASE_INSENSITIVE</jsf>); 305 * </p> 306 * 307 * <p> 308 * The assertion test returns the original response object allowing you to chain multiple requests like so: 309 * <p class='bcode w800'> 310 * <jc>// Validates the header and converts it to a bean.</jc> 311 * MediaType <jv>mediaType</jv> = <jv>client</jv> 312 * .get(<jsf>URI</jsf>) 313 * .run() 314 * .assertHeader(<js>"Content-Type"</js>).exists() 315 * .assertHeader(<js>"Content-Type"</js>).matches(<js>".*json.*"</js>) 316 * .getHeader(<js>"Content-Type"</js>).as(MediaType.<jk>class</jk>); 317 * </p> 318 * 319 * @param name The header name. 320 * @return A new fluent assertion object. 321 */ 322 public FluentStringAssertion<RestResponse> assertStringHeader(String name) { 323 return getHeader(name).assertString(); 324 } 325 326 /** 327 * Provides the ability to perform fluent-style assertions on an integer response header. 328 * 329 * <h5 class='section'>Examples:</h5> 330 * <p class='bcode w800'> 331 * <jc>// Validates that the response content age is greater than 1.</jc> 332 * <jv>client</jv> 333 * .get(<jsf>URI</jsf>) 334 * .run() 335 * .assertIntegerHeader(<js>"Age"</js>).isGreaterThan(1); 336 * </p> 337 * 338 * @param name The header name. 339 * @return A new fluent assertion object. 340 */ 341 public FluentIntegerAssertion<RestResponse> assertIntegerHeader(String name) { 342 return getHeader(name).assertInteger(); 343 } 344 345 /** 346 * Provides the ability to perform fluent-style assertions on a long response header. 347 * 348 * <h5 class='section'>Examples:</h5> 349 * <p class='bcode w800'> 350 * <jc>// Validates that the response body is not too large.</jc> 351 * <jv>client</jv> 352 * .get(<jsf>URI</jsf>) 353 * .run() 354 * .assertLongHeader(<js>"Length"</js>).isLessThan(100000); 355 * </p> 356 * 357 * @param name The header name. 358 * @return A new fluent assertion object. 359 */ 360 public FluentLongAssertion<RestResponse> assertLongHeader(String name) { 361 return getHeader(name).assertLong(); 362 } 363 364 /** 365 * Provides the ability to perform fluent-style assertions on a date response header. 366 * 367 * <h5 class='section'>Examples:</h5> 368 * <p class='bcode w800'> 369 * <jc>// Validates that the response content is not expired.</jc> 370 * <jv>client</jv> 371 * .get(<jsf>URI</jsf>) 372 * .run() 373 * .assertDateHeader(<js>"Expires"</js>).isAfterNow(); 374 * </p> 375 * 376 * @param name The header name. 377 * @return A new fluent assertion object. 378 */ 379 public FluentZonedDateTimeAssertion<RestResponse> assertDateHeader(String name) { 380 return getHeader(name).assertDate(); 381 } 382 383 /** 384 * Provides the ability to perform fluent-style assertions on a date response header. 385 * 386 * <h5 class='section'>Examples:</h5> 387 * <p class='bcode w800'> 388 * <jc>// Validates that the response content is not expired.</jc> 389 * <jv>client</jv> 390 * .get(<jsf>URI</jsf>) 391 * .run() 392 * .assertCsvArrayHeader(<js>"Allow"</js>).contains(<js>"GET"</js>); 393 * </p> 394 * 395 * @param name The header name. 396 * @return A new fluent assertion object. 397 */ 398 public FluentListAssertion<RestResponse> assertCsvArrayHeader(String name) { 399 return getHeader(name).assertCsvArray(); 400 } 401 402 /** 403 * Provides the ability to perform fluent-style assertions on the response character encoding. 404 * 405 * <h5 class='section'>Examples:</h5> 406 * <p class='bcode w800'> 407 * <jc>// Validates that the response content charset is UTF-8.</jc> 408 * <jv>client</jv> 409 * .get(<jsf>URI</jsf>) 410 * .run() 411 * .assertCharset().is(<js>"utf-8"</js>); 412 * </p> 413 * 414 * @return A new fluent assertion object. 415 * @throws RestCallException If REST call failed. 416 */ 417 public FluentStringAssertion<RestResponse> assertCharset() throws RestCallException { 418 return new FluentStringAssertion<>(getCharacterEncoding(), this); 419 } 420 421 /** 422 * Provides the ability to perform fluent-style assertions on the response content type. 423 * 424 * <h5 class='section'>Examples:</h5> 425 * <p class='bcode w800'> 426 * <jc>// Validates that the response content is JSON.</jc> 427 * <jv>client</jv> 428 * .get(<jsf>URI</jsf>) 429 * .run() 430 * .assertContentType().is(<js>"application/json"</js>); 431 * </p> 432 * 433 * <p> 434 * Note that this is equivalent to the following code: 435 * <p class='bcode w800'> 436 * <jc>// Validates that the response content is JSON.</jc> 437 * <jv>client</jv> 438 * .get(<jsf>URI</jsf>) 439 * .run() 440 * .assertHeader(<js>"Content-Type"</js>).is(<js>"application/json"</js>); 441 * </p> 442 * 443 * @return A new fluent assertion object. 444 */ 445 public FluentStringAssertion<RestResponse> assertContentType() { 446 return getHeader("Content-Type").assertString(); 447 } 448 449 //------------------------------------------------------------------------------------------------------------------ 450 // Body 451 //------------------------------------------------------------------------------------------------------------------ 452 453 /** 454 * Returns the body of the response. 455 * 456 * This method can be called multiple times returning the same response body each time. 457 * 458 * @return The body of the response. 459 */ 460 public RestResponseBody getBody() { 461 return responseBody; 462 } 463 464 /** 465 * Provides the ability to perform fluent-style assertions on this response body. 466 * 467 * <h5 class='section'>Examples:</h5> 468 * <p class='bcode w800'> 469 * <jc>// Validates the response body equals the text "OK".</jc> 470 * <jv>client</jv> 471 * .get(<jsf>URI</jsf>) 472 * .run() 473 * .assertBody().equals(<js>"OK"</js>); 474 * 475 * <jc>// Validates the response body contains the text "OK".</jc> 476 * <jv>client</jv> 477 * .get(<jsf>URI</jsf>) 478 * .run() 479 * .assertBody().contains(<js>"OK"</js>); 480 * 481 * <jc>// Validates the response body passes a predicate test.</jc> 482 * <jv>client</jv> 483 * .get(<jsf>URI</jsf>) 484 * .run() 485 * .assertBody().passes(<jv>x</jv> -> <jv>x</jv>.contains(<js>"OK"</js>)); 486 * 487 * <jc>// Validates the response body matches a regular expression.</jc> 488 * <jv>client</jv> 489 * .get(<jsf>URI</jsf>) 490 * .run() 491 * .assertBody().matches(<js>".*OK.*"</js>); 492 * 493 * <jc>// Validates the response body matches a regular expression using regex flags.</jc> 494 * <jv>client</jv> 495 * .get(<jsf>URI</jsf>) 496 * .run() 497 * .assertBody().matches(<js>".*OK.*"</js>, <jsf>MULTILINE</jsf> & <jsf>CASE_INSENSITIVE</jsf>); 498 * 499 * <jc>// Validates the response body matches a regular expression in the form of an existing Pattern.</jc> 500 * Pattern <jv>p</jv> = Pattern.<jsm>compile</jsm>(<js>".*OK.*"</js>); 501 * <jv>client</jv> 502 * .get(<jsf>URI</jsf>) 503 * .run() 504 * .assertBody().matches(<jv>p</jv>); 505 * </p> 506 * 507 * <p> 508 * The assertion test returns the original response object allowing you to chain multiple requests like so: 509 * <p class='bcode w800'> 510 * <jc>// Validates the response body matches a regular expression.</jc> 511 * MyBean <jv>bean</jv> = <jv>client</jv> 512 * .get(<jsf>URI</jsf>) 513 * .run() 514 * .assertBody().matches(<js>".*OK.*"</js>); 515 * .assertBody().doesNotMatch(<js>".*ERROR.*"</js>) 516 * .getBody().as(MyBean.<jk>class</jk>); 517 * </p> 518 * 519 * <ul class='notes'> 520 * <li> 521 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 522 * <li> 523 * When using this method, the body is automatically cached by calling the {@link RestResponseBody#cache()}. 524 * <li> 525 * The input stream is automatically closed after this call. 526 * </ul> 527 * 528 * @return A new fluent assertion object. 529 * @throws RestCallException If REST call failed. 530 */ 531 public FluentStringAssertion<RestResponse> assertBody() throws RestCallException { 532 return responseBody.cache().assertString(); 533 } 534 535 /** 536 * Provides the ability to perform fluent-style assertions on the bytes of the response body. 537 * 538 * <h5 class='section'>Examples:</h5> 539 * <p class='bcode w800'> 540 * <jc>// Validates the response body equals the text "foo".</jc> 541 * <jv>client</jv> 542 * .get(<jsf>URI</jsf>) 543 * .run() 544 * .assertBodyBytes().hex().is(<js>"666F6F"</js>); 545 * </p> 546 * 547 * <ul class='notes'> 548 * <li> 549 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 550 * <li> 551 * When using this method, the body is automatically cached by calling the {@link RestResponseBody#cache()}. 552 * <li> 553 * The input stream is automatically closed after this call. 554 * </ul> 555 * 556 * @return A new fluent assertion object. 557 * @throws RestCallException If REST call failed. 558 */ 559 public FluentByteArrayAssertion<RestResponse> assertBodyBytes() throws RestCallException { 560 return responseBody.cache().assertBytes(); 561 } 562 563 /** 564 * Provides the ability to perform fluent-style assertions on this response body. 565 * 566 * <p> 567 * <p> 568 * Combines the functionality of {@link RestResponseBody#as(Class)} with {@link #assertBody()} by converting the body to the specified 569 * bean and then serializing it to simplified JSON for easy string comparison. 570 * 571 * <h5 class='section'>Examples:</h5> 572 * <p class='bcode w800'> 573 * <jc>// Validates the response body bean is the expected value.</jc> 574 * <jv>client</jv> 575 * .get(<js>"/myBean"</js>) 576 * .run() 577 * .assertBody(MyBean.<jk>class</jk>).json().is(<js>"{foo:'bar'}"</js>); 578 * </p> 579 * 580 * <ul class='notes'> 581 * <li> 582 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 583 * <li> 584 * When using this method, the body is automatically cached by calling the {@link RestResponseBody#cache()}. 585 * <li> 586 * The input stream is automatically closed after this call. 587 * </ul> 588 * 589 * @param type The object type to create. 590 * @return A new fluent assertion object. 591 * @throws RestCallException If REST call failed. 592 */ 593 public FluentObjectAssertion<RestResponse> assertBody(Class<?> type) throws RestCallException { 594 return responseBody.cache().assertObject(type); 595 } 596 597 /** 598 * Caches the response body so that it can be read as a stream multiple times. 599 * 600 * This is equivalent to calling the following: 601 * <p class='bcode w800'> 602 * getBody().cache(); 603 * </p> 604 * 605 * @return The body of the response. 606 */ 607 public RestResponse cacheBody() { 608 responseBody.cache(); 609 return this; 610 } 611 612 @SuppressWarnings("unchecked") 613 <T> T as(ResponseBeanMeta rbm) { 614 Class<T> c = (Class<T>)rbm.getClassMeta().getInnerClass(); 615 final RestClient rc = this.client; 616 return (T)Proxy.newProxyInstance( 617 c.getClassLoader(), 618 new Class[] { c }, 619 new InvocationHandler() { 620 @Override /* InvocationHandler */ 621 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 622 ResponseBeanPropertyMeta pm = rbm.getProperty(method.getName()); 623 HttpPartParserSession pp = pm.getParser(partParser); 624 HttpPartSchema schema = pm.getSchema(); 625 HttpPartType pt = pm.getPartType(); 626 String name = pm.getPartName(); 627 ClassMeta<?> type = rc.getClassMeta(method.getGenericReturnType()); 628 if (pt == RESPONSE_HEADER) 629 return getHeader(name).parser(pp).schema(schema).as(type); 630 if (pt == RESPONSE_STATUS) 631 return getStatusCode(); 632 return getBody().schema(schema).as(type); 633 } 634 }); 635 } 636 637 /** 638 * Logs a message. 639 * 640 * @param level The log level. 641 * @param t The throwable cause. 642 * @param msg The message with {@link MessageFormat}-style arguments. 643 * @param args The arguments. 644 * @return This object (for method chaining). 645 */ 646 public RestResponse log(Level level, Throwable t, String msg, Object...args) { 647 client.log(level, t, msg, args); 648 return this; 649 } 650 651 /** 652 * Logs a message. 653 * 654 * @param level The log level. 655 * @param msg The message with {@link MessageFormat}-style arguments. 656 * @param args The arguments. 657 * @return This object (for method chaining). 658 */ 659 public RestResponse log(Level level, String msg, Object...args) { 660 client.log(level, msg, args); 661 return this; 662 } 663 664 // ----------------------------------------------------------------------------------------------------------------- 665 // HttpResponse pass-through methods. 666 // ----------------------------------------------------------------------------------------------------------------- 667 668 /** 669 * Obtains the status line of this response. 670 * 671 * The status line can be set using one of the setStatusLine methods, or it can be initialized in a constructor. 672 * 673 * @return The status line, or <jk>null</jk> if not yet set. 674 */ 675 @Override /* HttpResponse */ 676 public StatusLine getStatusLine() { 677 return response.getStatusLine(); 678 } 679 680 /** 681 * Sets the status line of this response. 682 * 683 * @param statusline The status line of this response 684 */ 685 @Override /* HttpResponse */ 686 public void setStatusLine(StatusLine statusline) { 687 response.setStatusLine(statusline); 688 } 689 690 /** 691 * Sets the status line of this response. 692 * 693 * <p> 694 * The reason phrase will be determined based on the current locale. 695 * 696 * @param ver The HTTP version. 697 * @param code The status code. 698 */ 699 @Override /* HttpResponse */ 700 public void setStatusLine(ProtocolVersion ver, int code) { 701 response.setStatusLine(ver, code); 702 } 703 704 /** 705 * Sets the status line of this response with a reason phrase. 706 * 707 * @param ver The HTTP version. 708 * @param code The status code. 709 * @param reason The reason phrase, or <jk>null</jk> to omit. 710 */ 711 @Override /* HttpResponse */ 712 public void setStatusLine(ProtocolVersion ver, int code, String reason) { 713 response.setStatusLine(ver, code, reason); 714 } 715 716 /** 717 * Updates the status line of this response with a new status code. 718 * 719 * @param code The HTTP status code. 720 * @throws IllegalStateException If the status line has not be set. 721 */ 722 @Override /* HttpResponse */ 723 public void setStatusCode(int code) { 724 response.setStatusCode(code); 725 } 726 727 /** 728 * Updates the status line of this response with a new reason phrase. 729 * 730 * @param reason The new reason phrase as a single-line string, or <jk>null</jk> to unset the reason phrase. 731 * @throws IllegalStateException If the status line has not be set. 732 */ 733 @Override /* HttpResponse */ 734 public void setReasonPhrase(String reason) { 735 response.setReasonPhrase(reason); 736 } 737 738 /** 739 * Obtains the message entity of this response. 740 * 741 * <p> 742 * The entity is provided by calling setEntity. 743 * 744 * <ul class='notes'> 745 * <li>Unlike the {@link HttpResponse#getEntity()} method, this method never returns a <jk>null</jk> response. 746 * Instead, <c>getBody().isPresent()</c> can be used to determine whether the response has a body. 747 * </ul> 748 * 749 * @return The response entity. Never <jk>null</jk>. 750 */ 751 @Override /* HttpResponse */ 752 public RestResponseBody getEntity() { 753 return responseBody; 754 } 755 756 /** 757 * Associates a response entity with this response. 758 * 759 * <ul class='notes'> 760 * <li>If an entity has already been set for this response and it depends on an input stream 761 * ({@link HttpEntity#isStreaming()} returns <jk>true</jk>), it must be fully consumed in order to ensure 762 * release of resources. 763 * </ul> 764 * 765 * @param entity The entity to associate with this response, or <jk>null</jk> to unset. 766 */ 767 @Override /* HttpResponse */ 768 public void setEntity(HttpEntity entity) { 769 response.setEntity(entity); 770 this.responseBody = new RestResponseBody(client, request, this, parser); 771 } 772 773 /** 774 * Obtains the locale of this response. 775 * 776 * The locale is used to determine the reason phrase for the status code. 777 * It can be changed using {@link #setLocale(Locale)}. 778 * 779 * @return The locale of this response, never <jk>null</jk>. 780 */ 781 @Override /* HttpResponse */ 782 public Locale getLocale() { 783 return response.getLocale(); 784 } 785 786 /** 787 * Changes the locale of this response. 788 * 789 * @param loc The new locale. 790 */ 791 @Override /* HttpResponse */ 792 public void setLocale(Locale loc) { 793 response.setLocale(loc); 794 } 795 796 /** 797 * Returns the protocol version this message is compatible with. 798 * 799 * @return The protocol version this message is compatible with. 800 */ 801 @Override /* HttpMessage */ 802 public ProtocolVersion getProtocolVersion() { 803 return response.getProtocolVersion(); 804 } 805 806 /** 807 * Checks if a certain header is present in this message. 808 * 809 * <p> 810 * Header values are ignored. 811 * 812 * @param name The header name to check for. 813 * @return <jk>true</jk> if at least one header with this name is present. 814 */ 815 @Override /* HttpMessage */ 816 public boolean containsHeader(String name) { 817 return response.containsHeader(name); 818 } 819 820 /** 821 * Returns all the headers with a specified name of this message. 822 * 823 * Header values are ignored. 824 * <br>Headers are ordered in the sequence they were sent over a connection. 825 * 826 * @param name The name of the headers to return. 827 * @return All the headers with a specified name of this message. 828 */ 829 @Override /* HttpMessage */ 830 public RestResponseHeader[] getHeaders(String name) { 831 Header[] a = response.getHeaders(name); 832 RestResponseHeader[] b = new RestResponseHeader[a.length]; 833 for (int i = 0; i < a.length; i++) 834 b[i] = new RestResponseHeader(request, this, a[i]).parser(partParser); 835 return b; 836 } 837 838 /** 839 * Returns the first header with a specified name of this message. 840 * 841 * Header values are ignored. 842 * <br>If there is more than one matching header in the message the first element of {@link #getHeaders(String)} is returned. 843 * 844 * @param name The name of the header to return. 845 * @return The header, or <jk>null</jk> if there is no matching header in the message. 846 */ 847 @Override /* HttpMessage */ 848 public RestResponseHeader getFirstHeader(String name) { 849 Header h = response.getFirstHeader(name); 850 return h == null ? null : new RestResponseHeader(request, this, h).parser(partParser); 851 } 852 853 /** 854 * Returns the last header with a specified name of this message. 855 * 856 * Header values are ignored. 857 * <br>?If there is more than one matching header in the message the last element of {@link #getHeaders(String)} is returned. 858 * 859 * @param name The name of the header to return. 860 * @return The header, or <jk>null</jk> if there is no matching header in the message. 861 */ 862 @Override /* HttpMessage */ 863 public RestResponseHeader getLastHeader(String name) { 864 Header h = response.getLastHeader(name); 865 return h == null ? null : new RestResponseHeader(request, this, h).parser(partParser); 866 } 867 868 /** 869 * Returns all the headers of this message. 870 * 871 * Headers are ordered in the sequence they were sent over a connection. 872 * 873 * @return All the headers of this message. 874 */ 875 @Override /* HttpMessage */ 876 public RestResponseHeader[] getAllHeaders() { 877 Header[] a = response.getAllHeaders(); 878 RestResponseHeader[] b = new RestResponseHeader[a.length]; 879 for (int i = 0; i < a.length; i++) 880 b[i] = new RestResponseHeader(request, this, a[i]).parser(partParser); 881 return b; 882 } 883 884 /** 885 * Adds a header to this message. 886 * 887 * The header will be appended to the end of the list. 888 * 889 * @param header The header to append. 890 */ 891 @Override /* HttpMessage */ 892 public void addHeader(Header header) { 893 response.addHeader(header); 894 } 895 896 /** 897 * Adds a header to this message. 898 * 899 * The header will be appended to the end of the list. 900 * 901 * @param name The name of the header. 902 * @param value The value of the header. 903 */ 904 @Override /* HttpMessage */ 905 public void addHeader(String name, String value) { 906 response.addHeader(name, value); 907 } 908 909 /** 910 * Overwrites the first header with the same name. 911 * 912 * The new header will be appended to the end of the list, if no header with the given name can be found. 913 * 914 * @param header The header to set. 915 */ 916 @Override /* HttpMessage */ 917 public void setHeader(Header header) { 918 response.setHeader(header); 919 } 920 921 /** 922 * Overwrites the first header with the same name. 923 * 924 * The new header will be appended to the end of the list, if no header with the given name can be found. 925 * 926 * @param name The name of the header. 927 * @param value The value of the header. 928 */ 929 @Override /* HttpMessage */ 930 public void setHeader(String name, String value) { 931 response.setHeader(name, value); 932 } 933 934 /** 935 * Overwrites all the headers in the message. 936 * 937 * @param headers The array of headers to set. 938 */ 939 @Override /* HttpMessage */ 940 public void setHeaders(Header[] headers) { 941 response.setHeaders(headers); 942 } 943 944 /** 945 * Removes a header from this message. 946 * 947 * @param header The header to remove. 948 */ 949 @Override /* HttpMessage */ 950 public void removeHeader(Header header) { 951 response.removeHeader(header); 952 } 953 954 /** 955 * Removes all headers with a certain name from this message. 956 * 957 * @param name The name of the headers to remove. 958 */ 959 @Override /* HttpMessage */ 960 public void removeHeaders(String name) { 961 response.removeHeaders(name); 962 } 963 964 /** 965 * Returns an iterator of all the headers. 966 * 967 * @return {@link Iterator} that returns {@link Header} objects in the sequence they are sent over a connection. 968 */ 969 @Override /* HttpMessage */ 970 public HeaderIterator headerIterator() { 971 return response.headerIterator(); 972 } 973 974 /** 975 * Returns an iterator of the headers with a given name. 976 * 977 * @param name The name of the headers over which to iterate, or <jk>null</jk> for all headers. 978 * @return {@link Iterator} that returns {@link Header} objects with the argument name in the sequence they are sent over a connection. 979 */ 980 @Override /* HttpMessage */ 981 public HeaderIterator headerIterator(String name) { 982 return response.headerIterator(name); 983 } 984 985 /** 986 * Returns the parameters effective for this message as set by {@link #setParams(HttpParams)}. 987 * 988 * @return The parameters effective for this message as set by {@link #setParams(HttpParams)}. 989 * @deprecated Use configuration classes provided <jk>org.apache.http.config</jk> and <jk>org.apache.http.client.config</jk>. 990 */ 991 @Override /* HttpMessage */ 992 @Deprecated 993 public HttpParams getParams() { 994 return response.getParams(); 995 } 996 997 /** 998 * Provides parameters to be used for the processing of this message. 999 * 1000 * @param params The parameters. 1001 * @deprecated Use configuration classes provided <jk>org.apache.http.config</jk> and <jk>org.apache.http.client.config</jk>. 1002 */ 1003 @Override /* HttpMessage */ 1004 @Deprecated 1005 public void setParams(HttpParams params) { 1006 response.setParams(params); 1007 } 1008 1009 void close() throws RestCallException { 1010 if (isClosed) 1011 return; 1012 isClosed = true; 1013 EntityUtils.consumeQuietly(response.getEntity()); 1014 1015 if (request.isDebug() || client.logRequestsPredicate.test(request, this)) { 1016 if (client.logRequests == DetailLevel.SIMPLE) { 1017 client.log(client.logRequestsLevel, "HTTP {0} {1}, {2}", request.getMethod(), request.getURI(), this.getStatusLine()); 1018 } else if (request.isDebug() || client.logRequests == DetailLevel.FULL) { 1019 String output = getBody().asString(); 1020 StringBuilder sb = new StringBuilder(); 1021 sb.append("\n=== HTTP Call (outgoing) ======================================================"); 1022 sb.append("\n=== REQUEST ===\n"); 1023 sb.append(request.getMethod()).append(" ").append(request.getURI()); 1024 sb.append("\n---request headers---"); 1025 for (Header h : request.getAllHeaders()) 1026 sb.append("\n\t").append(h); 1027 if (request.hasHttpEntity()) { 1028 sb.append("\n---request entity---"); 1029 HttpEntity e = request.getHttpEntity(); 1030 if (e.getContentType() != null) 1031 sb.append("\n\t").append(e.getContentType()); 1032 if (e.isRepeatable()) { 1033 try { 1034 sb.append("\n---request content---\n").append(EntityUtils.toString(e)); 1035 } catch (Exception ex) { 1036 sb.append("\n---request content exception---\n").append(ex.getMessage()); 1037 } 1038 } 1039 } 1040 sb.append("\n=== RESPONSE ===\n").append(getStatusLine()); 1041 sb.append("\n---response headers---"); 1042 for (Header h : getAllHeaders()) 1043 sb.append("\n\t").append(h); 1044 sb.append("\n---response content---\n").append(output); 1045 sb.append("\n=== END ======================================================================="); 1046 client.log(client.logRequestsLevel, sb.toString()); 1047 } 1048 } 1049 1050 for (RestCallInterceptor r : request.interceptors) { 1051 try { 1052 r.onClose(request, this); 1053 } catch (RuntimeException | RestCallException e) { 1054 throw e; 1055 } catch (Exception e) { 1056 throw new RestCallException(this, e, "Interceptor throw exception on close"); 1057 } 1058 } 1059 client.onClose(request, this); 1060 } 1061 1062 //------------------------------------------------------------------------------------------------------------------ 1063 // Other methods 1064 //------------------------------------------------------------------------------------------------------------------ 1065 1066 HttpResponse asHttpResponse() { 1067 return response; 1068 } 1069}