use of org.apache.sis.storage.DataStoreException in project sis by apache.
the class FolderStoreProvider method open.
/**
* Shared implementation of public {@code open(…)} methods.
* Note that this method may modify the given {@code options} set for its own purpose.
*
* @param connector information about the storage (URL, path, <i>etc</i>).
* @param format format name for directory content, or {@code null} if unspecified.
* @param options whether to create a new directory, overwrite existing content, <i>etc</i>.
*/
private DataStore open(final StorageConnector connector, final String format, final EnumSet<StandardOpenOption> options) throws DataStoreException {
/*
* Determine now the provider to use for directory content. We do that for determining if the component
* has write capability. If not, then the WRITE, CREATE and related options will be ignored. If we can
* not determine whether the component store has write capabilities (i.e. if canWrite(…) returns null),
* assume that the answer is "yes".
*/
final DataStoreProvider componentProvider;
if (format != null) {
componentProvider = StoreUtilities.providerByFormatName(format.trim());
if (Boolean.FALSE.equals(StoreUtilities.canWrite(componentProvider.getClass()))) {
// No write capability.
options.clear();
}
} else {
componentProvider = null;
// Can not write if we don't know the components format.
options.clear();
}
final Path path = connector.getStorageAs(Path.class);
final Store store;
try {
/*
* If the user asked to create a new directory, we need to perform this task before
* to create the Store (otherwise constructor will fail with NoSuchFileException).
* In the particular case of CREATE_NEW, we unconditionally attempt to create the
* directory in order to rely on the atomic check performed by Files.createDirectory(…).
*/
boolean isNew = false;
if (options.contains(StandardOpenOption.CREATE)) {
if (options.contains(StandardOpenOption.CREATE_NEW) || Files.notExists(path)) {
// IOException if the directory already exists.
Files.createDirectory(path);
isNew = true;
}
}
if (isNew || (options.contains(StandardOpenOption.WRITE) && Files.isWritable(path))) {
// May throw NoSuchFileException.
store = new WritableStore(this, connector, path, componentProvider);
} else {
// May throw NoSuchFileException.
store = new Store(this, connector, path, componentProvider);
}
/*
* If there is a destructive operation to perform (TRUNCATE_EXISTING), do it last only
* after we have successfully created the data store. The check for directory existence
* is also done after creation to be sure to check the path used by the store.
*/
if (!Files.isDirectory(path)) {
throw new DataStoreException(Resources.format(Resources.Keys.FileIsNotAResourceDirectory_1, path));
}
if (options.contains(StandardOpenOption.TRUNCATE_EXISTING)) {
WritableStore.deleteRecursively(path, false);
}
} catch (IOException e) {
/*
* In case of error, Java FileSystem implementation tries to throw a specific exception
* (NoSuchFileException or FileAlreadyExistsException), but this is not guaranteed.
*/
int isDirectory = 0;
final short errorKey;
if (e instanceof FileAlreadyExistsException) {
if (path != null && Files.isDirectory(path)) {
isDirectory = 1;
}
errorKey = Resources.Keys.FileAlreadyExists_2;
} else if (e instanceof NoSuchFileException) {
errorKey = Resources.Keys.NoSuchResourceDirectory_1;
} else {
errorKey = Resources.Keys.CanNotCreateFolderStore_1;
}
throw new DataStoreException(Resources.format(errorKey, (path != null) ? path : connector.getStorageName(), isDirectory), e);
}
return store;
}
use of org.apache.sis.storage.DataStoreException in project sis by apache.
the class Store method components.
/**
* Returns all resources found in the folder given at construction time.
* Only the resources recognized by a {@link DataStore} will be included.
* This includes sub-folders. Resources are in no particular order.
*/
@Override
@SuppressWarnings("ReturnOfCollectionOrArrayField")
public synchronized Collection<Resource> components() throws DataStoreException {
if (components == null) {
final List<DataStore> resources = new ArrayList<>();
try (DirectoryStream<Path> stream = Files.newDirectoryStream(location, this)) {
for (final Path candidate : stream) {
/*
* The candidate path may be a symbolic link to a file that we have previously read.
* In such case, use the existing data store. A use case is a directory containing
* hundred of GeoTIFF files all accompanied by ".prj" files having identical content.
* (Note: those ".prj" files should be invisible since they should be identified as
* GeoTIFF auxiliary files, but current Store implementation does not know that).
*/
final Path real = candidate.toRealPath();
DataStore next = children.get(real);
if (next instanceof Store) {
// Warn about directories only.
((Store) next).sharedRepository(real);
}
if (next == null) {
/*
* The candidate file has never been read before. Try to read it now.
* If the file format is unknown (UnsupportedStorageException), we will
* check if we can open it as a child folder store before to skip it.
*/
final StorageConnector connector = new StorageConnector(candidate);
connector.setOption(OptionKey.LOCALE, locale);
connector.setOption(OptionKey.TIMEZONE, timezone);
connector.setOption(OptionKey.ENCODING, encoding);
try {
if (componentProvider == null) {
// May throw UnsupportedStorageException.
next = DataStores.open(connector);
} else if (componentProvider.probeContent(connector).isSupported()) {
// Open a file of specified format.
next = componentProvider.open(connector);
} else if (Files.isDirectory(candidate)) {
// Open a sub-directory.
next = new Store(this, connector);
} else {
// Not the format specified at construction time.
connector.closeAllExcept(null);
continue;
}
} catch (UnsupportedStorageException ex) {
if (!Files.isDirectory(candidate)) {
connector.closeAllExcept(null);
listeners.warning(Level.FINE, null, ex);
continue;
}
next = new Store(this, connector);
} catch (DataStoreException ex) {
try {
connector.closeAllExcept(null);
} catch (DataStoreException s) {
ex.addSuppressed(s);
}
throw ex;
}
/*
* At this point we got the data store. It could happen that a store for
* the same file has been added concurrently, so we need to check again.
*/
final DataStore existing = children.putIfAbsent(real, next);
if (existing != null) {
next.close();
next = existing;
if (next instanceof Store) {
// Warn about directories only.
((Store) next).sharedRepository(real);
}
}
}
resources.add(next);
}
} catch (DirectoryIteratorException | UncheckedIOException ex) {
// The cause is an IOException (no other type allowed).
throw new DataStoreException(canNotRead(), ex.getCause());
} catch (IOException ex) {
throw new DataStoreException(canNotRead(), ex);
} catch (BackingStoreException ex) {
throw ex.unwrapOrRethrow(DataStoreException.class);
}
components = UnmodifiableArrayList.wrap(resources.toArray(new Resource[resources.size()]));
}
// Safe because unmodifiable list.
return components;
}
use of org.apache.sis.storage.DataStoreException in project sis by apache.
the class Store method close.
/**
* Closes all children resources.
*/
@Override
public synchronized void close() throws DataStoreException {
final Collection<Resource> resources = components;
if (resources != null) {
// Clear first in case of failure.
components = null;
DataStoreException failure = null;
for (final Resource r : resources) {
if (r instanceof DataStore)
try {
((DataStore) r).close();
} catch (DataStoreException ex) {
if (failure == null) {
failure = ex;
} else {
failure.addSuppressed(ex);
}
}
}
if (failure != null) {
throw failure;
}
}
}
use of org.apache.sis.storage.DataStoreException in project sis by apache.
the class WritableStore method remove.
/**
* Removes a {@code Resource} from this store. The resource must be a part of this {@code Aggregate}.
* For a folder store, this means that the resource must be a direct children of the directory managed
* by this store.
*
* This operation is destructive: the {@link Resource} and it's related files will be deleted.
*/
@Override
public synchronized void remove(final Resource resource) throws DataStoreException {
if (resource instanceof DataStore)
try {
if (resource instanceof Store) {
final Path path = ((Store) resource).location;
if (Files.isSameFile(path.getParent(), location)) {
((Store) resource).close();
deleteRecursively(path, true);
children.remove(path);
return;
}
} else if (resource instanceof ResourceOnFileSystem) {
final Path[] componentPaths = ((ResourceOnFileSystem) resource).getComponentFiles().clone();
for (Path root : componentPaths) {
root = root.getParent();
if (Files.isSameFile(root, location)) {
/*
* If we enter in this block, we have determined that at least one file is located in the
* directory managed by this store - NOT in a subdirectory since they could be managed by
* different folder stores. We assume that this root file is the "main" file. Other files
* could be in subdirectories, but we need to verify - we do not delete files outside.
*/
for (final Path path : componentPaths) {
if (path.startsWith(root)) {
Files.delete(path);
}
}
children.values().removeIf((e) -> e == resource);
// Clear cache. TODO: we should do something more efficient.
components = null;
return;
}
}
}
} catch (IOException e) {
throw new DataStoreException(messages().getString(Resources.Keys.CanNotRemoveResource_2, getDisplayName(), ((DataStore) resource).getDisplayName()), e);
}
throw new DataStoreException(messages().getString(Resources.Keys.NoSuchResourceInAggregate_2, getDisplayName(), StoreUtilities.getLabel(resource)));
}
use of org.apache.sis.storage.DataStoreException in project sis by apache.
the class FirstKeywordPeek method probeContent.
/**
* Returns {@link ProbeResult#SUPPORTED} if the given storage appears to begin with an expected keyword
* Returning {@code SUPPORTED} from this method does not guarantee that reading or writing will succeed,
* only that there appears to be a reasonable chance of success based on a brief inspection of the storage
* header.
*
* @param connector information about the storage (URL, stream, JDBC connection, <i>etc</i>).
* @return {@link ProbeResult#SUPPORTED} if the given storage seems to be readable.
* @throws DataStoreException if an I/O or SQL error occurred.
*/
@SuppressWarnings("null")
public final ProbeResult probeContent(final StorageConnector connector) throws DataStoreException {
char[] keyword = null;
int pos = 0;
try {
final ByteBuffer buffer = connector.getStorageAs(ByteBuffer.class);
final Reader reader;
if (buffer != null) {
buffer.mark();
reader = null;
} else {
// User gave us explicitely a Reader (e.g. a StringReader wrapping a String instance).
reader = connector.getStorageAs(Reader.class);
if (reader == null) {
return ProbeResult.UNSUPPORTED_STORAGE;
}
reader.mark(READ_AHEAD_LIMIT);
}
/*
* Ignore leading spaces and comments if any, then get a keyword no longer than 'maxLength'.
* That keyword shall be followed by [ or (, ignoring whitespaces.
*/
int c;
while ((c = nextAfterSpaces(buffer, reader)) == COMMENT) {
toEndOfLine(buffer, reader);
}
int s;
if ((s = isKeywordChar(c)) >= ACCEPT) {
keyword = new char[maxLength];
do {
if (s == ACCEPT) {
if (pos >= keyword.length) {
// Keyword too long.
pos = 0;
break;
}
keyword[pos++] = (char) c;
}
c = (buffer == null) ? IOUtilities.readCodePoint(reader) : buffer.hasRemaining() ? (char) buffer.get() : -1;
} while ((s = isKeywordChar(c)) >= ACCEPT);
/*
* At this point we finished to read and store the keyword.
* Verify if the keyword is followed by a character that indicate a keyword end.
*/
if (Character.isWhitespace(c)) {
c = nextAfterSpaces(buffer, reader);
}
if (!isPostKeyword(c)) {
pos = 0;
}
}
if (buffer != null) {
buffer.reset();
} else {
reader.reset();
}
if (c < 0) {
return ProbeResult.INSUFFICIENT_BYTES;
}
} catch (IOException e) {
throw new DataStoreException(e);
}
return forKeyword(keyword, pos);
}
Aggregations