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;
}
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);
}
};
}
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);
}
Aggregations