Author: desruisseaux
Date: Thu Aug 1 15:33:07 2013
New Revision: 1509300
URL: http://svn.apache.org/r1509300
Log:
Revisit the strategy about DataStore OpenOptions: move them as options given to
StorageConnector, because we need
to know them when the ByteChannel is created (having the options in
DataStoreProvider.canOpen(...) was too late).
As a side effect, the OpenOption are not anymore directly in the method
signature, which will make the port to
the JDK6 branch a little bit easier.
Added:
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/ProbeResult.java
- copied, changed from r1509040,
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/OpenOption.java
Removed:
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/OpenOption.java
Modified:
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/setup/OptionKey.java
sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java
sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/IOUtilities.java
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreProvider.java
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreRegistry.java
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStores.java
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
Modified:
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/setup/OptionKey.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/setup/OptionKey.java?rev=1509300&r1=1509299&r2=1509300&view=diff
==============================================================================
---
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/setup/OptionKey.java
[UTF-8] (original)
+++
sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/setup/OptionKey.java
[UTF-8] Thu Aug 1 15:33:07 2013
@@ -24,6 +24,10 @@ import java.io.ObjectStreamException;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.logging.Logging;
+// Related to JDK7
+import java.nio.file.OpenOption;
+import java.nio.file.StandardOpenOption;
+
/**
* Keys in a map of options, together with static constants for commonly-used
options.
@@ -33,7 +37,7 @@ import org.apache.sis.util.logging.Loggi
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.3
- * @version 0.3
+ * @version 0.4
* @module
*/
public class OptionKey<T> implements Serializable {
@@ -45,10 +49,10 @@ public class OptionKey<T> implements Ser
/**
* The encoding of a URL (<strong>not</strong> the encoding of the
document content).
* This option may be used when converting a {@link String} or a {@link
java.net.URL}
- * to a {@link java.net.URI} or a {@link java.io.File}:
+ * to a {@link java.net.URI} or a {@link java.io.File}. The following
rules apply:
*
* <ul>
- * <li>URI are always encoded in UTF-8.</li>
+ * <li>URI are always encoded in UTF-8. Consequently this option is
ignored for URI.</li>
* <li>URL are often encoded in UTF-8, but not necessarily. Other
encodings are possible
* (while not recommended), or some URL may not be encoded at
all.</li>
* </ul>
@@ -75,6 +79,20 @@ public class OptionKey<T> implements Ser
public static final OptionKey<String> URL_ENCODING = new
OptionKey<>("URL_ENCODING", String.class);
/**
+ * Whether a storage object (e.g. a {@link
org.apache.sis.storage.DataStore}) shall be opened in read,
+ * write, append or other modes. The main options that can be provided are:
+ *
+ * <table class="sis">
+ * <tr><th>Value</th> <th>Meaning</th></tr>
+ * <tr><td>{@link StandardOpenOption#READ}</td> <td>Open for reading
data from the storage object.</td></tr>
+ * <tr><td>{@link StandardOpenOption#WRITE}</td> <td>Open for modifying
existing data in the storage object.</td></tr>
+ * <tr><td>{@link StandardOpenOption#APPEND}</td> <td>Open for appending
new data in the storage object.</td></tr>
+ * <tr><td>{@link StandardOpenOption#CREATE}</td> <td>Creates a new
storage object (file or database) if it does not exist.</td></tr>
+ * </table>
+ */
+ public static final OptionKey<OpenOption[]> OPEN_OPTIONS = new
OptionKey<>("OPEN_OPTIONS", OpenOption[].class);
+
+ /**
* The byte buffer to use for input/output operations. Some {@link
org.apache.sis.storage.DataStore}
* implementations allow a byte buffer to be specified, thus allowing
users to choose the buffer
* {@linkplain ByteBuffer#capacity() capacity}, whether the buffer
{@linkplain ByteBuffer#isDirect()
Modified:
sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java?rev=1509300&r1=1509299&r2=1509300&view=diff
==============================================================================
---
sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java
[UTF-8] (original)
+++
sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java
[UTF-8] Thu Aug 1 15:33:07 2013
@@ -16,8 +16,6 @@
*/
package org.apache.sis.storage.netcdf;
-import java.util.Set;
-import java.util.Collections;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.lang.reflect.Method;
@@ -34,7 +32,7 @@ import org.apache.sis.storage.DataStore;
import org.apache.sis.storage.DataStoreProvider;
import org.apache.sis.storage.StorageConnector;
import org.apache.sis.storage.DataStoreException;
-import org.apache.sis.storage.OpenOption;
+import org.apache.sis.storage.ProbeResult;
import org.apache.sis.util.logging.WarningListeners;
import org.apache.sis.util.ThreadSafe;
@@ -98,38 +96,31 @@ public class NetcdfStoreProvider extends
}
/**
- * The open options of NetCDF files.
- */
- private static final Set<OpenOption> OPTIONS =
Collections.<OpenOption>singleton(OpenOption.READ);
-
- /**
* Creates a new provider.
*/
public NetcdfStoreProvider() {
}
/**
- * Returns a non-empty set if the given storage appears to be supported by
{@link NetcdfStore}.
- * Returning a non-empty set from this method does not guarantee that
reading or writing will succeed,
+ * Returns {@link ProbeResult#SUPPORTED} if the given storage appears to
be supported by {@link NetcdfStore}.
+ * 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
* {@linkplain StorageConnector#getStorage() storage object} or contents.
*
* @param storage Information about the storage (URL, stream, {@link
ucar.nc2.NetcdfFile} instance, <i>etc</i>).
- * @return A non-empty set if the given storage seems to be usable by the
{@code NetcdfStore} instances,
- * an empty set if {@code NetcdfStore} will not be able to use the
given storage,
- * or {@code null} if this method does not have enough information.
+ * @return {@code SUPPORTED} if the given storage seems to be usable by
the {@code NetcdfStore} instances.
* @throws DataStoreException if an I/O error occurred.
*/
@Override
- public Set<OpenOption> getOpenCapabilities(StorageConnector storage)
throws DataStoreException {
+ public ProbeResult canOpen(StorageConnector storage) throws
DataStoreException {
final ByteBuffer buffer = storage.getStorageAs(ByteBuffer.class);
if (buffer != null) {
if (buffer.remaining() < Integer.SIZE / Byte.SIZE) {
- return Collections.singleton(OpenOption.UNKNOWN);
+ return ProbeResult.UNDETERMINED;
}
final int header = buffer.getInt(buffer.position());
if ((header & 0xFFFFFF00) == ChannelDecoder.MAGIC_NUMBER) {
- return OPTIONS;
+ return ProbeResult.SUPPORTED;
}
}
/*
@@ -140,7 +131,7 @@ public class NetcdfStoreProvider extends
ensureInitialized();
final Method method = canOpenFromPath;
if (method != null) try {
- return ((Boolean) method.invoke(null, path)) ? OPTIONS :
Collections.<OpenOption>emptySet();
+ return ((Boolean) method.invoke(null, path)) ?
ProbeResult.SUPPORTED : ProbeResult.UNKNOWN_FORMAT;
} catch (IllegalAccessException e) {
throw new AssertionError(e); // Should never happen, since the
method is public.
} catch (InvocationTargetException e) {
@@ -158,16 +149,14 @@ public class NetcdfStoreProvider extends
*/
for (Class<?> type = storage.getStorage().getClass(); type != null;
type = type.getSuperclass()) {
if (UCAR_CLASSNAME.equals(type.getName())) {
- return OPTIONS;
+ return ProbeResult.SUPPORTED;
}
}
- return Collections.emptySet();
+ return ProbeResult.UNKNOWN_FORMAT;
}
/**
- * Returns a {@link NetcdfStore} implementation associated with this
provider. This method invokes
- * {@link StorageConnector#closeAllExcept(Object)} after data store
creation, keeping open only
- * the needed resource.
+ * Returns a {@link NetcdfStore} implementation associated with this
provider.
*
* @param storage Information about the storage (URL, stream, {@link
ucar.nc2.NetcdfFile} instance, <i>etc</i>).
*/
Modified:
sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java?rev=1509300&r1=1509299&r2=1509300&view=diff
==============================================================================
---
sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java
[UTF-8] (original)
+++
sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java
[UTF-8] Thu Aug 1 15:33:07 2013
@@ -16,7 +16,6 @@
*/
package org.apache.sis.storage.netcdf;
-import java.util.Collections;
import java.io.IOException;
import ucar.nc2.NetcdfFile;
import org.opengis.wrapper.netcdf.IOTestCase;
@@ -25,7 +24,7 @@ import org.apache.sis.internal.netcdf.De
import org.apache.sis.internal.netcdf.ucar.DecoderWrapper;
import org.apache.sis.internal.netcdf.impl.ChannelDecoder;
import org.apache.sis.internal.netcdf.impl.ChannelDecoderTest;
-import org.apache.sis.storage.OpenOption;
+import org.apache.sis.storage.ProbeResult;
import org.apache.sis.storage.StorageConnector;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.test.DependsOn;
@@ -47,7 +46,7 @@ import static org.opengis.test.Assert.*;
})
public final strictfp class NetcdfStoreProviderTest extends IOTestCase {
/**
- * Tests {@link NetcdfStoreProvider#getOpenCapabilities(StorageConnector)}
for an input stream which shall
+ * Tests {@link NetcdfStoreProvider#canOpen(StorageConnector)} for an
input stream which shall
* be recognized as a classic NetCDF file.
*
* @throws DataStoreException Should never happen.
@@ -56,12 +55,12 @@ public final strictfp class NetcdfStoreP
public void testCanOpenFromStream() throws DataStoreException {
final StorageConnector c = new
StorageConnector(IOTestCase.class.getResourceAsStream(NCEP));
final NetcdfStoreProvider provider = new NetcdfStoreProvider();
- assertEquals(Collections.singleton(OpenOption.READ),
provider.getOpenCapabilities(c));
+ assertEquals(ProbeResult.SUPPORTED, provider.canOpen(c));
c.closeAllExcept(null);
}
/**
- * Tests {@link NetcdfStoreProvider#getOpenCapabilities(StorageConnector)}
for a UCAR {@link NetcdfFile} object.
+ * Tests {@link NetcdfStoreProvider#canOpen(StorageConnector)} for a UCAR
{@link NetcdfFile} object.
*
* @throws IOException If an error occurred while opening the NetCDF file.
* @throws DataStoreException Should never happen.
@@ -71,7 +70,7 @@ public final strictfp class NetcdfStoreP
final NetcdfFile file = open(NCEP);
final StorageConnector c = new StorageConnector(file);
final NetcdfStoreProvider provider = new NetcdfStoreProvider();
- assertEquals(Collections.singleton(OpenOption.READ),
provider.getOpenCapabilities(c));
+ assertEquals(ProbeResult.SUPPORTED, provider.canOpen(c));
file.close();
}
Modified:
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/IOUtilities.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/IOUtilities.java?rev=1509300&r1=1509299&r2=1509300&view=diff
==============================================================================
---
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/IOUtilities.java
[UTF-8] (original)
+++
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/IOUtilities.java
[UTF-8] Thu Aug 1 15:33:07 2013
@@ -28,6 +28,7 @@ import java.net.URISyntaxException;
import java.net.MalformedURLException;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
+import org.apache.sis.util.logging.Logging;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.Exceptions;
import org.apache.sis.util.Static;
@@ -37,7 +38,9 @@ import org.apache.sis.util.resources.Err
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
import java.nio.file.FileSystemNotFoundException;
+import java.nio.file.OpenOption;
import java.nio.charset.StandardCharsets;
@@ -53,7 +56,7 @@ import java.nio.charset.StandardCharsets
* @author Martin Desruisseaux (Geomatys)
* @author Johann Sorel (Geomatys)
* @since 0.3 (derived from geotk-3.00)
- * @version 0.3
+ * @version 0.4
* @module
*/
public final class IOUtilities extends Static {
@@ -337,10 +340,6 @@ public final class IOUtilities extends S
* A URL can represent a file, but {@link URL#openStream()} appears to
return a {@code BufferedInputStream}
* wrapping the {@link FileInputStream}, which is not a desirable feature
when we want to obtain a channel.
*
- * <p>There is no {@code toPathOrURL} methods because {@link Path} can be
associated to various file systems.
- * It would be possible (not necessarily desirable, but at least doable)
do create {@code Path} for HTTP or
- * FTP protocols.</p>
- *
* @param path The path to convert, or {@code null}.
* @param encoding If the URL is encoded in a {@code
application/x-www-form-urlencoded}
* MIME format, the character encoding (normally {@code "UTF-8"}).
If the URL is
@@ -366,8 +365,11 @@ public final class IOUtilities extends S
}
}
final URL url = new URL(path);
- if (url.getProtocol().equalsIgnoreCase("file")) {
- return toFile(url, encoding);
+ final String scheme = url.getProtocol();
+ if (scheme != null) {
+ if (scheme.equalsIgnoreCase("file")) {
+ return toFile(url, encoding);
+ }
}
return url;
}
@@ -384,15 +386,20 @@ public final class IOUtilities extends S
* or {@link CharSequence}, then a new channel is opened.</li>
* </ul>
*
+ * The given options are used for opening the channel on a <em>best effort
basis</em>.
+ * In particular, even if the caller provided the {@code WRITE} option, he
still needs
+ * to verify if the returned channel implements {@link
java.nio.channels.WritableByteChannel}.
+ *
* @param input The file to open, or {@code null}.
* @param encoding If the URL is encoded in a {@code
application/x-www-form-urlencoded}
* MIME format, the character encoding (normally {@code "UTF-8"}).
If the URL is
* not encoded, then {@code null}. This argument is ignored if the
given path does
* not need to be converted from URL to {@code File}.
+ * @param options The options to use for creating a new byte channel, or
an empty set for read-only.
* @return The input stream for the given file, or {@code null} if the
given type is unknown.
* @throws IOException If an error occurred while opening the given file.
*/
- public static ReadableByteChannel open(Object input, final String
encoding) throws IOException {
+ public static ReadableByteChannel open(Object input, final String
encoding, OpenOption... options) throws IOException {
if (input instanceof ReadableByteChannel) {
return (ReadableByteChannel) input;
}
@@ -407,21 +414,68 @@ public final class IOUtilities extends S
}
return Channels.newChannel((InputStream) input);
}
- if (input instanceof Path) {
- return Files.newByteChannel((Path) input);
- }
+ /*
+ * 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 (input instanceof CharSequence) { // Needs to be before the check
for File or URL.
input = toFileOrURL(input.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 (input instanceof File) {
- return new FileInputStream((File) input).getChannel();
+ try {
+ input = ((File) input).toPath();
+ } catch (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).
+ final ReadableByteChannel channel;
+ try {
+ channel = new FileInputStream((File) input).getChannel();
+ } catch (IOException ioe) {
+ ioe.addSuppressed(e);
+ throw ioe;
+ }
+ // We have been able to create a channel, maybe not with the
given OpenOptions.
+ // But the exception was nevertheless unexpected, so log its
stack trace in order
+ // to allow the developer to check if there is something wrong.
+
Logging.unexpectedException(Logging.getLogger("org.apache.sis.storage"),
IOUtilities.class, "open", e);
+ return channel;
+ }
}
+ /*
+ * If the user gave us a URI, try again to convert to a Path for the
same reasons than the above File case.
+ * A failure here is much more likely than in the File case, because
JDK7 does not provide file systems for
+ * HTTP or FTP protocols by default.
+ */
if (input instanceof URI) { // Needs to be before the check for URL.
- input = ((URI) input).toURL();
+ final URI uri = (URI) input;
+ try {
+ input = Paths.get(uri);
+ } catch (IllegalArgumentException | FileSystemNotFoundException e)
{
+ try {
+ input = uri.toURL();
+ } catch (IOException ioe) {
+ ioe.addSuppressed(e);
+ throw ioe;
+ }
+ // We have been able to create a channel, maybe not with the
given OpenOptions.
+ // Log the exception at a fine level and without stack trace,
because it was probably normal.
+
Logging.recoverableException(Logging.getLogger("org.apache.sis.storage"),
IOUtilities.class, "open", e);
+ }
}
if (input instanceof URL) {
return Channels.newChannel(((URL) input).openStream());
}
+ if (input instanceof Path) {
+ if (options == null) {
+ options = new OpenOption[0];
+ }
+ return Files.newByteChannel((Path) input, options);
+ }
return null;
}
}
Modified:
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreProvider.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreProvider.java?rev=1509300&r1=1509299&r2=1509300&view=diff
==============================================================================
---
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreProvider.java
[UTF-8] (original)
+++
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreProvider.java
[UTF-8] Thu Aug 1 15:33:07 2013
@@ -61,90 +61,73 @@ public abstract class DataStoreProvider
}
/**
- * Indicates how the given storage can be opened.
- * The set returned by this method will fall in one of the following cases:
+ * Indicates if the given storage appears to be supported by the {@code
DataStore}s created by this provider.
+ * The most typical return values are:
*
* <ul>
- * <li>If the {@code DataStore} managed by this provider can not open
the given storage,
- * then this method returns an empty set.</li>
- * <li>Otherwise if this method does not have enough information for
determining the
- * open capabilities, then this method returns a singleton
containing only the
- * {@link OpenOption#UNKNOWN} value.</li>
- * <li>Otherwise this method returns a set containing at least one, and
possibly many, of
- * {@link OpenOption#READ}, {@link OpenOption#WRITE WRITE}, {@link
OpenOption#APPEND APPEND},
- * {@link OpenOption#CREATE CREATE} or implementation-specific
values.</li>
+ * <li>{@link ProbeResult#SUPPORTED} if the {@code DataStore}s created
by this provider
+ * can open the given storage.</li>
+ * <li>{@link ProbeResult#UNKNOWN_STORAGE} if the given storage does not
appear to be in a format
+ * supported by this {@code DataStoreProvider}.</li>
* </ul>
*
- * Note that the later case does not guarantee that reading or writing
will succeed,
+ * Note that the {@code SUPPORTED_FORMAT} value 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
* {@linkplain StorageConnector#getStorage() storage object} or contents.
*
- * {@section Implementation note}
+ * Implementors are responsible for restoring the input to its original
stream position on return of this method.
+ * Implementors can use a mark/reset pair for this purpose. Marks are
available as
+ * {@link java.nio.ByteBuffer#mark()}, {@link
java.io.InputStream#mark(int)} and
+ * {@link javax.imageio.stream.ImageInputStream#mark()}.
+ *
+ * {@section Implementation example}
* Implementations will typically check the first bytes of the stream for
a "magic number" associated
* with the format, as in the following example:
*
* {@preformat java
- * public Set<OpenOption> getOpenCapabilities(StorageConnector
storage) throws DataStoreException {
+ * public ProbeResult canOpen(StorageConnector storage) throws
DataStoreException {
* final ByteBuffer buffer =
storage.getStorageAs(ByteBuffer.class);
- * if (buffer != null) {
- * if (buffer.remaining() < Integer.SIZE / Byte.SIZE) {
- * return Collections.singleton(OpenOption.UNKNOWN);
- * }
- * if (buffer.getInt(buffer.position()) == MAGIC_NUMBER) {
- * return Collections.singleton(OpenOption.READ);
- * }
+ * if (buffer == null) {
+ * // If StorageConnector can not provide a ByteBuffer, then
the storage is
+ * // probably not a File, URL, URI, InputStream neither a
ReadableChannel.
+ * return ProbeResult.UNKNOWN_STORAGE;
* }
- * return Collections.emptySet();
+ * if (buffer.remaining() < Integer.SIZE / Byte.SIZE) {
+ * // If the buffer does not contain enough bytes for the
integer type, this is not
+ * // necessarily because the file is truncated. It may be
because the data were not
+ * // yet available at the time this method has been invoked.
+ * return ProbeResult.UNDETERMINED;
+ * }
+ * if (buffer.getInt(buffer.position()) != MAGIC_NUMBER) {
+ * // We used ByteBuffer.getInt(int) instead than
ByteBuffer.getInt() above
+ * // in order to keep the buffer position unchanged after
this method call.
+ * return ProbeResult.UNKNOWN_FORMAT;
+ * }
+ * return ProbeResult.SUPPORTED;
* }
* }
*
- * {@note <ul>
- * <li>If <code>StorageConnector</code> can not provide a
<code>ByteBuffer</code>, then the storage is
- * probably not a <code>File</code>, <code>URL</code>,
<code>URI</code>, <code>InputStream</code>
- * neither a <code>ReadableChannel</code>. In the above example, our
provider can not handle such
- * unknown source.</li>
- * <li>Above example uses <code>ByteBuffer.getInt(int)</code> instead
than <code>ByteBuffer.getInt()</code>
- * in order to keep the buffer position unchanged after this method
call.</li>
- * <li>If the buffer does not contain enough bytes for the
<code>int</code> type, this is not necessarily
- * because the file is truncated. It may be because the data were
not yet available at the time this
- * method has been invoked. Returning <code>null</code> means "don't
know".</li>
- * </ul>}
- *
- * Implementors are responsible for restoring the input to its original
stream position on return of this method.
- * Implementors can use a mark/reset pair for this purpose. Marks are
available as
- * {@link java.nio.ByteBuffer#mark()}, {@link
java.io.InputStream#mark(int)} and
- * {@link javax.imageio.stream.ImageInputStream#mark()}.
- *
* @param storage Information about the storage (URL, stream, JDBC
connection, <i>etc</i>).
- * @return A non-empty set if the given storage seems to be usable by the
{@code DataStore} instances
- * create by this provider, an empty set if the {@code DataStore}
will not be able to use
- * the given storage, or {@code null} if this method does not have
enough information.
+ * @return {@link ProbeResult#SUPPORTED} if the given storage seems to be
readable by the {@code DataStore}
+ * instances created by this provider.
* @throws DataStoreException if an I/O or SQL error occurred. The error
shall be unrelated to the logical
* structure of the storage.
- *
- * @since 0.4
- */
- public abstract Set<OpenOption> getOpenCapabilities(StorageConnector
storage) throws DataStoreException;
-
- /**
- * @deprecated Replaced by {@link #getOpenCapabilities(StorageConnector)}.
*/
- @Deprecated
- public Boolean canOpen(StorageConnector storage) throws DataStoreException
{
- final Set<OpenOption> options = getOpenCapabilities(storage);
- return (options == null) ? null : options.contains(OpenOption.READ);
- }
+ public abstract ProbeResult canOpen(StorageConnector storage) throws
DataStoreException;
/**
* Returns a data store implementation associated with this provider.
*
- * <p><b>Implementation note:</b>
+ * {@section Implementation note}
* Implementors shall invoke {@link
StorageConnector#closeAllExcept(Object)} after {@code DataStore}
- * creation, keeping open only the needed resource.</p>
+ * creation, keeping open only the needed resource.
*
* @param storage Information about the storage (URL, stream, JDBC
connection, <i>etc</i>).
* @return A data store implementation associated with this provider for
the given storage.
- * @throws DataStoreException if an error occurred while creating the data
store instance.
+ * @throws IllegalArgumentException If the set contains an invalid
combination of options.
+ * @throws DataStoreException If an error occurred while creating the data
store instance.
+ *
+ * @see DataStores#open(Object, Set)
*/
public abstract DataStore open(StorageConnector storage) throws
DataStoreException;
}
Modified:
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreRegistry.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreRegistry.java?rev=1509300&r1=1509299&r2=1509300&view=diff
==============================================================================
---
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreRegistry.java
[UTF-8] (original)
+++
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreRegistry.java
[UTF-8] Thu Aug 1 15:33:07 2013
@@ -16,7 +16,6 @@
*/
package org.apache.sis.storage;
-import java.util.Set;
import java.util.ServiceLoader;
import org.apache.sis.util.ThreadSafe;
import org.apache.sis.util.ArgumentChecks;
@@ -78,21 +77,12 @@ final class DataStoreRegistry {
* </ul>
*
* @param storage The input/output object as a URL, file, image input
stream, <i>etc.</i>.
- * @param options The open options. Shall contain at least one element,
typically {@link OpenOption#READ}.
* @return The object to use for reading geospatial data from the given
storage.
* @throws UnsupportedStorageException if no {@link DataStoreProvider} is
found for a given storage object.
* @throws DataStoreException If an error occurred while opening the
storage.
*/
- public DataStore open(final Object storage, final Set<OpenOption> options)
throws DataStoreException {
+ public DataStore open(final Object storage) throws DataStoreException {
ArgumentChecks.ensureNonNull("storage", storage);
- ArgumentChecks.ensureNonNull("options", options);
- if (options.isEmpty()) {
- throw new
IllegalArgumentException(Errors.format(Errors.Keys.EmptyArgument_1, "options"));
- }
- if (options.contains(OpenOption.UNKNOWN)) {
- throw new IllegalArgumentException(Errors.format(
- Errors.Keys.IllegalArgumentValue_2, "options",
OpenOption.UNKNOWN));
- }
StorageConnector connector;
if (storage instanceof StorageConnector) {
connector = (StorageConnector) storage;
@@ -102,13 +92,16 @@ final class DataStoreRegistry {
try {
DataStoreProvider provider = null;
synchronized (loader) {
- for (final DataStoreProvider candidate : loader) {
- final Set<OpenOption> capabilities =
candidate.getOpenCapabilities(connector);
- if (capabilities.contains(OpenOption.UNKNOWN)) {
- // TODO: not enough information.
- } else if (capabilities.containsAll(options)) {
- provider = candidate;
- break;
+search: for (final DataStoreProvider candidate : loader) {
+ switch (candidate.canOpen(connector)) {
+ case SUPPORTED: {
+ provider = candidate;
+ break search;
+ }
+ case UNDETERMINED: {
+ // TODO: not enough information.
+ break;
+ }
}
}
}
Modified:
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStores.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStores.java?rev=1509300&r1=1509299&r2=1509300&view=diff
==============================================================================
---
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStores.java
[UTF-8] (original)
+++
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStores.java
[UTF-8] Thu Aug 1 15:33:07 2013
@@ -16,8 +16,6 @@
*/
package org.apache.sis.storage;
-import java.util.Set;
-import java.util.Collections;
import org.apache.sis.util.Static;
import org.apache.sis.internal.system.Modules;
import org.apache.sis.internal.system.SystemListener;
@@ -58,44 +56,13 @@ public final class DataStores extends St
}
/**
- * The options for opening storage in read mode.
- */
- private static final Set<OpenOption> READ =
Collections.singleton(OpenOption.READ);
-
- /**
* Do not allow instantiation of this class.
*/
private DataStores() {
}
/**
- * Creates a {@link DataStore} for the given storage using its default set
of {@code OpenOption}s.
- * The data store is guaranteed to be opened at least with {@link
OpenOption#READ}.
- * Whether the data store has also write or append capabilities is
implementation dependent.
- *
- * <p>The {@code storage} argument can be any of the following types:</p>
- *
- * <ul>
- * <li>A {@link java.nio.file.Path} or a {@link java.io.File} for a file
or a directory.</li>
- * <li>A {@link java.net.URI} or a {@link java.net.URL} to a distant
resource.</li>
- * <li>A {@link java.lang.CharSequence} interpreted as a filename or a
URL.</li>
- * <li>A {@link java.nio.channels.Channel} or a {@link
java.io.DataInput}.</li>
- * <li>A {@link javax.sql.DataSource} or a {@link java.sql.Connection}
to a JDBC database.</li>
- * <li>Any other {@code DataStore}-specific object, for example {@link
ucar.nc2.NetcdfFile}.</li>
- * <li>An existing {@link StorageConnector} instance.</li>
- * </ul>
- *
- * @param storage The input/output object as a URL, file, image input
stream, <i>etc.</i>.
- * @return The object to use for reading geospatial data from the given
storage.
- * @throws UnsupportedStorageException if no {@link DataStoreProvider} is
found for a given storage object.
- * @throws DataStoreException If an error occurred while opening the
storage.
- */
- public static DataStore open(final Object storage) throws
DataStoreException {
- return open(storage, READ);
- }
-
- /**
- * Creates a {@link DataStore} for the given storage using the given set
of {@code OpenOption}s.
+ * Creates a {@link DataStore} for the given storage.
* The {@code storage} argument can be any of the following types:
*
* <ul>
@@ -109,12 +76,11 @@ public final class DataStores extends St
* </ul>
*
* @param storage The input/output object as a URL, file, image input
stream, <i>etc.</i>.
- * @param options The open options. Shall contain at least one element,
typically {@link OpenOption#READ}.
* @return The object to use for reading geospatial data from the given
storage.
* @throws UnsupportedStorageException if no {@link DataStoreProvider} is
found for a given storage object.
* @throws DataStoreException If an error occurred while opening the
storage.
*/
- public static DataStore open(final Object storage, final Set<OpenOption>
options) throws DataStoreException {
+ public static DataStore open(final Object storage) throws
DataStoreException {
DataStoreRegistry r = registry;
if (r == null) {
synchronized (DataStores.class) {
@@ -124,6 +90,6 @@ public final class DataStores extends St
}
}
}
- return r.open(storage, options);
+ return r.open(storage);
}
}
Copied:
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/ProbeResult.java
(from r1509040,
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/OpenOption.java)
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/ProbeResult.java?p2=sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/ProbeResult.java&p1=sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/OpenOption.java&r1=1509040&r2=1509300&rev=1509300&view=diff
==============================================================================
---
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/OpenOption.java
[UTF-8] (original)
+++
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/ProbeResult.java
[UTF-8] Thu Aug 1 15:33:07 2013
@@ -16,71 +16,43 @@
*/
package org.apache.sis.storage;
-import java.util.List;
-import java.util.ArrayList;
-import org.opengis.util.CodeList;
-
/**
- * Specifies how to open a {@link DataStore}.
- * This code list serves a similar purpose than the {@code java.nio.file}
{@link java.nio.file.OpenOption},
- * except that it applies to data stores instead than files. The options
provided by this code list are very
- * similar to the {@code java.nio.file} ones except for {@link #UNKNOWN}.
+ * Tells whether a storage (file, database, <i>etc.</i>) appears to be
supported by a {@code DataStore}.
+ * There is three categories of values in this enumeration:
+ *
+ * <ul>
+ * <li>{@link #SUPPORTED} indicates that the storage can be read and
eventually written.</li>
+ * <li>{@link #UNDETERMINED} indicates that the provider does not have
enough information for telling
+ * whether the storage can be opened. SIS will try to use such provider
last, if no better suited
+ * provider is found.</li>
+ * <li>All other values indicate that the storage can not be opened. The
actual enumeration value gives
+ * the reason (e.g. unknown format, or unsupported version).</li>
+ * </ul>
*
- * <p>This code list is extensible: some {@code DataStore} subclasses may
provide their own implementation
- * specific open options.</p>
+ * When a {@link DataStores#open DataStores.open(…)} method is invoked, SIS
will iterate over the list of known
+ * providers and invoke the {@link
DataStoreProvider#canOpen(StorageConnector)} method for each of them.
+ * The {@code ProbeResult} value returned by {@code canOpen(…)} tells to SIS
whether a particular
+ * {@code DataStoreProvider} instance has reasonable chances to be able to
handle the given storage.
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.4
* @version 0.4
* @module
*
- * @see java.nio.file.OpenOption
+ * @see DataStoreProvider#canOpen(StorageConnector)
*/
-public final class OpenOption extends CodeList<OpenOption> {
- /**
- * For cross-version compatibility.
- */
- private static final long serialVersionUID = -892034640198004572L;
-
+public enum ProbeResult {
/**
- * List of all enumerations of this type.
- * Shall be declared before any enum declaration.
+ * The {@code DataStoreProvider} recognizes the given storage.
+ * {@code DataStore} instances created by that provider are likely (but
not guaranteed)
+ * to be able to read from - and eventually write to - the given storage.
*/
- private static final List<OpenOption> VALUES = new ArrayList<>(5);
+ SUPPORTED,
/**
- * Open for reading data from a {@link DataStore}.
- *
- * @see java.nio.file.StandardOpenOption#READ
- */
- public static final OpenOption READ = new OpenOption("READ");
-
- /**
- * Open for overwriting existing data in a {@link DataStore}.
- *
- * @see java.nio.file.StandardOpenOption#WRITE
- */
- public static final OpenOption WRITE = new OpenOption("WRITE");
-
- /**
- * Open for appending new data in a {@link DataStore}.
- *
- * @see java.nio.file.StandardOpenOption#APPEND
- */
- public static final OpenOption APPEND = new OpenOption("APPEND");
-
- /**
- * Creates a new file or database if it does not exist.
- *
- * @see java.nio.file.StandardOpenOption#CREATE
- */
- public static final OpenOption CREATE = new OpenOption("CREATE");
-
- /**
- * Indicates that the open capabilities can not be determined.
- * This value may be returned by {@linkplain
DataStoreProvider#getOpenCapabilities(StorageConnector)}
- * in two kind of situations:
+ * The open capability can not be determined.
+ * This value may be returned in two kinds of situation:
*
* <ul>
* <li>The method can not look ahead far enough in the file header,
@@ -88,54 +60,25 @@ public final class OpenOption extends Co
* <li>The {@code DataStore} could potentially open anything.
* This is the case for example of the RAW image format.</li>
* </ul>
- *
- * This option is exclusive with all other options.
*/
- public static final OpenOption UNKNOWN = new OpenOption("UNKNOWN");
+ UNDETERMINED,
/**
- * Creates a new code list element of the given name.
- * The new element is automatically added to the {@link #VALUES} list.
- *
- * @param name The name of the new element. Must be unique in this code
list.
+ * The {@code DataStoreProvider} does not recognize the given storage
object.
+ * For example the storage may be a file while the provider expected a
database connection, or conversely.
*/
- private OpenOption(final String name) {
- super(name, VALUES);
- }
+ UNKNOWN_STORAGE,
/**
- * Returns the list of {@code OpenOption}s.
- *
- * @return The list of open options declared in the current JVM.
+ * The {@code DataStoreProvider} does not recognize the file format or
schema.
+ * For example the file does not contains the expected magic number,
+ * or the database schema does not contain the expected tables.
*/
- public static OpenOption[] values() {
- synchronized (VALUES) {
- return VALUES.toArray(new OpenOption[VALUES.size()]);
- }
- }
+ UNKNOWN_FORMAT,
/**
- * Returns the list of codes of the same kind than this code list element.
- * Invoking this method is equivalent to invoking {@link #values()},
except that
- * this method can be invoked on an instance of the parent {@code
CodeList} class.
- *
- * @return The list of open options declared in the current JVM.
- */
- @Override
- public OpenOption[] family() {
- return values();
- }
-
- /**
- * Returns the open option that matches the given string, or returns a new
one if none match it.
- * More specifically, this methods returns the first instance for which
- * <code>{@linkplain #name() name()}.{@linkplain String#equals
equals}(code)</code> returns {@code true}.
- * If no existing instance is found, then a new one is created for the
given name.
- *
- * @param code The name of the code to fetch or to create.
- * @return A code matching the given name.
+ * The {@code DataStoreProvider} recognizes the given storage, but the
data are structured
+ * according a file or schema version not yet supported by the current
implementation.
*/
- public static OpenOption valueOf(String code) {
- return valueOf(OpenOption.class, code);
- }
+ UNSUPPORTED_VERSION
}
Modified:
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java?rev=1509300&r1=1509299&r2=1509300&view=diff
==============================================================================
---
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
[UTF-8] (original)
+++
sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
[UTF-8] Thu Aug 1 15:33:07 2013
@@ -164,6 +164,7 @@ public class StorageConnector implements
*
* <ul>
* <li>{@link OptionKey#URL_ENCODING} for converting URL to URI or
filename, if needed.</li>
+ * <li>{@link OptionKey#OPEN_OPTIONS} for specifying whether the data
store shall be read only or read/write.</li>
* <li>{@link OptionKey#BYTE_BUFFER} for allowing users to control the
byte buffer to be created.</li>
* </ul>
*
@@ -296,8 +297,8 @@ public class StorageConnector implements
*
* Multiple invocations of this method on the same {@code
StorageConnector} instance will try
* to return the same instance on a <cite>best effort</cite> basis.
Consequently, implementations of
- * {@link DataStoreProvider#getOpenCapabilities(StorageConnector)} methods
shall not close the stream or
- * database connection returned by this method. In addition, those {@code
getOpenCapabilities(StorageConnector)}
+ * {@link DataStoreProvider#canOpen(StorageConnector)} methods shall not
close the stream or
+ * database connection returned by this method. In addition, those {@code
canOpen(StorageConnector)}
* methods are responsible for restoring the stream or byte buffer to its
original position on return.
*
* @param <T> The compile-time type of the {@code type} argument.
@@ -368,7 +369,8 @@ public class StorageConnector implements
* @throws IOException If an error occurred while opening a channel for
the input.
*/
private void createChannelDataInput(final boolean asImageInputStream)
throws IOException {
- final ReadableByteChannel channel = IOUtilities.open(storage,
getOption(OptionKey.URL_ENCODING));
+ final ReadableByteChannel channel = IOUtilities.open(storage,
+ getOption(OptionKey.URL_ENCODING),
getOption(OptionKey.OPEN_OPTIONS));
ChannelDataInput asDataInput = null;
if (channel != null) {
ByteBuffer buffer = getOption(OptionKey.BYTE_BUFFER);