blob: 2e874ad8e82ba759204f3979164651b19852b585 [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.avro.io;
import java.io.IOException;
import java.io.InputStream;
import org.apache.avro.Schema;
/**
* A factory for creating and configuring {@link Decoder}s.
* <p/>
* Factories are thread-safe, and are generally cached by applications for
* performance reasons. Multiple instances are only required if multiple
* concurrent configurations are needed.
*
* @see Decoder
*/
public class DecoderFactory {
private static final DecoderFactory DEFAULT_FACTORY = new DefaultDecoderFactory();
static final int DEFAULT_BUFFER_SIZE = 8192;
int binaryDecoderBufferSize = DEFAULT_BUFFER_SIZE;
/** Constructor for factory instances */
public DecoderFactory() {
super();
}
/**
* @deprecated use the equivalent {@link #get()} instead
*/
@Deprecated
public static DecoderFactory defaultFactory() {
return get();
}
/**
* Returns an immutable static DecoderFactory configured with default settings
* All mutating methods throw IllegalArgumentExceptions. All creator methods
* create objects with default settings.
*/
public static DecoderFactory get() {
return DEFAULT_FACTORY;
}
/**
* Configures this factory to use the specified buffer size when creating
* Decoder instances that buffer their input. The default buffer size is
* 8192 bytes.
*
* @param size The preferred buffer size. Valid values are in the range [32,
* 16*1024*1024]. Values outside this range are rounded to the nearest
* value in the range. Values less than 512 or greater than 1024*1024
* are not recommended.
* @return This factory, to enable method chaining:
* <pre>
* DecoderFactory myFactory = new DecoderFactory().useBinaryDecoderBufferSize(4096);
* </pre>
*/
public DecoderFactory configureDecoderBufferSize(int size) {
if (size < 32)
size = 32;
if (size > 16 * 1024 * 1024)
size = 16 * 1024 * 1024;
this.binaryDecoderBufferSize = size;
return this;
}
/**
* Returns this factory's configured preferred buffer size. Used when creating
* Decoder instances that buffer. See {@link #configureDecoderBufferSize}
* @return The preferred buffer size, in bytes.
*/
public int getConfiguredBufferSize() {
return this.binaryDecoderBufferSize;
}
/** @deprecated use the equivalent
* {@link #binaryDecoder(InputStream, BinaryDecoder)} instead */
@Deprecated
public BinaryDecoder createBinaryDecoder(InputStream in, BinaryDecoder reuse) {
return binaryDecoder(in, reuse);
}
/**
* Creates or reinitializes a {@link BinaryDecoder} with the input stream
* provided as the source of data. If <i>reuse</i> is provided, it will be
* reinitialized to the given input stream.
* <p/>
* {@link BinaryDecoder} instances returned by this method buffer their input,
* reading up to {@link #getConfiguredBufferSize()} bytes past the minimum
* required to satisfy read requests in order to achieve better performance.
* If the buffering is not desired, use
* {@link #directBinaryDecoder(InputStream, BinaryDecoder)}.
* <p/>
* {@link BinaryDecoder#inputStream()} provides a view on the data that is
* buffer-aware, for users that need to interleave access to data
* with the Decoder API.
*
* @param in
* The InputStream to initialize to
* @param reuse
* The BinaryDecoder to <i>attempt</i> to reuse given the factory
* configuration. A BinaryDecoder implementation may not be
* compatible with reuse, causing a new instance to be returned. If
* null, a new instance is returned.
* @return A BinaryDecoder that uses <i>in</i> as its source of data. If
* <i>reuse</i> is null, this will be a new instance. If <i>reuse</i>
* is not null, then it may be reinitialized if compatible, otherwise
* a new instance will be returned.
* @see BinaryDecoder
* @see Decoder
*/
public BinaryDecoder binaryDecoder(InputStream in, BinaryDecoder reuse) {
if (null == reuse || !reuse.getClass().equals(BinaryDecoder.class)) {
return new BinaryDecoder(in, binaryDecoderBufferSize);
} else {
return ((BinaryDecoder)reuse).configure(in, binaryDecoderBufferSize);
}
}
/**
* Creates or reinitializes a {@link BinaryDecoder} with the input stream
* provided as the source of data. If <i>reuse</i> is provided, it will be
* reinitialized to the given input stream.
* <p/>
* {@link BinaryDecoder} instances returned by this method do not buffer their input.
* In most cases a buffering BinaryDecoder is sufficient in combination with
* {@link BinaryDecoder#inputStream()} which provides a buffer-aware view on
* the data.
* <p/>
* A "direct" BinaryDecoder does not read ahead from an InputStream or other data source
* that cannot be rewound. From the perspective of a client, a "direct" decoder
* must never read beyond the minimum necessary bytes to service a {@link BinaryDecoder}
* API read request.
* <p/>
* In the case that the improved performance of a buffering implementation does not outweigh the
* inconvenience of its buffering semantics, a "direct" decoder can be
* used.
* @param in
* The InputStream to initialize to
* @param reuse
* The BinaryDecoder to <i>attempt</i> to reuse given the factory
* configuration. A BinaryDecoder implementation may not be
* compatible with reuse, causing a new instance to be returned. If
* null, a new instance is returned.
* @return A BinaryDecoder that uses <i>in</i> as its source of data. If
* <i>reuse</i> is null, this will be a new instance. If <i>reuse</i>
* is not null, then it may be reinitialized if compatible, otherwise
* a new instance will be returned.
* @see DirectBinaryDecoder
* @see Decoder
*/
public BinaryDecoder directBinaryDecoder(InputStream in, BinaryDecoder reuse) {
if (null == reuse || !reuse.getClass().equals(DirectBinaryDecoder.class)) {
return new DirectBinaryDecoder(in);
} else {
return ((DirectBinaryDecoder)reuse).configure(in);
}
}
/** @deprecated use {@link #binaryDecoder(byte[], int, int, BinaryDecoder)}
* instead */
@Deprecated
public BinaryDecoder createBinaryDecoder(byte[] bytes, int offset,
int length, BinaryDecoder reuse) {
if (null == reuse || !reuse.getClass().equals(BinaryDecoder.class)) {
return new BinaryDecoder(bytes, offset, length);
} else {
return reuse.configure(bytes, offset, length);
}
}
/**
* Creates or reinitializes a {@link BinaryDecoder} with the byte array
* provided as the source of data. If <i>reuse</i> is provided, it will
* attempt to reinitialize <i>reuse</i> to the new byte array. This instance
* will use the provided byte array as its buffer.
* <p/>
* {@link BinaryDecoder#inputStream()} provides a view on the data that is
* buffer-aware and can provide a view of the data not yet read by Decoder API
* methods.
*
* @param bytes The byte array to initialize to
* @param offset The offset to start reading from
* @param length The maximum number of bytes to read from the byte array
* @param reuse The BinaryDecoder to attempt to reinitialize. if null a new
* BinaryDecoder is created.
* @return A BinaryDecoder that uses <i>bytes</i> as its source of data. If
* <i>reuse</i> is null, this will be a new instance. <i>reuse</i> may
* be reinitialized if appropriate, otherwise a new instance is
* returned. Clients must not assume that <i>reuse</i> is
* reinitialized and returned.
*/
public BinaryDecoder binaryDecoder(byte[] bytes, int offset,
int length, BinaryDecoder reuse) {
if (null == reuse || !reuse.getClass().equals(BinaryDecoder.class)) {
return new BinaryDecoder(bytes, offset, length);
} else {
return reuse.configure(bytes, offset, length);
}
}
/** @deprecated use {@link #binaryDecoder(byte[], BinaryDecoder)} instead */
@Deprecated
public BinaryDecoder createBinaryDecoder(byte[] bytes, BinaryDecoder reuse) {
return binaryDecoder(bytes, 0, bytes.length, reuse);
}
/**
* This method is shorthand for
* <pre>
* createBinaryDecoder(bytes, 0, bytes.length, reuse);
* </pre> {@link #binaryDecoder(byte[], int, int, BinaryDecoder)}
*/
public BinaryDecoder binaryDecoder(byte[] bytes, BinaryDecoder reuse) {
return binaryDecoder(bytes, 0, bytes.length, reuse);
}
/**
* Creates a {@link JsonDecoder} using the InputStrim provided for reading
* data that conforms to the Schema provided.
* <p/>
*
* @param schema
* The Schema for data read from this JsonEncoder. Cannot be null.
* @param input
* The InputStream to read from. Cannot be null.
* @return A JsonEncoder configured with <i>input</i> and <i>schema</i>
* @throws IOException
*/
public JsonDecoder jsonDecoder(Schema schema, InputStream input)
throws IOException {
return new JsonDecoder(schema, input);
}
/**
* Creates a {@link JsonDecoder} using the String provided for reading data
* that conforms to the Schema provided.
* <p/>
*
* @param schema
* The Schema for data read from this JsonEncoder. Cannot be null.
* @param input
* The String to read from. Cannot be null.
* @return A JsonEncoder configured with <i>input</i> and <i>schema</i>
* @throws IOException
*/
public JsonDecoder jsonDecoder(Schema schema, String input)
throws IOException {
return new JsonDecoder(schema, input);
}
/**
* Creates a {@link ValidatingDecoder} wrapping the Decoder provided. This
* ValidatingDecoder will ensure that operations against it conform to the
* schema provided.
*
* @param schema
* The Schema to validate against. Cannot be null.
* @param wrapped
* The Decoder to wrap.
* @return A ValidatingDecoder configured with <i>wrapped</i> and
* <i>schema</i>
* @throws IOException
*/
public ValidatingDecoder validatingDecoder(Schema schema, Decoder wrapped)
throws IOException {
return new ValidatingDecoder(schema, wrapped);
}
/**
* Creates a {@link ResolvingDecoder} wrapping the Decoder provided. This
* ResolvingDecoder will resolve input conforming to the <i>writer</i> schema
* from the wrapped Decoder, and present it as the <i>reader</i> schema.
*
* @param writer
* The Schema that the source data is in. Cannot be null.
* @param reader
* The Schema that the reader wishes to read the data as. Cannot be
* null.
* @param wrapped
* The Decoder to wrap.
* @return A ResolvingDecoder configured to resolve <i>writer</i> to
* <i>reader</i> from <i>in</i>
* @throws IOException
*/
public ResolvingDecoder resolvingDecoder(Schema writer, Schema reader,
Decoder wrapped) throws IOException {
return new ResolvingDecoder(writer, reader, wrapped);
}
private static class DefaultDecoderFactory extends DecoderFactory {
@Override
public DecoderFactory configureDecoderBufferSize(int bufferSize) {
throw new IllegalArgumentException("This Factory instance is Immutable");
}
}
}