Search in sources :

Example 1 with ChannelDataInput

use of org.apache.sis.internal.storage.io.ChannelDataInput in project sis by apache.

the class StorageConnector method createChannelDataInput.

/**
 * Creates a view for the input as a {@link ChannelDataInput} if possible.
 * This is also a starting point for {@link #createDataInput()} and {@link #createByteBuffer()}.
 * This method is one of the {@link #OPENERS} methods and should be invoked at most once per
 * {@code StorageConnector} instance.
 *
 * @param  asImageInputStream  whether the {@code ChannelDataInput} needs to be {@link ChannelImageInputStream} subclass.
 * @throws IOException if an error occurred while opening a channel for the input.
 */
private ChannelDataInput createChannelDataInput(final boolean asImageInputStream) throws IOException, DataStoreException {
    /*
         * Before to try to wrap an InputStream, mark its position so we can rewind if the user asks for
         * the InputStream directly. We need to reset because ChannelDataInput may have read some bytes.
         * Note that if mark is unsupported, the default InputStream.mark(…) implementation does nothing.
         */
    reset();
    if (storage instanceof InputStream) {
        ((InputStream) storage).mark(DEFAULT_BUFFER_SIZE);
    }
    /*
         * Following method call recognizes ReadableByteChannel, InputStream (with special case for FileInputStream),
         * URL, URI, File, Path or other types that may be added in future Apache SIS versions.
         * If the given storage is already a ReadableByteChannel, then the factory will return it as-is.
         */
    final ChannelFactory factory = ChannelFactory.prepare(storage, getOption(OptionKey.URL_ENCODING), false, getOption(OptionKey.OPEN_OPTIONS));
    if (factory == null) {
        return null;
    }
    /*
         * ChannelDataInput depends on ReadableByteChannel, which itself depends on storage
         * (potentially an InputStream). We need to remember this chain in 'Coupled' objects.
         */
    final String name = getStorageName();
    final ReadableByteChannel channel = factory.readable(name, null);
    addView(ReadableByteChannel.class, channel, null, factory.isCoupled() ? CASCADE_ON_RESET : 0);
    // User-supplied buffer.
    ByteBuffer buffer = getOption(OptionKey.BYTE_BUFFER);
    if (buffer == null) {
        // Default buffer if user did not specified any.
        buffer = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE);
    }
    final ChannelDataInput asDataInput;
    if (asImageInputStream) {
        asDataInput = new ChannelImageInputStream(name, channel, buffer, false);
    } else {
        asDataInput = new ChannelDataInput(name, channel, buffer, false);
    }
    addView(ChannelDataInput.class, asDataInput, ReadableByteChannel.class, CASCADE_ON_RESET);
    /*
         * Following is an undocumented mechanism for allowing some Apache SIS implementations of DataStore
         * to re-open the same channel or input stream another time, typically for re-reading the same data.
         */
    if (factory.canOpen()) {
        addView(ChannelFactory.class, factory);
    }
    return asDataInput;
}
Also used : ReadableByteChannel(java.nio.channels.ReadableByteChannel) BufferedInputStream(java.io.BufferedInputStream) ChannelImageInputStream(org.apache.sis.internal.storage.io.ChannelImageInputStream) ImageInputStream(javax.imageio.stream.ImageInputStream) InputStream(java.io.InputStream) ChannelImageInputStream(org.apache.sis.internal.storage.io.ChannelImageInputStream) ChannelFactory(org.apache.sis.internal.storage.io.ChannelFactory) ByteBuffer(java.nio.ByteBuffer) ChannelDataInput(org.apache.sis.internal.storage.io.ChannelDataInput)

Example 2 with ChannelDataInput

use of org.apache.sis.internal.storage.io.ChannelDataInput in project sis by apache.

the class StorageConnector method createByteBuffer.

/**
 * Creates a {@link ByteBuffer} from the {@link ChannelDataInput} if possible, or from the
 * {@link ImageInputStream} otherwise. The buffer will be initialized with an arbitrary amount
 * of bytes read from the input. If this amount is not sufficient, it can be increased by a call
 * to {@link #prefetch()}.
 *
 * <p>This method is one of the {@link #OPENERS} methods and should be invoked at most once per
 * {@code StorageConnector} instance.</p>
 *
 * @throws IOException if an error occurred while opening a stream for the input.
 */
