All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.amazon.ion.BufferConfiguration Maven / Gradle / Ivy

There is a newer version: 1.11.9
Show newest version
package com.amazon.ion;

import com.amazon.ion.impl.ReaderLookaheadBuffer;

/**
 * Provides logic common to all BufferConfiguration implementations.
 * @param  the type of the concrete subclass of this BufferConfiguration that is applicable to the
 *                        ReaderLookaheadBufferBase subclass.
 */
public abstract class BufferConfiguration> {

    /**
     * Functional interface for handling oversized values.
     */
    public interface OversizedValueHandler {
        /**
         * Invoked each time a value (and any symbol tables that immediately precede it) exceed the buffer size limit
         * specified by the LookaheadReaderWrapper instance, but the symbol tables by themselves do not exceed the
         * limit. This is recoverable. If the implementation wishes to recover, it should simply return normally from
         * this method. The oversized value will be flushed from the input pipe; normal processing will resume with the
         * next value. If the implementation wishes to abort processing immediately, it may throw an exception from this
         * method. Such an exception will propagate upward and will be thrown from
         * {@link ReaderLookaheadBuffer#fillInput()}.
         * @throws Exception if handler logic fails.
         */
        void onOversizedValue() throws Exception;
    }

    /**
     * Functional interface for reporting processed data.
     */
    public interface DataHandler {
        /**
         * Invoked whenever the bytes from a value are processed, regardless of whether the bytes are buffered or
         * skipped due to the value being oversized.
         * @param numberOfBytes the number of bytes processed.
         * @throws Exception if handler logic fails.
         */
        void onData(int numberOfBytes) throws Exception;
    }

    /**
     * Provides logic common to all BufferConfiguration Builder implementations.
     * @param  the type of BufferConfiguration.
     * @param  the type of Builder that builds BufferConfiguration subclasses of type `Configuration`.
     */
    public static abstract class Builder<
        Configuration extends BufferConfiguration,
        BuilderType extends BufferConfiguration.Builder
    > {

        /**
         * Large enough that most streams will never need to grow the buffer. NOTE: this only needs to be large
         * enough to exceed the length of the longest top-level value plus any system values that precede it.
         */
        static final int DEFAULT_INITIAL_BUFFER_SIZE = 32 * 1024; // bytes

        /**
         * The initial size of the lookahead buffer, in bytes.
         */
        private int initialBufferSize = DEFAULT_INITIAL_BUFFER_SIZE;

        /**
         * The maximum number of bytes that will be buffered.
         */
        private int maximumBufferSize = Integer.MAX_VALUE;

        /**
         * The handler that will be notified when oversized values are encountered.
         */
        private OversizedValueHandler oversizedValueHandler = null;

        /**
         * The handler that will be notified when data is processed.
         */
        private DataHandler dataHandler = null;

        /**
         * Sets the initial size of the buffer that will be used to hold the data between top-level values. Default:
         * 32KB.
         *
         * @param initialBufferSizeInBytes the value.
         * @return this Builder.
         */
        public final BuilderType withInitialBufferSize(final int initialBufferSizeInBytes) {
            initialBufferSize = initialBufferSizeInBytes;
            return (BuilderType) this;
        }

        /**
         * @return the initial size of the lookahead buffer, in bytes.
         */
        public final int getInitialBufferSize() {
            return initialBufferSize;
        }

        /**
         * Sets the handler that will be notified when oversized values are encountered. If the maximum buffer size is
         * finite (see {@link #withMaximumBufferSize(int)}, this handler is required to be non-null.
         *
         * @param handler the handler.
         * @return this builder.
         */
        public final BuilderType onOversizedValue(final OversizedValueHandler handler) {
            oversizedValueHandler = handler;
            return (BuilderType) this;
        }

        /**
         * Sets the handler that will be notified when data is processed. The handler may be null, in which case the
         * number of bytes processed will not be reported.
         *
         * @param handler the handler.
         * @return this builder.
         */
        public final BuilderType onData(final DataHandler handler) {
            dataHandler = handler;
            return (BuilderType) this;
        }

        /**
         * @return the handler that will be notified when oversized values are encountered.
         */
        public final OversizedValueHandler getOversizedValueHandler() {
            return oversizedValueHandler;
        }

        /**
         * @return the handler that will be notified when data is processed.
         */
        public final DataHandler getDataHandler() {
            return dataHandler;
        }

        /**
         * Set the maximum number of bytes between top-level values. This can be used to limit growth of the internal
         * buffer. For binary Ion, the minimum value is 5 because all valid binary Ion data begins with a 4-byte Ion
         * version marker and the smallest value is 1 byte. For delimited text Ion, the minimum value is 2 because the
         * smallest text Ion value is 1 byte and the smallest delimiter is 1 byte. Default: Integer.MAX_VALUE.
         *
         * @param maximumBufferSizeInBytes the value.
         * @return this builder.
         */
        public final BuilderType withMaximumBufferSize(final int maximumBufferSizeInBytes) {
            maximumBufferSize = maximumBufferSizeInBytes;
            return (BuilderType) this;
        }

        /**
         * @return the maximum number of bytes that will be buffered.
         */
        public int getMaximumBufferSize() {
            return maximumBufferSize;
        }

        /**
         * Gets the minimum allowed maximum buffer size.
         * @return the value.
         */
        public abstract int getMinimumMaximumBufferSize();

        /**
         * @return the no-op {@link OversizedValueHandler} for the type of BufferConfiguration that this Builder builds.
         */
        public abstract OversizedValueHandler getNoOpOversizedValueHandler();

        /**
         * @return the no-op {@link DataHandler} for the type of BufferConfiguration that this Builder builds.
         */
        public abstract DataHandler getNoOpDataHandler();

        /**
         * Creates a new BufferConfiguration from the Builder's current settings.
         * @return a new instance.
         */
        public abstract Configuration build();
    }

