blob: 7290fc6201ac5e142ab00e4de63f3a7147d91201 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.axiom.util.blob;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.axiom.ext.io.StreamCopyException;
/**
* A writable blob.
* <p>
* The behavior of the methods defined by this interface is described in terms of three logical
* states the blob can be in:
* <dl>
* <dt>NEW
* <dd>The blob has just been created and no data has been written to it yet.
* <dt>UNCOMMITTED
* <dd>Data is being written to the blob.
* <dt>COMMITTED
* <dd>All data has been written to the blob and the blob will no longer accept any new data.
* </dl>
* Whether or not reading data from the blob if is in state NEW or UNCOMMITTED depends on the
* return value of {@link #isSupportingReadUncommitted()}.
* <p>
* Blobs are not thread safe.
*
* @deprecated Use {@link org.apache.axiom.blob.WritableBlob} instead.
*/
public interface WritableBlob extends Blob {
/**
* Determine whether the blob supports reading in state NEW or UNCOMMITTED. If this method
* returns <code>false</code> and the blob is in state NEW or UNCOMMITTED, any call to a method
* defined by the {@link Blob} superinterface will result in an {@link IllegalStateException}.
* If this method returns <code>true</code>, then any data written to the blob will be
* immediately available for reading. This is also true for an input stream obtained from
* {@link Blob#getInputStream()} before the data is written. This implies that it is possible
* for the input stream to first report the end of the stream and later allow reading additional
* data. Therefore, a pair of streams obtained from {@link #getOutputStream()} and
* {@link Blob#getInputStream()} behaves differently than a {@link java.io.PipedOutputStream}
* and {@link java.io.PipedInputStream} pair, because in this situation
* {@link java.io.PipedInputStream} would block.
*
* @return <code>true</code> if the blob allows reading the data in state NEW or UNCOMMITTED;
* <code>false</code> if the blob allows read operations only in state COMMITTED
*/
boolean isSupportingReadUncommitted();
/**
* Create an output stream to write data to the blob.
* <p>
* <em>Precondition:</em> The blob is in state NEW.
* <p>
* <em>Postcondition:</em> The blob is in state UNCOMMITTED.
* <p>
* Note that the pre- and postconditions imply that this method may be called at most once for
* a given blob instance.
* <p>
* Calls to methods of the returned output stream will modify the state of the blob
* according to the following rules:
* <ul>
* <li>A call to {@link OutputStream#close()} will change the state to COMMITTED.
* <li>Calls to other methods will not modify the state of the blob. They will result in
* an {@link IOException} if the state is COMMITTED, i.e. if the stream has already been
* closed.
* </ul>
*
* @return an output stream that can be used to write data to the blob
*
* @throws IllegalStateException if the blob is not in state NEW
*/
BlobOutputStream getOutputStream();
/**
* Read data from the given input stream and write it to the blob.
* <p>
* A call to this method has the same effect as requesting an output stream using
* {@link #getOutputStream()} and copying the data from the input stream to that
* output stream, but the implementation will achieve this result in a more efficient way.
* <p>
* <em>Precondition:</em> The blob is in state NEW or UNCOMMITTED.
* <p>
* <em>Postcondition:</em> The blob is in state UNCOMMITTED if <code>commit</code> is
* <code>false</code>. It is in state COMMITTED if <code>commit</code> is <code>true</code>.
* <p>
* The precondition implies that this method may be used after a call to
* {@link #getOutputStream()}. In that case it is illegal to set <code>commit</code> to
* <code>true</code> (because this would invalidate the state of the output stream).
* <p>
* The method transfers data from the input stream to the blob until one of the following
* conditions is met:
* <ul>
* <li>The end of the input stream is reached.
* <li>The value of the <code>length</code> argument is different from <code>-1</code>
* and the number of bytes transferred is equal to <code>length</code>.
* </ul>
*
* @param in An input stream to read data from. This method will not
* close the stream.
* @param length the number of bytes to transfer, or <code>-1</code> if the method should
* transfer data until the end of the input stream is reached
* @param commit indicates whether the blob should be in state COMMITTED after the operation
* @return the number of bytes transferred
* @throws StreamCopyException
* @throws IllegalStateException if the blob is in state COMMITTED or if
* {@link #getOutputStream()} has been called before and <code>commit</code> is
* <code>true</code>
*/
long readFrom(InputStream in, long length, boolean commit) throws StreamCopyException;
/**
* Read data from the given input stream and write it to the blob.
* <p>
* This method is similar to {@link #readFrom(InputStream, long, boolean)}, except that the state
* of the blob after the invocation (i.e. the <code>commit</code> argument) is determined
* automatically:
* <p>
* <table border="2" rules="all" cellpadding="4" cellspacing="0">
* <caption>State transitions</caption>
* <thead>
* <tr><th>Precondition (state)</th><th>Postcondition (state)</th></tr>
* </thead>
* <tbody>
* <tr><td>NEW</td><td>COMMITTED</td></tr>
* <tr><td>UNCOMMITTED</td><td>UNCOMMITTED</td></tr>
* <tr><td>COMMITTED</td><td><em>illegal</em></td></tr>
* </tbody>
* </table>
* <p>
* There are thus two usage patterns for this method:
* <ol>
* <li>The method is used to fill the blob with the data from an input stream, but no other
* data is written to the blob.
* <li>The method is used in parallel with the output stream returned by
* {@link #getOutputStream()}: some data is written using the output stream and some
* data is written using this method (for efficiency reasons).
* </ol>
*
* @param in An input stream to read data from. This method will not
* close the stream.
* @param length the number of bytes to transfer, or <code>-1</code> if the method should
* transfer data until the end of the input stream is reached
* @return the number of bytes transferred
* @throws StreamCopyException
* @throws IllegalStateException if the blob is in state COMMITTED
*/
long readFrom(InputStream in, long length) throws StreamCopyException;
/**
* Release all resources held by this blob.
*/
void release();
}