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
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package com.amazon.ion;

import com.amazon.ion.impl._Private_IonConstants;

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

    /**
     * Functional interface for handling oversized values.
     */
    @FunctionalInterface
    public interface OversizedValueHandler {
        /**
         * Invoked each time a user value exceeds the buffer size limit specified. 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 buffer; normal processing will resume with the next value. If the implementation wishes
         * to abort processing immediately, it may throw an exception from this method.
         */
        void onOversizedValue();
    }

    /**
     * Functional interface for reporting processed data.
     */
    @FunctionalInterface
    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.
         */
        void onData(int numberOfBytes);
    }

    /**
     * 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 = _Private_IonConstants.ARRAY_MAXIMUM_SIZE;

        /**
         * 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 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 size of the 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 text Ion, the minimum value is
         * 2 because the smallest text Ion value is 1 byte and the smallest delimiter is 1 byte.
         * Default: Near to the maximum size of an array.
         *
         * @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 an {@link OversizedValueHandler} that always throws a runtime exception.
         */
        public abstract OversizedValueHandler getThrowingOversizedValueHandler();

        /**
         * @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 buffer, in bytes.
     */
    private final int initialBufferSize;

    /**
     * The maximum number of bytes that may 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) {
            requireMaximumBufferSize();
            oversizedValueHandler = builder.getThrowingOversizedValueHandler();
        } 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 requireMaximumBufferSize() {
        if (maximumBufferSize < _Private_IonConstants.ARRAY_MAXIMUM_SIZE) {
            throw new IllegalArgumentException(
                "Must specify an OversizedValueHandler when a custom maximum buffer size is specified."
            );
        }
    }

    /**
     * @return the initial size of the 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