private ByteBuffer createByteBuffer() throws IOException, DataStoreException {
    /*
         * First, try to create the ChannelDataInput if it does not already exists.
         * If successful, this will create a ByteBuffer companion as a side effect.
         */
    final ChannelDataInput c = getStorageAs(ChannelDataInput.class);
    ByteBuffer asByteBuffer = null;
    if (c != null) {
        asByteBuffer = c.buffer.asReadOnlyBuffer();
    } else {
        /*
             * If no ChannelDataInput has been created by the above code, get the input as an ImageInputStream and
             * read an arbitrary amount of bytes. Read only a small amount of bytes because, at the contrary of the
             * buffer created in createChannelDataInput(boolean), the buffer created here is unlikely to be used for
             * the reading process after the recognition of the file format.
             */
        final ImageInputStream in = getStorageAs(ImageInputStream.class);
        if (in != null) {
            in.mark();
            final byte[] buffer = new byte[MINIMAL_BUFFER_SIZE];
            final int n = in.read(buffer);
            in.reset();
            if (n >= 1) {
                // Can not invoke asReadOnly() because 'prefetch()' need to be able to write in it.
                asByteBuffer = ByteBuffer.wrap(buffer).order(in.getByteOrder());
                asByteBuffer.limit(n);
            }
        }
    }
    addView(ByteBuffer.class, asByteBuffer);
    return asByteBuffer;
}
Also used : ChannelImageInputStream(org.apache.sis.internal.storage.io.ChannelImageInputStream) ImageInputStream(javax.imageio.stream.ImageInputStream) ByteBuffer(java.nio.ByteBuffer) ChannelDataInput(org.apache.sis.internal.storage.io.ChannelDataInput)

Example 3 with ChannelDataInput

use of org.apache.sis.internal.storage.io.ChannelDataInput in project sis by apache.

the class ChannelDecoderTest method createChannelDecoder.

/**
 * Creates a new {@link ChannelDecoder} instance for dataset of the given name.
 * The {@code name} parameter can be one of the following values:
 *
 * <ul>
 *   <li>{@link #NCEP}    for a netCDF binary file.</li>
 *   <li>{@link #CIP}     for a netCDF binary file.</li>
 * </ul>
 *
 * @param  name  the file name as one of the above-cited constants.
 * @return the decoder for the given name.
 * @throws IOException if an I/O error occurred while opening the file.
 * @throws DataStoreException if a logical error occurred.
 */
public static Decoder createChannelDecoder(final String name) throws IOException, DataStoreException {
    final InputStream in = IOTestCase.class.getResourceAsStream(name);
    assumeNotNull(name, in);
    final ChannelDataInput input = new ChannelDataInput(name, Channels.newChannel(in), ByteBuffer.allocate(4096), false);
    return new ChannelDecoder(input, null, GeometryLibrary.JAVA2D, LISTENERS);
}
Also used : InputStream(java.io.InputStream) ChannelDataInput(org.apache.sis.internal.storage.io.ChannelDataInput)

Example 4 with ChannelDataInput

use of org.apache.sis.internal.storage.io.ChannelDataInput in project sis by apache.

the class NetcdfStoreProvider method decoder.

/**
 * Creates a decoder for the given input. This method invokes
 * {@link StorageConnector#closeAllExcept(Object)} after the decoder has been created.
 *
 * @param  listeners  where to send the warnings.
 * @param  connector  information about the input (file, input stream, <i>etc.</i>)
 * @return the decoder for the given input, or {@code null} if the input type is not recognized.
 * @throws IOException if an error occurred while opening the netCDF file.
 * @throws DataStoreException if a logical error (other than I/O) occurred.
 */
static Decoder decoder(final WarningListeners<DataStore> listeners, final StorageConnector connector) throws IOException, DataStoreException {
    final GeometryLibrary geomlib = connector.getOption(OptionKey.GEOMETRY_LIBRARY);
    Decoder decoder;
    Object keepOpen;
    final ChannelDataInput input = connector.getStorageAs(ChannelDataInput.class);
    if (input != null)
        try {
            decoder = new ChannelDecoder(input, connector.getOption(OptionKey.ENCODING), geomlib, listeners);
            keepOpen = input;
        } catch (DataStoreException e) {
            final String path = connector.getStorageAs(String.class);
            if (path != null)
                try {
                    decoder = createByReflection(path, false, geomlib, listeners);
                    keepOpen = path;
                } catch (IOException | DataStoreException s) {
                    e.addSuppressed(s);
                }
            throw e;
        }
    else {
        keepOpen = connector.getStorage();
        decoder = createByReflection(keepOpen, true, geomlib, listeners);
    }
    connector.closeAllExcept(keepOpen);
    return decoder;
}
Also used : GeometryLibrary(org.apache.sis.setup.GeometryLibrary) ChannelDecoder(org.apache.sis.internal.netcdf.impl.ChannelDecoder) DataStoreException(org.apache.sis.storage.DataStoreException) Decoder(org.apache.sis.internal.netcdf.Decoder) ChannelDecoder(org.apache.sis.internal.netcdf.impl.ChannelDecoder) ChannelDataInput(org.apache.sis.internal.storage.io.ChannelDataInput)

