001/*
002 * ====================================================================
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *   http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied.  See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 * ====================================================================
020 *
021 * This software consists of voluntary contributions made by many
022 * individuals on behalf of the Apache Software Foundation.  For more
023 * information on the Apache Software Foundation, please see
024 * <http://www.apache.org/>.
025 *
026 */
027
028package org.apache.http.entity;
029
030import java.io.IOException;
031import java.io.InputStream;
032import java.io.OutputStream;
033
034import org.apache.http.impl.io.EmptyInputStream;
035import org.apache.http.util.Args;
036import org.apache.http.util.Asserts;
037
038/**
039 * A generic streamed, non-repeatable entity that obtains its content
040 * from an {@link InputStream}.
041 *
042 * @since 4.0
043 */
044public class BasicHttpEntity extends AbstractHttpEntity {
045
046    private InputStream content;
047    private long length;
048
049    /**
050     * Creates a new basic entity.
051     * The content is initially missing, the content length
052     * is set to a negative number.
053     */
054    public BasicHttpEntity() {
055        super();
056        this.length = -1;
057    }
058
059    @Override
060    public long getContentLength() {
061        return this.length;
062    }
063
064    /**
065     * Obtains the content, once only.
066     *
067     * @return  the content, if this is the first call to this method
068     *          since {@link #setContent setContent} has been called
069     *
070     * @throws IllegalStateException
071     *          if the content has not been provided
072     */
073    @Override
074    public InputStream getContent() throws IllegalStateException {
075        Asserts.check(this.content != null, "Content has not been provided");
076        return this.content;
077    }
078
079    /**
080     * Tells that this entity is not repeatable.
081     *
082     * @return {@code false}
083     */
084    @Override
085    public boolean isRepeatable() {
086        return false;
087    }
088
089    /**
090     * Specifies the length of the content.
091     *
092     * @param len       the number of bytes in the content, or
093     *                  a negative number to indicate an unknown length
094     */
095    public void setContentLength(final long len) {
096        this.length = len;
097    }
098
099    /**
100     * Specifies the content.
101     *
102     * @param instream          the stream to return with the next call to
103     *                          {@link #getContent getContent}
104     */
105    public void setContent(final InputStream instream) {
106        this.content = instream;
107    }
108
109    @Override
110    public void writeTo(final OutputStream outstream) throws IOException {
111        Args.notNull(outstream, "Output stream");
112        final InputStream instream = getContent();
113        try {
114            int l;
115            final byte[] tmp = new byte[OUTPUT_BUFFER_SIZE];
116            while ((l = instream.read(tmp)) != -1) {
117                outstream.write(tmp, 0, l);
118            }
119        } finally {
120            instream.close();
121        }
122    }
123
124    @Override
125    public boolean isStreaming() {
126        return this.content != null && this.content != EmptyInputStream.INSTANCE;
127    }
128
129}