001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.http.response; 018 019import static org.apache.juneau.assertions.Assertions.*; 020import static org.apache.juneau.http.HttpEntities.*; 021 022import java.net.*; 023import java.util.*; 024 025import org.apache.http.*; 026import org.apache.http.impl.*; 027import org.apache.http.params.*; 028import org.apache.juneau.annotation.*; 029import org.apache.juneau.common.utils.*; 030import org.apache.juneau.http.*; 031import org.apache.juneau.http.header.*; 032import org.apache.juneau.internal.*; 033 034/** 035 * Basic implementation of the {@link HttpResponse} interface. 036 * 037 * <p> 038 * Although this class implements the various setters defined on the {@link HttpResponse} interface, it's in general 039 * going to be more efficient to set the status/headers/content of this bean through the builder. 040 * 041 * <p> 042 * If the <c>unmodifiable</c> flag is set on this bean, calls to the setters will throw {@link UnsupportedOperationException} exceptions. 043 * 044 * <h5 class='section'>Notes:</h5><ul> 045 * <li class='warn'>Beans are not thread safe unless they're marked as unmodifiable. 046 * </ul> 047 * 048 * <h5 class='section'>See Also:</h5><ul> 049 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommonBasics">juneau-rest-common Basics</a> 050 * </ul> 051 */ 052@BeanIgnore /* Use toString() to serialize */ 053public class BasicHttpResponse implements HttpResponse { 054 055 //----------------------------------------------------------------------------------------------------------------- 056 // Instance 057 //----------------------------------------------------------------------------------------------------------------- 058 059 BasicStatusLine statusLine = new BasicStatusLine(); 060 HeaderList headers = HeaderList.create(); 061 HttpEntity content; 062 boolean unmodifiable; 063 064 /** 065 * Constructor. 066 * 067 * @param statusLine The HTTP status line. 068 */ 069 public BasicHttpResponse(BasicStatusLine statusLine) { 070 setStatusLine(statusLine.copy()); 071 } 072 073 /** 074 * Copy constructor. 075 * 076 * @param copyFrom The bean to copy from. 077 */ 078 public BasicHttpResponse(BasicHttpResponse copyFrom) { 079 statusLine = copyFrom.statusLine.copy(); 080 headers = copyFrom.headers.copy(); 081 content = copyFrom.content; 082 } 083 084 /** 085 * Constructor. 086 * 087 * <p> 088 * This is the constructor used when parsing an HTTP response. 089 * 090 * @param response The HTTP response to copy from. Must not be <jk>null</jk>. 091 */ 092 public BasicHttpResponse(HttpResponse response) { 093 setHeaders(response.getAllHeaders()); 094 setContent(response.getEntity()); 095 setStatusLine(response.getStatusLine()); 096 } 097 098 //----------------------------------------------------------------------------------------------------------------- 099 // Properties 100 //----------------------------------------------------------------------------------------------------------------- 101 102 /** 103 * Specifies whether this bean should be unmodifiable. 104 * <p> 105 * When enabled, attempting to set any properties on this bean will cause an {@link UnsupportedOperationException}. 106 * 107 * @return This object. 108 */ 109 public BasicHttpResponse setUnmodifiable() { 110 unmodifiable = true; 111 return this; 112 } 113 114 /** 115 * Returns <jk>true</jk> if this bean is unmodifiable. 116 * 117 * @return <jk>true</jk> if this bean is unmodifiable. 118 */ 119 public boolean isUnmodifiable() { 120 return unmodifiable; 121 } 122 123 /** 124 * Throws an {@link UnsupportedOperationException} if the unmodifiable flag is set on this bean. 125 */ 126 protected final void assertModifiable() { 127 if (unmodifiable) 128 throw new UnsupportedOperationException("Bean is read-only"); 129 } 130 131 //----------------------------------------------------------------------------------------------------------------- 132 // BasicStatusLine setters. 133 //----------------------------------------------------------------------------------------------------------------- 134 135 /** 136 * Sets the protocol version on the status line. 137 * 138 * <p> 139 * If not specified, <js>"HTTP/1.1"</js> will be used. 140 * 141 * @param value The new value. 142 * @return This object. 143 */ 144 public BasicHttpResponse setStatusLine(BasicStatusLine value) { 145 assertModifiable(); 146 statusLine = value.copy(); 147 return this; 148 } 149 150 /** 151 * Sets the status code on the status line. 152 * 153 * <p> 154 * If not specified, <c>0</c> will be used. 155 * 156 * @param value The new value. 157 * @return This object. 158 */ 159 public BasicHttpResponse setStatusCode2(int value) { 160 statusLine.setStatusCode(value); 161 return this; 162 } 163 164 /** 165 * Sets the protocol version on the status line. 166 * 167 * <p> 168 * If not specified, <js>"HTTP/1.1"</js> will be used. 169 * 170 * @param value The new value. 171 * @return This object. 172 */ 173 public BasicHttpResponse setProtocolVersion(ProtocolVersion value) { 174 statusLine.setProtocolVersion(value); 175 return this; 176 } 177 178 /** 179 * Sets the reason phrase on the status line. 180 * 181 * <p> 182 * If not specified, the reason phrase will be retrieved from the reason phrase catalog 183 * using the locale on this builder. 184 * 185 * @param value The new value. 186 * @return This object. 187 */ 188 public BasicHttpResponse setReasonPhrase2(String value) { 189 statusLine.setReasonPhrase(value); 190 return this; 191 } 192 193 /** 194 * Sets the reason phrase catalog used to retrieve reason phrases. 195 * 196 * <p> 197 * If not specified, uses {@link EnglishReasonPhraseCatalog}. 198 * 199 * @param value The new value. 200 * @return This object. 201 */ 202 public BasicHttpResponse setReasonPhraseCatalog(ReasonPhraseCatalog value) { 203 statusLine.setReasonPhraseCatalog(value); 204 return this; 205 } 206 207 /** 208 * Sets the locale used to retrieve reason phrases. 209 * 210 * <p> 211 * If not specified, uses {@link Locale#getDefault()}. 212 * 213 * @param value The new value. 214 * @return This object. 215 */ 216 public BasicHttpResponse setLocale2(Locale value) { 217 statusLine.setLocale(value); 218 return this; 219 } 220 221 //----------------------------------------------------------------------------------------------------------------- 222 // BasicHeaderGroup setters. 223 //----------------------------------------------------------------------------------------------------------------- 224 225 /** 226 * Returns access to the underlying builder for the headers. 227 * 228 * @return The underlying builder for the headers. 229 */ 230 public HeaderList getHeaders() { 231 return headers; 232 } 233 234 /** 235 * Sets the specified headers on this response. 236 * 237 * @param value The new value. 238 * @return This object. 239 */ 240 public BasicHttpResponse setHeaders(HeaderList value) { 241 assertModifiable(); 242 headers = value.copy(); 243 return this; 244 } 245 246 /** 247 * Sets the specified header to the end of the headers in this builder. 248 * 249 * @param value The header to add. <jk>null</jk> values are ignored. 250 * @return This object. 251 */ 252 public BasicHttpResponse setHeader2(Header value) { 253 headers.set(value); 254 return this; 255 } 256 257 /** 258 * Sets the specified header to the end of the headers in this builder. 259 * 260 * @param name The header name. 261 * @param value The header value. 262 * @return This object. 263 */ 264 public BasicHttpResponse setHeader2(String name, String value) { 265 headers.set(name, value); 266 return this; 267 } 268 269 /** 270 * Sets the specified headers to the end of the headers in this builder. 271 * 272 * @param values The headers to add. <jk>null</jk> values are ignored. 273 * @return This object. 274 */ 275 public BasicHttpResponse setHeaders2(Header...values) { 276 headers.set(values); 277 return this; 278 } 279 280 /** 281 * Sets the specified headers to the end of the headers in this builder. 282 * 283 * @param values The headers to add. <jk>null</jk> values are ignored. 284 * @return This object. 285 */ 286 public BasicHttpResponse setHeaders(List<Header> values) { 287 headers.set(values); 288 return this; 289 } 290 291 /** 292 * Specifies the value for the <c>Location</c> header. 293 * 294 * @param value The new header location. 295 * @return This object. 296 */ 297 public BasicHttpResponse setLocation(URI value) { 298 headers.set(Location.of(value)); 299 return this; 300 } 301 302 /** 303 * Specifies the value for the <c>Location</c> header. 304 * 305 * @param value The new header location. 306 * @return This object. 307 */ 308 public BasicHttpResponse setLocation(String value) { 309 headers.set(Location.of(value)); 310 return this; 311 } 312 313 //----------------------------------------------------------------------------------------------------------------- 314 // Body setters. 315 //----------------------------------------------------------------------------------------------------------------- 316 317 /** 318 * Sets the body on this response. 319 * 320 * @param value The body on this response. 321 * @return This object. 322 */ 323 public BasicHttpResponse setContent(String value) { 324 return setContent(stringEntity(value)); 325 } 326 327 /** 328 * Sets the body on this response. 329 * 330 * @param value The body on this response. 331 * @return This object. 332 */ 333 public BasicHttpResponse setContent(HttpEntity value) { 334 assertModifiable(); 335 this.content = value; 336 return this; 337 } 338 339 /** 340 * Asserts that the specified HTTP response has the same status code as the one on the status line of this bean. 341 * 342 * @param response The HTTP response to check. Must not be <jk>null</jk>. 343 * @throws AssertionError If status code is not what was expected. 344 */ 345 protected void assertStatusCode(HttpResponse response) throws AssertionError { 346 Utils.assertArgNotNull("response", response); 347 int expected = getStatusLine().getStatusCode(); 348 int actual = response.getStatusLine().getStatusCode(); 349 assertInteger(actual).setMsg("Unexpected status code. Expected:[{0}], Actual:[{1}]", expected, actual).is(expected); 350 } 351 352 @Override /* Object */ 353 public String toString() { 354 StringBuilder sb = new StringBuilder().append(statusLine).append(' ').append(headers); 355 if (content != null) 356 sb.append(' ').append(content); 357 return sb.toString(); 358 } 359 360 @Override /* HttpMessage */ 361 public ProtocolVersion getProtocolVersion() { 362 return statusLine.getProtocolVersion(); 363 } 364 365 @Override /* HttpMessage */ 366 public boolean containsHeader(String name) { 367 return headers.contains(name); 368 } 369 370 @Override /* HttpMessage */ 371 public Header[] getHeaders(String name) { 372 return headers.getAll(name); 373 } 374 375 @Override /* HttpMessage */ 376 public Header getFirstHeader(String name) { 377 return headers.getFirst(name).orElse(null); 378 } 379 380 @Override /* HttpMessage */ 381 public Header getLastHeader(String name) { 382 return headers.getLast(name).orElse(null); 383 } 384 385 @Override /* HttpMessage */ 386 public Header[] getAllHeaders() { 387 return headers.getAll(); 388 } 389 390 @Override /* HttpMessage */ 391 public void addHeader(Header value) { 392 headers.append(value); 393 } 394 395 @Override /* HttpMessage */ 396 public void addHeader(String name, String value) { 397 headers.append(name, value); 398 } 399 400 @Override /* HttpMessage */ 401 public void setHeader(Header value) { 402 headers.set(value); 403 } 404 405 @Override /* HttpMessage */ 406 public void setHeader(String name, String value) { 407 headers.set(name, value); 408 } 409 410 @Override /* HttpMessage */ 411 public void setHeaders(Header[] values) { 412 headers.removeAll().append(values); 413 } 414 415 @Override /* HttpMessage */ 416 public void removeHeader(Header value) { 417 headers.remove(value); 418 } 419 420 @Override /* HttpMessage */ 421 public void removeHeaders(String name) { 422 headers.remove(name); 423 } 424 425 @Override /* HttpMessage */ 426 public HeaderIterator headerIterator() { 427 return headers.headerIterator(); 428 } 429 430 @Override /* HttpMessage */ 431 public HeaderIterator headerIterator(String name) { 432 return headers.headerIterator(name); 433 } 434 435 @SuppressWarnings("deprecation") 436 @Override /* HttpMessage */ 437 public HttpParams getParams() { 438 return null; 439 } 440 441 @SuppressWarnings("deprecation") 442 @Override /* HttpMessage */ 443 public void setParams(HttpParams params) { 444 } 445 446 @Override /* HttpMessage */ 447 public StatusLine getStatusLine() { 448 return statusLine; 449 } 450 451 @Override /* HttpMessage */ 452 public void setStatusLine(StatusLine value) { 453 setStatusLine(value.getProtocolVersion(), value.getStatusCode(), value.getReasonPhrase()); 454 } 455 456 @Override /* HttpMessage */ 457 public void setStatusLine(ProtocolVersion ver, int code) { 458 statusLine.setProtocolVersion(ver).setStatusCode(code); 459 } 460 461 @Override /* HttpMessage */ 462 public void setStatusLine(ProtocolVersion ver, int code, String reason) { 463 statusLine.setProtocolVersion(ver).setReasonPhrase(reason).setStatusCode(code); 464 } 465 466 @Override /* HttpMessage */ 467 public void setStatusCode(int code) throws IllegalStateException { 468 statusLine.setStatusCode(code); 469 } 470 471 @Override /* HttpMessage */ 472 public void setReasonPhrase(String reason) throws IllegalStateException { 473 statusLine.setReasonPhrase(reason); 474 } 475 476 @Override /* HttpMessage */ 477 public HttpEntity getEntity() { 478 // Constructing a StringEntity is somewhat expensive, so don't create it unless it's needed. 479 if (content == null) 480 content = stringEntity(getStatusLine().getReasonPhrase()); 481 return content; 482 } 483 484 @Override /* HttpMessage */ 485 public void setEntity(HttpEntity entity) { 486 assertModifiable(); 487 this.content = entity; 488 } 489 490 @Override /* HttpMessage */ 491 public Locale getLocale() { 492 return statusLine.getLocale(); 493 } 494 495 @Override /* HttpMessage */ 496 public void setLocale(Locale loc) { 497 statusLine.setLocale(loc); 498 } 499}