Example 5 with ChannelDataInput

use of org.apache.sis.internal.storage.io.ChannelDataInput in project sis by apache.

the class StorageConnector method createDataInput.

/**
 * Creates a view for the input as a {@link DataInput} if possible. This method performs the choice
 * documented in the {@link #getStorageAs(Class)} method for the {@code DataInput} case. Opening the
 * data input may imply creating a {@link ByteBuffer}, in which case the buffer will be stored under
 * the {@code ByteBuffer.class} key together with the {@code DataInput.class} case.
 *
 * <p>This method is one of the {@link #OPENERS} methods and should be invoked at most once per
 * {@code StorageConnector} instance.</p>
 *
 * @throws IOException if an error occurred while opening a stream for the input.
 */
private DataInput createDataInput() throws IOException, DataStoreException {
    /*
         * Gets or creates a ChannelImageInputStream instance if possible. We really need that specific
         * type because some SIS data stores will want to access directly the channel and the buffer.
         * We will fallback on the ImageIO.createImageInputStream(Object) method only in last resort.
         */
    Coupled c = getView(ChannelDataInput.class);
    final ChannelDataInput in;
    if (reset(c)) {
        in = (ChannelDataInput) c.view;
    } else {
        // May be null.
        in = createChannelDataInput(true);
    }
    final DataInput asDataInput;
    if (in != null) {
        // May have been added by createChannelDataInput(…).
        c = getView(ChannelDataInput.class);
        if (in instanceof DataInput) {
            asDataInput = (DataInput) in;
        } else {
            // Upgrade existing instance.
            asDataInput = new ChannelImageInputStream(in);
            c.view = asDataInput;
        }
        // Share the same Coupled instance.
        views.put(DataInput.class, c);
    } else {
        reset();
        asDataInput = ImageIO.createImageInputStream(storage);
        addView(DataInput.class, asDataInput, null, (byte) (CASCADE_ON_RESET | CASCADE_ON_CLOSE));
    /*
             * Note: Java Image I/O wrappers for Input/OutputStream do NOT close the underlying streams.
             * This is a complication for us. We could mitigate the problem by subclassing the standard
             * FileCacheImageInputStream and related classes, but we don't do that for now because this
             * code should never be executed for InputStream storage. Instead getChannelDataInput(true)
             * should have created a ChannelImageInputStream or ChannelDataInput.
             */
    }
    return asDataInput;
}
Also used : DataInput(java.io.DataInput) ChannelDataInput(org.apache.sis.internal.storage.io.ChannelDataInput) ChannelImageInputStream(org.apache.sis.internal.storage.io.ChannelImageInputStream) ChannelDataInput(org.apache.sis.internal.storage.io.ChannelDataInput)

Aggregations

ChannelDataInput (org.apache.sis.internal.storage.io.ChannelDataInput)7 ChannelImageInputStream (org.apache.sis.internal.storage.io.ChannelImageInputStream)5 ByteBuffer (java.nio.ByteBuffer)3 ImageInputStream (javax.imageio.stream.ImageInputStream)3 DataInput (java.io.DataInput)2 InputStream (java.io.InputStream)2 BufferedInputStream (java.io.BufferedInputStream)1 IOException (java.io.IOException)1 ReadableByteChannel (java.nio.channels.ReadableByteChannel)1 Decoder (org.apache.sis.internal.netcdf.Decoder)1 ChannelDecoder (org.apache.sis.internal.netcdf.impl.ChannelDecoder)1 ChannelFactory (org.apache.sis.internal.storage.io.ChannelFactory)1 GeometryLibrary (org.apache.sis.setup.GeometryLibrary)1 DataStoreException (org.apache.sis.storage.DataStoreException)1 Test (org.junit.Test)1