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.entity;
018
019
020import java.io.*;
021
022import org.apache.juneau.http.*;
023import static org.apache.juneau.commons.utils.Shorts.*;
024
025/**
026 * A non-repeatable {@link HttpBody} that streams content from an {@link InputStream}.
027 *
028 * <p>
029 * Because the stream is one-shot, {@link #isRepeatable()} returns {@code false} and {@link #getContentLength()}
030 * returns {@code -1} (the transport must use chunked transfer encoding).
031 *
032 * <p>
033 * The caller is responsible for closing the wrapped stream after the response has been consumed.
034 *
035 * @since 9.2.1
036 */
037@SuppressWarnings({
038   "resource" // stream is caller-owned; StreamBody does not close it (documented in class Javadoc)
039})
040public final class StreamBody implements HttpBody {
041
042   private final InputStream stream;
043   private final String contentType;
044
045   private StreamBody(InputStream stream, String contentType) {
046      this.stream = reqnn("stream", stream);
047      this.contentType = contentType;
048   }
049
050   /**
051    * Creates a {@link StreamBody} with {@code application/octet-stream} content type.
052    *
053    * @param stream The input stream. Must not be <jk>null</jk>.
054    * @return A new instance. Never <jk>null</jk>.
055    */
056   public static StreamBody of(InputStream stream) {
057      return new StreamBody(stream, "application/octet-stream");
058   }
059
060   /**
061    * Creates a {@link StreamBody} with the given content type.
062    *
063    * @param stream The input stream. Must not be <jk>null</jk>.
064    * @param contentType The MIME content type. May be <jk>null</jk>.
065    * @return A new instance. Never <jk>null</jk>.
066    */
067   public static StreamBody of(InputStream stream, String contentType) {
068      return new StreamBody(stream, contentType);
069   }
070
071   @Override /* HttpBody */
072   public String getContentType() {
073      return contentType;
074   }
075
076   @Override /* HttpBody */
077   public void writeTo(OutputStream out) throws IOException {
078      stream.transferTo(out);
079   }
080
081   @Override /* HttpBody */
082   public boolean isRepeatable() {
083      return false;
084   }
085}