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.rest.client;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import java.io.*;
022import java.util.*;
023
024/**
025 * A transport-layer HTTP response.
026 *
027 * <p>
028 * Produced by {@link HttpTransport#execute(TransportRequest)} and consumed by the higher-level
029 * {@code RestResponse}.
030 *
031 * <p>
032 * Callers <b>must</b> close this object (it implements {@link Closeable}) after consuming the response body;
033 * transport implementations use the close callback to release connection-pool resources.
034 *
035 * @since 9.2.1
036 */
037@SuppressWarnings({
038   "resource" // body and closeCallback are owned by TransportResponse and released in close()
039})
040public final class TransportResponse implements Closeable {
041
042   private final int statusCode;
043   private final String reasonPhrase;
044   private final List<TransportHeader> headers;
045   private final InputStream body;
046   private final Closeable closeCallback;
047
048   private TransportResponse(Builder builder) {
049      this.statusCode = builder.statusCode;
050      this.reasonPhrase = builder.reasonPhrase;
051      this.headers = List.copyOf(builder.headers);
052      this.body = builder.body;
053      this.closeCallback = builder.closeCallback != null ? builder.closeCallback : () -> {};
054   }
055
056   /** Returns a new {@link Builder}. */
057   public static Builder builder() {
058      return new Builder();
059   }
060
061   /**
062    * Returns the HTTP status code.
063    *
064    * @return The status code (e.g. {@code 200}).
065    */
066   public int getStatusCode() {
067      return statusCode;
068   }
069
070   /**
071    * Returns the reason phrase (e.g. {@code "OK"}), or {@code null} if absent.
072    *
073    * @return The reason phrase, possibly <jk>null</jk>.
074    */
075   public String getReasonPhrase() {
076      return reasonPhrase;
077   }
078
079   /**
080    * Returns all response headers.
081    *
082    * @return An unmodifiable list. Never <jk>null</jk>.
083    */
084   public List<TransportHeader> getHeaders() {
085      return headers;
086   }
087
088   /**
089    * Returns the first header with the given name (case-insensitive), or {@code null} if absent.
090    *
091    * @param name The header name. Must not be <jk>null</jk>.
092    * @return The first matching header, or <jk>null</jk> if absent.
093    */
094   public TransportHeader getFirstHeader(String name) {
095      return headers.stream()
096         .filter(h -> eqic(h.name(), name))
097         .findFirst()
098         .orElse(null);
099   }
100
101   /**
102    * Returns the response body stream, or {@code null} if the response has no body.
103    *
104    * <p>
105    * Callers must not close this stream directly — close the {@link TransportResponse} instead.
106    *
107    * @return The body stream, possibly <jk>null</jk>.
108    */
109   public InputStream getBody() {
110      return body;
111   }
112
113   @Override /* Closeable */
114   public void close() throws IOException {
115      closeCallback.close();
116   }
117
118   // -----------------------------------------------------------------------------------------------------------------
119   // Builder
120   // -----------------------------------------------------------------------------------------------------------------
121
122   /**
123    * Fluent builder for {@link TransportResponse}.
124    *
125    * <p>
126    * Primarily used by transport implementations and tests.
127    *
128    * @since 9.2.1
129    */
130   public static final class Builder {
131
132      int statusCode;
133      String reasonPhrase;
134      final List<TransportHeader> headers = l();
135      InputStream body;
136      Closeable closeCallback;
137
138      private Builder() {}
139
140      /**
141       * Sets the HTTP status code.
142       *
143       * @param value The status code.
144       * @return This object.
145       */
146      public Builder statusCode(int value) {
147         statusCode = value;
148         return this;
149      }
150
151      /**
152       * Sets the reason phrase.
153       *
154       * @param value The reason phrase. May be <jk>null</jk>.
155       * @return This object.
156       */
157      public Builder reasonPhrase(String value) {
158         reasonPhrase = value;
159         return this;
160      }
161
162      /**
163       * Appends a response header.
164       *
165       * @param name The header name. Must not be <jk>null</jk>.
166       * @param value The header value. Must not be <jk>null</jk>.
167       * @return This object.
168       */
169      public Builder header(String name, String value) {
170         headers.add(TransportHeader.of(name, value));
171         return this;
172      }
173
174      /**
175       * Sets the response body stream.
176       *
177       * @param value The stream. May be <jk>null</jk>.
178       * @return This object.
179       */
180      public Builder body(InputStream value) {
181         body = value;
182         return this;
183      }
184
185      /**
186       * Sets a callback invoked when {@link TransportResponse#close()} is called.
187       *
188       * <p>
189       * Transport implementations use this to return connections to the pool.
190       *
191       * @param value The close callback. May be <jk>null</jk>.
192       * @return This object.
193       */
194      public Builder closeCallback(Closeable value) {
195         closeCallback = value;
196         return this;
197      }
198
199      /**
200       * Builds and returns the {@link TransportResponse}.
201       *
202       * @return A new instance. Never <jk>null</jk>.
203       */
204      public TransportResponse build() {
205         return new TransportResponse(this);
206      }
207   }
208}