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.http;
014
015import static org.apache.juneau.internal.ObjectUtils.*;
016
017import java.util.*;
018import java.util.function.*;
019
020import org.apache.http.*;
021import org.apache.juneau.collections.*;
022import org.apache.juneau.internal.*;
023import org.apache.juneau.http.header.*;
024import org.apache.juneau.http.header.ContentType;
025
026/**
027 * An extension of an {@link HttpEntity} with support for arbitrary headers.
028 *
029 * Provides the following features:
030 * <ul class='spaced-list'>
031 *    <li>
032 *       Default support for various streams and readers.
033 *    <li>
034 *       Content from {@link Supplier Suppliers}.
035 *    <li>
036 *       Caching.
037 *    <li>
038 *       Fluent setters.
039 *    <li>
040 *       Fluent assertions.
041 * </ul>
042 */
043public class BasicHttpResource extends BasicHttpEntity implements HttpResource {
044
045   private final List<Header> headers = AList.of();
046
047   /**
048    * Creator.
049    *
050    * @param content
051    *    The content.
052    *    <br>Can be any of the following:
053    *    <ul>
054    *       <li><c>InputStream</c>
055    *       <li><c>Reader</c> - Converted to UTF-8 bytes.
056    *       <li><c>File</c>
057    *       <li><c>CharSequence</c> - Converted to UTF-8 bytes.
058    *       <li><c><jk>byte</jk>[]</c>.
059    *       <li>A {@link Supplier} of anything on this list.
060    *    </ul>
061    * </ul>
062    * @return A new empty {@link BasicHttpResource} object.
063    */
064   public static BasicHttpResource of(Object content) {
065      return new BasicHttpResource(content);
066   }
067
068   /**
069    * Creator.
070    *
071    * @param content
072    *    The content.
073    *    <br>Can be any of the following:
074    *    <ul>
075    *       <li><c>InputStream</c>
076    *       <li><c>Reader</c> - Converted to UTF-8 bytes.
077    *       <li><c>File</c>
078    *       <li><c>CharSequence</c> - Converted to UTF-8 bytes.
079    *       <li><c><jk>byte</jk>[]</c>.
080    *       <li>A {@link Supplier} of anything on this list.
081    *    </ul>
082    * </ul>
083    * @return A new empty {@link BasicHttpResource} object.
084    */
085   public static BasicHttpResource of(Supplier<?> content) {
086      return new BasicHttpResource(content);
087   }
088
089   /**
090    * Constructor.
091    *
092    * @param content
093    *    The content.
094    *    <br>Can be any of the following:
095    *    <ul>
096    *       <li><c>InputStream</c>
097    *       <li><c>Reader</c> - Converted to UTF-8 bytes.
098    *       <li><c>File</c>
099    *       <li><c>CharSequence</c> - Converted to UTF-8 bytes.
100    *       <li><c><jk>byte</jk>[]</c>.
101    *       <li>A {@link Supplier} of anything on this list.
102    *    </ul>
103    * </ul>
104    */
105   public BasicHttpResource(Object content) {
106      super(content);
107   }
108
109   /**
110    * Constructor.
111    *
112    * @param content
113    *    The content.
114    *    <br>Can be any of the following:
115    *    <ul>
116    *       <li><c>InputStream</c>
117    *       <li><c>Reader</c> - Converted to UTF-8 bytes.
118    *       <li><c>File</c>
119    *       <li><c>CharSequence</c> - Converted to UTF-8 bytes.
120    *       <li><c><jk>byte</jk>[]</c>.
121    *       <li>A {@link Supplier} of anything on this list.
122    *    </ul>
123    * </ul>
124    * @param contentType
125    *    The content type of the contents.
126    *    <br>Can be <jk>null</jk>.
127    * @param contentEncoding
128    *    The content encoding of the contents.
129    *    <br>Can be <jk>null</jk>.
130    */
131   public BasicHttpResource(Object content, ContentType contentType, ContentEncoding contentEncoding) {
132      super(content, contentType, contentEncoding);
133   }
134
135   /**
136    * Adds an arbitrary header to this resource.
137    *
138    * <p>
139    * Header is not added if name or value is null.
140    *
141    * @param name The header name.
142    * @param val The header value.
143    * @return This object (for method chaining).
144    */
145   @FluentSetter
146   public BasicHttpResource header(String name, Object val) {
147      if (name != null && val != null)
148         headers.add(BasicHeader.of(name, val));
149      return this;
150   }
151
152   /**
153    * Adds an arbitrary header to this resource.
154    *
155    * @param value The header.
156    * @return This object (for method chaining).
157    */
158   @FluentSetter
159   public BasicHttpResource header(Header value) {
160      headers.add(value);
161      return this;
162   }
163
164   /**
165    * Adds an arbitrary collection of headers to this resource.
166    *
167    * @param headers The headers to add to this resource.
168    * @return This object (for method chaining).
169    */
170   @FluentSetter
171   public BasicHttpResource headers(List<Header> headers) {
172      this.headers.addAll(headers);
173      return this;
174   }
175
176   /**
177    * Adds an arbitrary collection of headers to this resource.
178    *
179    * @param headers The headers to add to this resource.
180    * @return This object (for method chaining).
181    */
182   @FluentSetter
183   public BasicHttpResource headers(Header...headers) {
184      this.headers.addAll(Arrays.asList(headers));
185      return this;
186   }
187
188   /**
189    * Returns the first header with the specified name as a string.
190    *
191    * @param name The header name.
192    * @return The header value or <jk>null</jk> if header was not found.
193    */
194   public String getStringHeader(String name) {
195      Header h = getLastHeader(name);
196      return h == null ? null : h.getValue();
197   }
198
199   /**
200    * Returns the first header with the specified name as a string.
201    *
202    * @param name The header name.
203    * @return The header or <jk>null</jk> if header was not found.
204    */
205   public Header getFirstHeader(String name) {
206      for (Header h : headers)
207         if (h != null && eq(name, h.getName()))
208            return h;
209      return null;
210   }
211
212   /**
213    * Returns the last header with the specified name as a string.
214    *
215    * @param name The header name.
216    * @return The header or <jk>null</jk> if header was not found.
217    */
218   public Header getLastHeader(String name) {
219      for (ListIterator<Header> li = headers.listIterator(headers.size()); li.hasPrevious();) {
220         Header h = li.previous();
221         if (h != null && eq(name, h.getName()))
222            return h;
223      }
224      return null;
225   }
226
227   @Override /* Resource */
228   public List<Header> getHeaders() {
229      return Collections.unmodifiableList(headers);
230   }
231
232   // <FluentSetters>
233
234   @Override /* GENERATED - BasicHttpEntity */
235   public BasicHttpResource cache() {
236      super.cache();
237      return this;
238   }
239
240   @Override /* GENERATED - BasicHttpEntity */
241   public BasicHttpResource cache(boolean value) {
242      super.cache(value);
243      return this;
244   }
245
246   @Override /* GENERATED - BasicHttpEntity */
247   public BasicHttpResource chunked() {
248      super.chunked();
249      return this;
250   }
251
252   @Override /* GENERATED - BasicHttpEntity */
253   public BasicHttpResource chunked(boolean value) {
254      super.chunked(value);
255      return this;
256   }
257
258   @Override /* GENERATED - BasicHttpEntity */
259   public BasicHttpResource contentEncoding(String value) {
260      super.contentEncoding(value);
261      return this;
262   }
263
264   @Override /* GENERATED - BasicHttpEntity */
265   public BasicHttpResource contentEncoding(Header value) {
266      super.contentEncoding(value);
267      return this;
268   }
269
270   @Override /* GENERATED - BasicHttpEntity */
271   public BasicHttpResource contentLength(long value) {
272      super.contentLength(value);
273      return this;
274   }
275
276   @Override /* GENERATED - BasicHttpEntity */
277   public BasicHttpResource contentType(String value) {
278      super.contentType(value);
279      return this;
280   }
281
282   @Override /* GENERATED - BasicHttpEntity */
283   public BasicHttpResource contentType(Header value) {
284      super.contentType(value);
285      return this;
286   }
287
288   // </FluentSetters>
289}