    /**
     * The initial size of the lookahead buffer, in bytes.
     */
    private final int initialBufferSize;

    /**
     * The maximum number of bytes that will be buffered.
     */
    private final int maximumBufferSize;

    /**
     * The handler that will be notified when oversized values are encountered.
     */
    private final OversizedValueHandler oversizedValueHandler;

    /**
     * The handler that will be notified when data is processed.
     */
    private final DataHandler dataHandler;

    /**
     * Constructs an instance from the given Builder.
     * @param builder the builder containing the settings to apply to the new configuration.
     */
    protected BufferConfiguration(Builder builder) {
        initialBufferSize = builder.getInitialBufferSize();
        maximumBufferSize = builder.getMaximumBufferSize();
        if (initialBufferSize > maximumBufferSize) {
            throw new IllegalArgumentException("Initial buffer size may not exceed the maximum buffer size.");
        }
        if (maximumBufferSize < builder.getMinimumMaximumBufferSize()) {
            throw new IllegalArgumentException(String.format(
                "Maximum buffer size must be at least %d bytes.", builder.getMinimumMaximumBufferSize()
            ));
        }
        if (builder.getOversizedValueHandler() == null) {
            requireUnlimitedBufferSize();
            oversizedValueHandler = builder.getNoOpOversizedValueHandler();
        } else {
            oversizedValueHandler = builder.getOversizedValueHandler();
        }
        if (builder.getDataHandler() == null) {
            dataHandler = builder.getNoOpDataHandler();
        } else {
            dataHandler = builder.getDataHandler();
        }
    }

    /**
     * Requires that the maximum buffer size not be limited.
     */
    protected void requireUnlimitedBufferSize() {
        if (maximumBufferSize < Integer.MAX_VALUE) {
            throw new IllegalArgumentException(
                "Must specify an OversizedValueHandler when a maximum buffer size is specified."
            );
        }
    }

    /**
     * @return the initial size of the lookahead buffer, in bytes.
     */
    public final int getInitialBufferSize() {
        return initialBufferSize;
    }

    /**
     * @return the maximum number of bytes that will be buffered.
     */
    public final int getMaximumBufferSize() {
        return maximumBufferSize;
    }

    /**
     * @return the handler that will be notified when oversized values are encountered.
     */
    public final OversizedValueHandler getOversizedValueHandler() {
        return oversizedValueHandler;
    }

    /**
     * @return the handler that will be notified when data is processed.
     */
    public final DataHandler getDataHandler() {
        return dataHandler;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy