Search in sources :

Example 1 with StoreListeners

use of org.apache.sis.storage.event.StoreListeners in project sis by apache.

the class ChannelFactory method prepare.

/**
 * Returns a byte channel factory without wrappers, or {@code null} if unsupported.
 * This method performs the same work than {@linkplain #prepare(Object, boolean, String,
 * OpenOption[], UnaryOperator, UnaryOperator) above method}, but without wrappers.
 *
 * @param  storage         the stream or the file to open, or {@code null}.
 * @param  allowWriteOnly  whether to allow wrapping {@link WritableByteChannel} and {@link OutputStream}.
 * @param  encoding        if the input is an encoded URL, the character encoding (normally {@code "UTF-8"}).
 * @param  options         the options to use for creating a new byte channel. Can be null or empty for read-only.
 * @return the channel factory for the given input, or {@code null} if the given input is of unknown type.
 * @throws IOException if an error occurred while processing the given input.
 */
private static ChannelFactory prepare(Object storage, final boolean allowWriteOnly, final String encoding, OpenOption[] options) throws IOException {
    /*
         * Unconditionally verify the options (unless 'allowWriteOnly' is true),
         * even if we may not use them.
         */
    final Set<OpenOption> optionSet;
    if (options == null || options.length == 0) {
        optionSet = Collections.singleton(StandardOpenOption.READ);
    } else {
        optionSet = new HashSet<>(Arrays.asList(options));
        optionSet.add(StandardOpenOption.READ);
        if (!allowWriteOnly && optionSet.removeAll(ILLEGAL_OPTIONS)) {
            throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2, "options", Arrays.toString(options)));
        }
    }
    /*
         * Check for inputs that are already readable channels or input streams.
         * Note that Channels.newChannel(InputStream) checks for instances of FileInputStream in order to delegate
         * to its getChannel() method, but only if the input stream type is exactly FileInputStream, not a subtype.
         * If Apache SIS defines its own FileInputStream subclass someday, we may need to add a special case here.
         */
    if (storage instanceof ReadableByteChannel || (allowWriteOnly && storage instanceof WritableByteChannel)) {
        return new Stream((Channel) storage);
    } else if (storage instanceof InputStream) {
        return new Stream(Channels.newChannel((InputStream) storage));
    } else if (allowWriteOnly && storage instanceof OutputStream) {
        return new Stream(Channels.newChannel((OutputStream) storage));
    }
    /*
         * In the following cases, we will try hard to convert to Path objects before to fallback
         * on File, URL or URI, because only Path instances allow us to use the given OpenOptions.
         */
    if (storage instanceof URL) {
        try {
            storage = IOUtilities.toPath((URL) storage, encoding);
        } catch (IOException e) {
            /*
                 * This is normal if the URL uses HTTP or FTP protocol for instance. Log the exception at FINE
                 * level without stack trace. We will open the channel later using the URL instead of the Path.
                 */
            recoverableException(e);
        }
    } else if (storage instanceof URI) {
        /*
             * If the user gave us a URI, try to convert to a Path before to fallback to URL, in order to be
             * able to use the given OpenOptions.  Note that the conversion to Path is likely to fail if the
             * URL uses HTTP or FTP protocols, because JDK7 does not provide file systems for them by default.
             */
        final URI uri = (URI) storage;
        if (!uri.isAbsolute()) {
            /*
                 * All methods invoked in this block throws IllegalArgumentException if the URI has no scheme,
                 * so we are better to check now and provide a more appropriate exception for this method.
                 */
            throw new IOException(Resources.format(Resources.Keys.MissingSchemeInURI_1, uri));
        } else
            try {
                storage = Paths.get(uri);
            } catch (IllegalArgumentException | FileSystemNotFoundException e) {
                try {
                    storage = uri.toURL();
                } catch (MalformedURLException ioe) {
                    ioe.addSuppressed(e);
                    throw ioe;
                }
                /*
                 * We have been able to convert to URL, but the given OpenOptions may not be used.
                 * Log the exception at FINE level without stack trace, because the exception is
                 * probably a normal behavior in this context.
                 */
                recoverableException(e);
            }
    } else {
        if (storage instanceof CharSequence) {
            // Needs to be before the check for File or URL.
            storage = IOUtilities.toFileOrURL(storage.toString(), encoding);
        }
        /*
             * If the input is a File or a CharSequence that we have been able to convert to a File,
             * try to convert to a Path in order to be able to use the OpenOptions. Only if we fail
             * to convert to a Path (which is unlikely), we will use directly the File.
             */
        if (storage instanceof File) {
            final File file = (File) storage;
            try {
                storage = file.toPath();
            } catch (final InvalidPathException e) {
                /*
                     * Unlikely to happen. But if it happens anyway, try to open the channel in a
                     * way less surprising for the user (closer to the object he has specified).
                     */
                if (file.isFile()) {
                    return new Fallback(file, e);
                }
            }
        }
    }
    /*
         * One last check for URL. The URL may be either the given input if we have not been able
         * to convert it to a Path, or a URI, File or CharSequence input converted to URL. Do not
         * try to convert the URL to a Path, because this has already been tried before this point.
         */
    if (storage instanceof URL) {
        final URL file = (URL) storage;
        return new ChannelFactory() {

            @Override
            public ReadableByteChannel readable(String filename, StoreListeners listeners) throws IOException {
                return Channels.newChannel(file.openStream());
            }

            @Override
            public WritableByteChannel writable(String filename, StoreListeners listeners) throws IOException {
                return Channels.newChannel(file.openConnection().getOutputStream());
            }
        };
    }
    /*
         * Handle path to directory as an unsupported input. Attempts to read bytes from that channel would cause an
         * IOException to be thrown. On Java 10, that IOException does not occur at channel openning time but rather
         * at reading time. See https://bugs.openjdk.java.net/browse/JDK-8080629 for more information.
         *
         * If the file does not exist, we let NoSuchFileException to be thrown by the code below because non-existant
         * file is probably an error. This is not the same situation than a directory, which can not be opened by this
         * class but may be opened by some specialized DataStore implementations.
         */
    if (storage instanceof Path) {
        final Path path = (Path) storage;
        if (!Files.isDirectory(path)) {
            return new ChannelFactory() {

                @Override
                public ReadableByteChannel readable(String filename, StoreListeners listeners) throws IOException {
                    return Files.newByteChannel(path, optionSet);
                }

                @Override
                public WritableByteChannel writable(String filename, StoreListeners listeners) throws IOException {
                    return Files.newByteChannel(path, optionSet);
                }
            };
        }
    }
    return null;
}
Also used : Path(java.nio.file.Path) ReadableByteChannel(java.nio.channels.ReadableByteChannel) MalformedURLException(java.net.MalformedURLException) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) OutputStream(java.io.OutputStream) FileOutputStream(java.io.FileOutputStream) WritableByteChannel(java.nio.channels.WritableByteChannel) IOException(java.io.IOException) URI(java.net.URI) URL(java.net.URL) InvalidPathException(java.nio.file.InvalidPathException) OpenOption(java.nio.file.OpenOption) StandardOpenOption(java.nio.file.StandardOpenOption) StoreListeners(org.apache.sis.storage.event.StoreListeners) FileSystemNotFoundException(java.nio.file.FileSystemNotFoundException) OutputStream(java.io.OutputStream) FileOutputStream(java.io.FileOutputStream) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) File(java.io.File)

Example 2 with StoreListeners

use of org.apache.sis.storage.event.StoreListeners in project sis by apache.

the class FileAccessView method apply.

/**
 * Invoked when a new {@link ReadableByteChannel} or {@link WritableByteChannel} is about to be created.
 * The caller will replace the given factory by the returned factory. It allows us to wrap the channel
 * in an object will will collect information about blocks read.
 *
 * @param  factory  the factory for creating channels.
 * @return the factory to use instead of the factory given in argument.
 */
@Override
public ChannelFactory apply(final ChannelFactory factory) {
    return new ChannelFactory() {

        /**
         * Creates a readable channel and listens (if possible) read operations.
         * Current implementation listens only to {@link SeekableByteChannel}
         * because otherwise we do not know the file size.
         *
         * @param  filename  data store name.
         * @param  listeners set of registered {@code StoreListener}s for the data store, or {@code null} if none.
         * @return the channel for the given input.
         * @throws DataStoreException if the channel is read-once.
         * @throws IOException if an error occurred while opening the channel.
         */
        @Override
        public ReadableByteChannel readable(final String filename, final StoreListeners listeners) throws DataStoreException, IOException {
            final ReadableByteChannel channel = factory.readable(filename, listeners);
            if (channel instanceof SeekableByteChannel) {
                final FileAccessItem item = new FileAccessItem(table.getItems(), filename);
                Platform.runLater(() -> item.owner.add(item));
                return item.new Observer((SeekableByteChannel) channel);
            }
            return channel;
        }

        /**
         * Forwards to the factory (listeners not yet implemented).
         */
        @Override
        public WritableByteChannel writable(final String filename, final StoreListeners listeners) throws DataStoreException, IOException {
            return factory.writable(filename, listeners);
        }
    };
}
Also used : SeekableByteChannel(java.nio.channels.SeekableByteChannel) ReadableByteChannel(java.nio.channels.ReadableByteChannel) StoreListeners(org.apache.sis.storage.event.StoreListeners) ChannelFactory(org.apache.sis.internal.storage.io.ChannelFactory)

Example 3 with StoreListeners

use of org.apache.sis.storage.event.StoreListeners in project sis by apache.

the class MetadataReader method warning.

/**
 * Logs a warning using the localized error resource bundle for the locale given by
 * {@link StoreListeners#getLocale()}.
 *
 * @param  key  one of {@link Errors.Keys} values.
 */
private void warning(final short key, final Object p1, final Object p2, final Exception e) {
    final StoreListeners listeners = decoder.listeners;
    listeners.warning(Errors.getResources(listeners.getLocale()).getString(key, p1, p2), e);
}
Also used : StoreListeners(org.apache.sis.storage.event.StoreListeners)

Aggregations

StoreListeners (org.apache.sis.storage.event.StoreListeners)3 ReadableByteChannel (java.nio.channels.ReadableByteChannel)2 File (java.io.File)1 FileInputStream (java.io.FileInputStream)1 FileOutputStream (java.io.FileOutputStream)1 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 OutputStream (java.io.OutputStream)1 MalformedURLException (java.net.MalformedURLException)1 URI (java.net.URI)1 URL (java.net.URL)1 SeekableByteChannel (java.nio.channels.SeekableByteChannel)1 WritableByteChannel (java.nio.channels.WritableByteChannel)1 FileSystemNotFoundException (java.nio.file.FileSystemNotFoundException)1 InvalidPathException (java.nio.file.InvalidPathException)1 OpenOption (java.nio.file.OpenOption)1 Path (java.nio.file.Path)1 StandardOpenOption (java.nio.file.StandardOpenOption)1 ChannelFactory (org.apache.sis.internal.storage.io.ChannelFactory)1