sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1515763 [1/2] - in /sis/branches/JDK6: ./ application/sis-console/src/main/java/org/apache/sis/console/ application/sis-console/src/main/resources/org/apache/sis/console/ core/sis-utility/src/main/java/org/apache/sis/internal/util/ core/si...
Date Tue, 20 Aug 2013 10:35:43 GMT
Author: desruisseaux
Date: Tue Aug 20 10:35:42 2013
New Revision: 1515763

URL: http://svn.apache.org/r1515763
Log:
Merge from the JDK7 branch, with omission of java.nio.file.spi.FileTypeDetector service.

Added:
    sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/MimeTypeSC.java
      - copied, changed from r1515760, sis/branches/JDK7/application/sis-console/src/main/java/org/apache/sis/console/MimeTypeSC.java
    sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/util/ExceptionsTest.java
      - copied unchanged from r1515760, sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/ExceptionsTest.java
    sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/MimeTypeDetector.java
      - copied, changed from r1515760, sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/MimeTypeDetector.java
    sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/storage/ProbeProviderPair.java
      - copied unchanged from r1515760, sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/ProbeProviderPair.java
    sis/branches/JDK6/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/xml/MimeTypeDetectorTest.java
      - copied unchanged from r1515760, sis/branches/JDK7/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/xml/MimeTypeDetectorTest.java
    sis/branches/JDK6/storage/sis-storage/src/test/java/org/apache/sis/storage/DataStoresTest.java
      - copied unchanged from r1515760, sis/branches/JDK7/storage/sis-storage/src/test/java/org/apache/sis/storage/DataStoresTest.java
    sis/branches/JDK6/storage/sis-storage/src/test/java/org/apache/sis/storage/ProbeResultTest.java
      - copied unchanged from r1515760, sis/branches/JDK7/storage/sis-storage/src/test/java/org/apache/sis/storage/ProbeResultTest.java
Modified:
    sis/branches/JDK6/   (props changed)
    sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/Command.java
    sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/HelpSC.java
    sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/MetadataSC.java
    sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/SubCommand.java
    sis/branches/JDK6/application/sis-console/src/main/resources/org/apache/sis/console/Commands.properties
    sis/branches/JDK6/application/sis-console/src/main/resources/org/apache/sis/console/Commands_fr.properties
    sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java
    sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/Exceptions.java
    sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/Version.java
    sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
    sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
    sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
    sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/internal/util/UtilitiesTest.java
    sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
    sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/util/VersionTest.java
    sis/branches/JDK6/ide-project/NetBeans/build.xml
    sis/branches/JDK6/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java
    sis/branches/JDK6/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java
    sis/branches/JDK6/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java
    sis/branches/JDK6/storage/sis-storage/pom.xml
    sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/IOUtilities.java
    sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/XMLStoreProvider.java
    sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreProvider.java
    sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreRegistry.java
    sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStores.java
    sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/storage/ProbeResult.java
    sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
    sis/branches/JDK6/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/xml/XMLStoreProviderTest.java
    sis/branches/JDK6/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/xml/XMLStoreTest.java
    sis/branches/JDK6/storage/sis-storage/src/test/java/org/apache/sis/test/suite/StorageTestSuite.java

Propchange: sis/branches/JDK6/
------------------------------------------------------------------------------
  Merged /sis/branches/JDK7:r1514389-1515760

Modified: sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/Command.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/Command.java?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/Command.java [UTF-8] (original)
+++ sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/Command.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -24,7 +24,6 @@ import java.io.IOException;
 import java.sql.SQLException;
 import org.opengis.referencing.operation.TransformException;
 import org.apache.sis.storage.DataStoreException;
-import org.apache.sis.util.Exceptions;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.logging.MonolineFormatter;
 
@@ -35,6 +34,7 @@ import org.apache.sis.util.logging.Monol
  * <blockquote><table class="compact">
  * <tr><td>{@code help}     </td><td>Show a help overview.</td></tr>
  * <tr><td>{@code about}    </td><td>Show information about Apache SIS and system configuration.</td></tr>
+ * <tr><td>{@code mime-type}</td><td>Show MIME type for the given file.</td></tr>
  * <tr><td>{@code metadata} </td><td>Show metadata information for the given file.</td></tr>
  * </table></blockquote>
  *
@@ -146,9 +146,10 @@ public final class Command {
             command = new HelpSC(-1, args);
         } else {
             commandName = commandName.toLowerCase(Locale.US);
-                 if (commandName.equals("about"))    command = new AboutSC   (commandIndex, args);
-            else if (commandName.equals("help"))     command = new HelpSC    (commandIndex, args);
-            else if (commandName.equals("metadata")) command = new MetadataSC(commandIndex, args);
+                 if (commandName.equals("about"))     command = new AboutSC   (commandIndex, args);
+            else if (commandName.equals("help"))      command = new HelpSC    (commandIndex, args);
+            else if (commandName.equals("mime-type")) command = new MimeTypeSC(commandIndex, args);
+            else if (commandName.equals("metadata"))  command = new MetadataSC(commandIndex, args);
             else throw new InvalidCommandException(Errors.format(
                         Errors.Keys.UnknownCommand_1, commandName), commandName);
         }
@@ -173,8 +174,7 @@ public final class Command {
         } else try {
             return command.run();
         } catch (Exception e) {
-            command.out.flush();
-            command.err.println(Exceptions.formatChainedMessages(command.locale, null, e));
+            command.error(null, e);
             throw e;
         }
         return 0;
@@ -221,7 +221,8 @@ public final class Command {
      *
      * @param args Command-line options.
      */
-    public static void main(final String[] args) {
+    public static void main(String[] args) {
+        args = new String[] {"mime-type", "/Users/desruisseaux/Projets/SIS/JDK7/target/binaries/../../../../GeoAPI/trunk//geoapi-netcdf/src/test/resources/org/opengis/wrapper/netcdf/NCEP-SST.nc"};
         MonolineFormatter.install();
         final Command c;
         try {

Modified: sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/HelpSC.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/HelpSC.java?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/HelpSC.java [UTF-8] (original)
+++ sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/HelpSC.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -39,6 +39,7 @@ final class HelpSC extends SubCommand {
     private static final String[] COMMANDS = {
         "help",
         "about",
+        "mime-type",
         "metadata"
     };
 

Modified: sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/MetadataSC.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/MetadataSC.java?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/MetadataSC.java [UTF-8] (original)
+++ sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/MetadataSC.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -39,7 +39,7 @@ import org.apache.sis.xml.XML;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.3
+ * @version 0.4
  * @module
  */
 final class MetadataSC extends SubCommand {
@@ -53,9 +53,7 @@ final class MetadataSC extends SubComman
     /**
      * Prints metadata information.
      *
-     * @todo NetCDF data store is hard-coded for now. Will need a dynamic mechanism in the future.
-     *
-     * @throws DataStoreException If an error occurred while reading the NetCDF file.
+     * @throws DataStoreException If an error occurred while reading the file.
      * @throws JAXBException If an error occurred while producing the XML output.
      * @throws IOException Should never happen, since we are appending to a print writer.
      */

Copied: sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/MimeTypeSC.java (from r1515760, sis/branches/JDK7/application/sis-console/src/main/java/org/apache/sis/console/MimeTypeSC.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/MimeTypeSC.java?p2=sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/MimeTypeSC.java&p1=sis/branches/JDK7/application/sis-console/src/main/java/org/apache/sis/console/MimeTypeSC.java&r1=1515760&r2=1515763&rev=1515763&view=diff
==============================================================================
--- sis/branches/JDK7/application/sis-console/src/main/java/org/apache/sis/console/MimeTypeSC.java [UTF-8] (original)
+++ sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/MimeTypeSC.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -24,12 +24,6 @@ import org.apache.sis.storage.DataStores
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.util.resources.Errors;
 
-// Related to JDK7.
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.FileSystemNotFoundException;
-
 
 /**
  * The "mime-type" subcommand.
@@ -73,13 +67,8 @@ final class MimeTypeSC extends SubComman
             // If the URI is not absolute, we will not be able to convert to Path.
             // Open as a String, leaving the conversion to DataStore implementations.
             type = DataStores.probeContentType(file);
-        } else try {
-            type = Files.probeContentType(Paths.get(uri));
-        } catch (IllegalArgumentException | FileSystemNotFoundException e) {
+        } else {
             type = DataStores.probeContentType(uri);
-        } catch (NoSuchFileException e) {
-            error(Errors.format(Errors.Keys.CanNotOpen_1, uri), e);
-            return Command.IO_EXCEPTION_EXIT_CODE;
         }
         if (type != null) {
             out.println(type);

Modified: sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/SubCommand.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/SubCommand.java?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/SubCommand.java [UTF-8] (original)
+++ sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/SubCommand.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -28,6 +28,7 @@ import java.io.StringWriter;
 import java.io.OutputStreamWriter;
 import java.nio.charset.Charset;
 import org.apache.sis.util.Locales;
+import org.apache.sis.util.Exceptions;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.internal.util.X364;
 
@@ -278,6 +279,27 @@ abstract class SubCommand {
     }
 
     /**
+     * Prints the "<cite>Can not open …</cite>" error message followed by the message in the given exception.
+     *
+     * @param fileIndex Index in the {@link #files} list of the file that can not be opened.
+     * @param e The exception which occurred.
+     */
+    final void canNotOpen(final int fileIndex, final Exception e) {
+        error(Errors.format(Errors.Keys.CanNotOpen_1, files.get(fileIndex)), e);
+    }
+
+    /**
+     * Prints the given error message followed by the message in the given exception.
+     *
+     * @param message The message to print before the exception, or {@code null}.
+     * @param e The exception which occurred.
+     */
+    final void error(final String message, final Exception e) {
+        out.flush();
+        err.println(Exceptions.formatChainedMessages(locale, message, e));
+    }
+
+    /**
      * Shows the help instructions for a specific command. This method is invoked
      * instead of {@link #run()} if the the user provided the {@code --help} option.
      *

Modified: sis/branches/JDK6/application/sis-console/src/main/resources/org/apache/sis/console/Commands.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/application/sis-console/src/main/resources/org/apache/sis/console/Commands.properties?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/application/sis-console/src/main/resources/org/apache/sis/console/Commands.properties [ISO-8859-1] (original)
+++ sis/branches/JDK6/application/sis-console/src/main/resources/org/apache/sis/console/Commands.properties [ISO-8859-1] Tue Aug 20 10:35:42 2013
@@ -4,4 +4,5 @@ Usage=Usage: sis <command> [options] [fi
 
 help=Show a help overview.
 about=Show information about Apache SIS and system configuration.
+mime-type=Show MIME type for the given file.
 metadata=Show metadata information for the given file.

Modified: sis/branches/JDK6/application/sis-console/src/main/resources/org/apache/sis/console/Commands_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/application/sis-console/src/main/resources/org/apache/sis/console/Commands_fr.properties?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/application/sis-console/src/main/resources/org/apache/sis/console/Commands_fr.properties [ISO-8859-1] (original)
+++ sis/branches/JDK6/application/sis-console/src/main/resources/org/apache/sis/console/Commands_fr.properties [ISO-8859-1] Tue Aug 20 10:35:42 2013
@@ -4,4 +4,5 @@ Usage=Usage: sis <commande> [options] [f
 
 help=Affiche un écran d\u2019aide.
 about=Affiche des informations à propos de Apache SIS et de la configuration du système.
+mime-type=Affiche le type MIME du fichier spécifié.
 metadata=Affiche les méta-données du fichier spécifié.

Modified: sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -19,6 +19,7 @@ package org.apache.sis.internal.util;
 import java.util.Formatter;
 import java.util.FormattableFlags;
 import org.apache.sis.util.Static;
+import org.apache.sis.util.Classes;
 import org.apache.sis.util.CharSequences;
 
 import static java.lang.Math.abs;
@@ -30,7 +31,7 @@ import static java.lang.Math.max;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-3.00)
- * @version 0.3
+ * @version 0.4
  * @module
  */
 public final class Utilities extends Static {
@@ -117,6 +118,37 @@ public final class Utilities extends Sta
     }
 
     /**
+     * Returns a string representation of an instance of the given class having the given properties.
+     * This is a convenience method for implementation of {@link Object#toString()} methods that are
+     * used mostly for debugging purpose.
+     *
+     * @param  classe     The class to format.
+     * @param  properties The (<var>key</var>=</var>value</var>) pairs.
+     * @return A string representation of an instance of the given class having the given properties.
+     *
+     * @since 0.4
+     */
+    public static String toString(final Class<?> classe, final Object... properties) {
+        final StringBuffer buffer = new StringBuffer(32).append(Classes.getShortName(classe)).append('[');
+        boolean isNext = false;
+        for (int i=0; i<properties.length; i++) {
+            final Object value = properties[++i];
+            if (value != null) {
+                if (isNext) {
+                    buffer.append(", ");
+                }
+                buffer.append(properties[i-1]).append('=');
+                final boolean isText = (value instanceof CharSequence);
+                if (isText) buffer.append('“');
+                buffer.append(value);
+                if (isText) buffer.append('”');
+                isNext = true;
+            }
+        }
+        return buffer.append(']').toString();
+    }
+
+    /**
      * Formats the given character sequence to the given formatter. This method takes in account
      * the {@link FormattableFlags#UPPERCASE} and {@link FormattableFlags#LEFT_JUSTIFY} flags.
      *

Modified: sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/Exceptions.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/Exceptions.java?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/Exceptions.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/Exceptions.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -16,8 +16,8 @@
  */
 package org.apache.sis.util;
 
-import java.util.Set;
-import java.util.HashSet;
+import java.util.List;
+import java.util.ArrayList;
 import java.util.Locale;
 import java.sql.SQLException;
 import org.apache.sis.internal.util.LocalizedException;
@@ -33,7 +33,7 @@ import org.apache.sis.internal.jdk7.JDK7
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.3 (derived from geotk-2.0)
- * @version 0.3
+ * @version 0.4
  * @module
  */
 public final class Exceptions extends Static {
@@ -127,34 +127,24 @@ public final class Exceptions extends St
      *         and no exception provide a message.
      */
     public static String formatChainedMessages(final Locale locale, String header, Throwable cause) {
-        Set<CharSequence> done = null;
+        List<String> previousLines = null;
         String lineSeparator = null;
         StringBuilder buffer = null;
         while (cause != null) {
             final String message = trimWhitespaces(getLocalizedMessage(cause, locale));
             if (message != null && !message.isEmpty()) {
                 if (buffer == null) {
-                    done = new HashSet<CharSequence>();
                     buffer = new StringBuilder(128);
                     lineSeparator = JDK7.lineSeparator();
+                    previousLines = new ArrayList<String>(4);
                     header = trimWhitespaces(header);
                     if (header != null && !header.isEmpty()) {
                         buffer.append(header);
-                        done.add(header);
-                        /*
-                         * The folowing is for avoiding to repeat the same message in the
-                         * common case where the header contains the exception class name
-                         * followed by the message, as in:
-                         *
-                         * FooException: InnerException: the inner message.
-                         */
-                        int s=0;
-                        while ((s=header.indexOf(':', s)) >= 0) {
-                            done.add(trimWhitespaces(header, ++s, header.length()));
-                        }
+                        previousLines.add(header);
                     }
                 }
-                if (done.add(message)) {
+                if (!contains(previousLines, message)) {
+                    previousLines.add(message);
                     if (buffer.length() != 0) {
                         buffer.append(lineSeparator);
                     }
@@ -175,4 +165,17 @@ public final class Exceptions extends St
         }
         return header;
     }
+
+    /**
+     * Returns {@code true} if a previous line contains the given exception message.
+     */
+    private static boolean contains(final List<String> previousLines, final String message) {
+        for (int i=previousLines.size(); --i>=0;) {
+            final int p = previousLines.get(i).indexOf(message);
+            if (p >= 0) {
+                return true;
+            }
+        }
+        return false;
+    }
 }

Modified: sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/Version.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/Version.java?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/Version.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/Version.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -18,6 +18,7 @@ package org.apache.sis.util;
 
 import java.io.Serializable;
 import java.util.StringTokenizer;
+import org.apache.sis.util.resources.Errors;
 
 
 /**
@@ -31,9 +32,9 @@ import java.util.StringTokenizer;
  * <p>This class provides methods for performing comparisons of {@code Version} objects where major,
  * minor and revision parts are compared as numbers when possible, or as strings otherwise.</p>
  *
- * @author  Martin Desruisseaux (IRD)
+ * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.3 (derived from geotk-2.4)
- * @version 0.3
+ * @version 0.4
  * @module
  */
 @Immutable
@@ -44,15 +45,26 @@ public class Version implements CharSequ
     private static final long serialVersionUID = 8402041502662929792L;
 
     /**
+     * The separator characters between {@linkplain #getMajor() major}, {@linkplain #getMinor() minor}
+     * and {@linkplain #getRevision() revision} components. Any character in this string fits.
+     */
+    private static final String SEPARATORS = ".-";
+
+    /**
      * The version of this Apache SIS distribution.
      */
     public static final Version SIS = new Version("0.4-SNAPSHOT");
 
     /**
-     * The separator characters between {@linkplain #getMajor() major}, {@linkplain #getMinor() minor}
-     * and {@linkplain #getRevision() revision} components. Any character in this string fits.
+     * A few commonly used version numbers. This list is based on SIS needs, e.g. in {@code DataStore}
+     * implementations. New constants are likely to be added in any future SIS versions.
+     *
+     * @see #valueOf(int[])
      */
-    private static final String SEPARATORS = ".-";
+    private static final Version[] CONSTANTS = {
+        new Version("1"),
+        new Version("2")
+    };
 
     /**
      * The version in string form, with leading and trailing spaces removed.
@@ -81,7 +93,56 @@ public class Version implements CharSequ
      */
     public Version(final String version) {
         ArgumentChecks.ensureNonNull("version", version);
-        this.version = CharSequences.trimWhitespaces(version);
+        this.version = version;
+    }
+
+    /**
+     * Returns an instance for the given integer values.
+     * The {@code components} array must contain at least 1 element, where:
+     *
+     * <ul>
+     *   <li>The first element is the {@linkplain #getMajor() major} number.</li>
+     *   <li>The second element (if any) is the {@linkplain #getMinor() minor} number.</li>
+     *   <li>The third element (if any) is the {@linkplain #getRevision() revision} number.</li>
+     *   <li>Other elements (if any) will be appended to the {@link #toString() string value}.</li>
+     * </ul>
+     *
+     * @param  components The major number, optionally followed by minor, revision or other numbers.
+     * @return A new or existing instance of {@code Version} for the given numbers.
+     *
+     * @since 0.4
+     */
+    public static Version valueOf(final int... components) {
+        if (components.length == 0) {
+            throw new IllegalArgumentException(Errors.format(Errors.Keys.EmptyArgument_1, "components"));
+        }
+        final Version version;
+        final int major = components[0];
+        if (components.length == 1) {
+            if (major >= 1 && major <= CONSTANTS.length) {
+                return CONSTANTS[major-1];
+            } else {
+                version = new Version(Integer.toString(major));
+            }
+        } else {
+            final StringBuilder buffer = new StringBuilder().append(major);
+            for (int i=1; i<components.length; i++) {
+                buffer.append('.').append(components[i]);
+            }
+            version = new Version(buffer.toString());
+        }
+        /*
+         * Pre-compute the 'parsed' array since we already have the integer values. It will avoid the need to
+         * create the 'this.components' array and to parse the String values if a 'getFoo()' method is invoked.
+         * Note that the cost is typically only the 'parsed' array creation, not Integer objects creation, since
+         * version numbers are usually small enough for allowing 'Integer.valueOf(int)' to cache them.
+         */
+        final Integer[] parsed = new Integer[components.length];
+        for (int i=0; i<components.length; i++) {
+            parsed[i] = components[i];
+        }
+        version.parsed = parsed;
+        return version;
     }
 
     /**

Modified: sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -316,6 +316,11 @@ public final class Errors extends Indexe
         public static final int MissingRequiredModule_1 = 84;
 
         /**
+         * Missing scheme in URI.
+         */
+        public static final int MissingSchemeInURI = 109;
+
+        /**
          * Missing value for option “{0}”.
          */
         public static final int MissingValueForOption_1 = 99;

Modified: sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] (original)
+++ sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] Tue Aug 20 10:35:42 2013
@@ -74,6 +74,7 @@ MismatchedCRS                   = The co
 MismatchedDimension_2           = Mismatched object dimension: {0}D and {1}D.
 MismatchedDimension_3           = Argument \u2018{0}\u2019 has {2} dimension{2,choice,1#|2#s}, while {1} was expected.
 MissingRequiredModule_1         = This operation requires the \u201c{0}\u201d module.
+MissingSchemeInURI              = Missing scheme in URI.
 MissingValueForOption_1         = Missing value for option \u201c{0}\u201d.
 MissingValueForProperty_1       = Missing value for property \u201c{0}\u201d.
 MissingValueInColumn_1          = Missing value in the \u201c{0}\u201d column.

Modified: sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties [ISO-8859-1] (original)
+++ sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties [ISO-8859-1] Tue Aug 20 10:35:42 2013
@@ -64,6 +64,7 @@ MismatchedCRS                   = Le sys
 MismatchedDimension_2           = Les dimensions des objets ({0}D et {1}D) ne concordent pas.
 MismatchedDimension_3           = L\u2019argument \u2018{0}\u2019 a {2} dimension{2,choice,1#|2#s}, alors qu\u2019on en attendait {1}.
 MissingRequiredModule_1         = Cette op\u00e9ration requiert le module \u201c{0}\u201d.
+MissingSchemeInURI              = Il manque le sch\u00e9ma d\u2019URI.
 MissingValueForOption_1         = Aucune valeur n\u2019a \u00e9t\u00e9 d\u00e9finie pour l\u2019option \u201c{0}\u201d.
 MissingValueForProperty_1       = Aucune valeur n\u2019a \u00e9t\u00e9 d\u00e9finie pour la propri\u00e9t\u00e9 \u201c{0}\u201d.
 MissingValueInColumn_1          = Il manque une valeur dans la colonne \u201c{0}\u201d.

Modified: sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/internal/util/UtilitiesTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/internal/util/UtilitiesTest.java?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/internal/util/UtilitiesTest.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/internal/util/UtilitiesTest.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -31,7 +31,7 @@ import static org.apache.sis.test.Assert
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.3
+ * @version 0.4
  * @module
  */
 public final strictfp class UtilitiesTest extends TestCase {
@@ -51,4 +51,12 @@ public final strictfp class UtilitiesTes
         assertTrue (epsilonEqual(-100, -100 + COMPARISON_THRESHOLD * 50));
         assertFalse(epsilonEqual( 100,  100 + COMPARISON_THRESHOLD * 150));
     }
+
+    /**
+     * Tests the {@link Utilities#toString(Class, Object[])} method.
+     */
+    @Test
+    public void testToString() {
+        assertEquals("Number[base=“decimal”, value=20]", Utilities.toString(Number.class, "base", "decimal", "value", 20));
+    }
 }

Modified: sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -26,7 +26,7 @@ import org.junit.BeforeClass;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.3
+ * @version 0.4
  * @module
  */
 @Suite.SuiteClasses({
@@ -41,6 +41,7 @@ import org.junit.BeforeClass;
     org.apache.sis.util.CharactersTest.class,
     org.apache.sis.util.CharSequencesTest.class,
     org.apache.sis.util.StringBuildersTest.class,
+    org.apache.sis.util.ExceptionsTest.class,
     org.apache.sis.util.UtilitiesTest.class,
     org.apache.sis.util.NumbersTest.class,
     org.apache.sis.util.ClassesTest.class,

Modified: sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/util/VersionTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/util/VersionTest.java?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/util/VersionTest.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/util/VersionTest.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.util;
 
+import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
@@ -25,9 +26,9 @@ import static org.apache.sis.test.Assert
 /**
  * Tests the {@link Version} class, especially the {@code compareTo} method.
  *
- * @author  Martin Desruisseaux (IRD)
+ * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.3 (derived from geotk-2.4)
- * @version 0.3
+ * @version 0.4
  * @module
  */
 public final strictfp class VersionTest extends TestCase {
@@ -54,6 +55,7 @@ public final strictfp class VersionTest 
      * Tests a alpha-numeric version.
      */
     @Test
+    @DependsOnMethod("testNumeric")
     public void testAlphaNumeric() {
         final Version version = new Version("1.6.b2");
         assertEquals("1.6.b2", version.toString());
@@ -69,6 +71,48 @@ public final strictfp class VersionTest 
     }
 
     /**
+     * Tests the {@link Version#valueOf(int[])} method.
+     */
+    @Test
+    public void testValueOf() {
+        Version version = Version.valueOf(1);
+        assertEquals("1", version.toString());
+        assertEquals( 1,  version.getMajor());
+        assertNull  (     version.getMinor());
+        assertNull  (     version.getRevision());
+
+        version = Version.valueOf(10);
+        assertEquals("10", version.toString());
+        assertEquals( 10,  version.getMajor());
+        assertNull  (      version.getMinor());
+        assertNull  (      version.getRevision());
+
+        version = Version.valueOf(0, 4);
+        assertEquals("0.4", version.toString());
+        assertEquals( 0,    version.getMajor());
+        assertEquals(   4,  version.getMinor());
+        assertNull  (       version.getRevision());
+
+        version = Version.valueOf(6, 11, 2);
+        assertEquals("6.11.2", version.toString());
+        assertEquals( 6,       version.getMajor());
+        assertEquals(   11,    version.getMinor());
+        assertEquals(      2,  version.getRevision());
+    }
+
+    /**
+     * Tests the cached values of {@link Version#valueOf(int[])}.
+     */
+    @Test
+    @DependsOnMethod("testValueOf")
+    public void testCachedValueOf() {
+        for (int major=1; major<=2; major++) {
+            final Version version = Version.valueOf(major);
+            assertSame(version.toString(), version, Version.valueOf(major));
+        }
+    }
+
+    /**
      * Tests serialization.
      */
     @Test

Modified: sis/branches/JDK6/ide-project/NetBeans/build.xml
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/ide-project/NetBeans/build.xml?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/ide-project/NetBeans/build.xml (original)
+++ sis/branches/JDK6/ide-project/NetBeans/build.xml Tue Aug 20 10:35:42 2013
@@ -48,6 +48,13 @@
       </fileset>
     </copy>
 
+    <!-- FileTypeDetector implementations to be loaded by ServiceLoader. -->
+    <concat destfile="${build.classes.dir}/META-INF/services/java.nio.file.spi.FileTypeDetector" encoding="UTF-8" fixlastline="yes">
+      <fileset dir="${project.root}">
+        <include name="*/*/src/main/resources/META-INF/services/java.nio.file.spi.FileTypeDetector"/>
+      </fileset>
+    </concat>
+
     <!-- ObjectConverter implementations to be loaded by ServiceLoader. -->
     <concat destfile="${build.classes.dir}/META-INF/services/org.apache.sis.util.ObjectConverter" encoding="UTF-8" fixlastline="yes">
       <fileset dir="${project.root}">

Modified: sis/branches/JDK6/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java [UTF-8] (original)
+++ sis/branches/JDK6/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -76,6 +76,11 @@ public final class ChannelDecoder extend
     public static final int MAGIC_NUMBER = ('C' << 24) | ('D' << 16) | ('F' <<  8);
 
     /**
+     * The maximal version number supported by this implementation.
+     */
+    public static final int MAX_VERSION = 2;
+
+    /**
      * The encoding of dimension, variable and attribute names. This is fixed to {@value} by the
      * NetCDF specification. Note however that the encoding of attribute values may be different.
      *
@@ -211,6 +216,7 @@ public final class ChannelDecoder extend
             case 1:  is64bits = false; break;
             case 2:  is64bits = true;  break;
             default: throw new DataStoreException(errors().getString(Errors.Keys.UnsupportedVersion_1, version));
+            // If more cases are added, remember to increment the MAX_VERSION constant.
         }
         numrecs = input.readInt();
         /*

Modified: sis/branches/JDK6/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java [UTF-8] (original)
+++ sis/branches/JDK6/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -35,6 +35,7 @@ import org.apache.sis.storage.DataStoreE
 import org.apache.sis.storage.ProbeResult;
 import org.apache.sis.util.logging.WarningListeners;
 import org.apache.sis.util.ThreadSafe;
+import org.apache.sis.util.Version;
 
 
 /**
@@ -54,6 +55,11 @@ import org.apache.sis.util.ThreadSafe;
 @ThreadSafe
 public class NetcdfStoreProvider extends DataStoreProvider {
     /**
+     * The MIME type for NetCDF files.
+     */
+    static final String MIME_TYPE = "application/x-netcdf";
+
+    /**
      * The name of the {@link ucar.nc2.NetcdfFile} class, which is {@value}.
      */
     private static final String UCAR_CLASSNAME = "ucar.nc2.NetcdfFile";
@@ -112,7 +118,10 @@ public class NetcdfStoreProvider extends
      * @throws DataStoreException if an I/O error occurred.
      */
     @Override
-    public ProbeResult canOpen(StorageConnector storage) throws DataStoreException {
+    public ProbeResult probeContent(StorageConnector storage) throws DataStoreException {
+        int     version     = 0;
+        boolean hasVersion  = false;
+        boolean isSupported = false;
         final ByteBuffer buffer = storage.getStorageAs(ByteBuffer.class);
         if (buffer != null) {
             if (buffer.remaining() < Integer.SIZE / Byte.SIZE) {
@@ -120,39 +129,56 @@ public class NetcdfStoreProvider extends
             }
             final int header = buffer.getInt(buffer.position());
             if ((header & 0xFFFFFF00) == ChannelDecoder.MAGIC_NUMBER) {
-                return ProbeResult.SUPPORTED;
+                hasVersion  = true;
+                version     = header & 0xFF;
+                isSupported = (version >= 1 && version <= ChannelDecoder.MAX_VERSION);
             }
         }
         /*
          * If we failed to check using the embedded decoder, tries using the UCAR library.
+         * The UCAR library is an optional dependency. If that library is present and the
+         * input is a String, then the following code may trigs a large amount of classes
+         * loading.
          */
-        final String path = storage.getStorageAs(String.class);
-        if (path != null) {
-            ensureInitialized();
-            final Method method = canOpenFromPath;
-            if (method != null) try {
-                return ((Boolean) method.invoke(null, path)) ? ProbeResult.SUPPORTED : ProbeResult.UNSUPPORTED_STORAGE;
-            } catch (IllegalAccessException e) {
-                throw new AssertionError(e); // Should never happen, since the method is public.
-            } catch (InvocationTargetException e) {
-                final Throwable cause = e.getCause();
-                if (cause instanceof DataStoreException) throw (DataStoreException) cause;
-                if (cause instanceof RuntimeException)   throw (RuntimeException)   cause;
-                if (cause instanceof Error)              throw (Error)              cause;
-                throw new DataStoreException(e); // The cause may be IOException.
+        if (!isSupported) {
+            final String path = storage.getStorageAs(String.class);
+            if (path != null) {
+                ensureInitialized();
+                final Method method = canOpenFromPath;
+                if (method != null) try {
+                    isSupported = (Boolean) method.invoke(null, path);
+                } catch (IllegalAccessException e) {
+                    // Should never happen, since the method is public.
+                    throw (Error) new IncompatibleClassChangeError("canOpen").initCause(e);
+                } catch (InvocationTargetException e) {
+                    final Throwable cause = e.getCause();
+                    if (cause instanceof DataStoreException) throw (DataStoreException) cause;
+                    if (cause instanceof RuntimeException)   throw (RuntimeException)   cause;
+                    if (cause instanceof Error)              throw (Error)              cause;
+                    throw new DataStoreException(e); // The cause may be IOException.
+                }
+            } else {
+                /*
+                 * Check if the given input is itself an instance of the UCAR oject.
+                 * We check classnames instead of netcdfFileClass.isInstance(storage)
+                 * in order to avoid loading the UCAR library if not needed.
+                 */
+                for (Class<?> type = storage.getStorage().getClass(); type != null; type = type.getSuperclass()) {
+                    if (UCAR_CLASSNAME.equals(type.getName())) {
+                        isSupported = true;
+                        break;
+                    }
+                }
             }
         }
         /*
-         * Check if the given input is itself an instance of the UCAR oject.
-         * We check classnames instead of netcdfFileClass.isInstance(storage)
-         * in order to avoid loading the UCAR library if not needed.
+         * At this point, the readability status has been determined. The file version number
+         * is unknown if we are able to open the file only through the UCAR library.
          */
-        for (Class<?> type = storage.getStorage().getClass(); type != null; type = type.getSuperclass()) {
-            if (UCAR_CLASSNAME.equals(type.getName())) {
-                return ProbeResult.SUPPORTED;
-            }
+        if (hasVersion) {
+            return new ProbeResult(isSupported, MIME_TYPE, Version.valueOf(version));
         }
-        return ProbeResult.UNSUPPORTED_STORAGE;
+        return isSupported ? new ProbeResult(true, MIME_TYPE, null) : ProbeResult.UNSUPPORTED_STORAGE;
     }
 
     /**

Modified: sis/branches/JDK6/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java [UTF-8] (original)
+++ sis/branches/JDK6/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -27,6 +27,7 @@ import org.apache.sis.internal.netcdf.im
 import org.apache.sis.storage.ProbeResult;
 import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.util.Version;
 import org.apache.sis.test.DependsOn;
 import org.junit.Test;
 
@@ -38,7 +39,7 @@ import static org.opengis.test.Assert.*;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.3
+ * @version 0.4
  * @module
  */
 @DependsOn({
@@ -46,31 +47,37 @@ import static org.opengis.test.Assert.*;
 })
 public final strictfp class NetcdfStoreProviderTest extends IOTestCase {
     /**
-     * Tests {@link NetcdfStoreProvider#canOpen(StorageConnector)} for an input stream which shall
+     * Tests {@link NetcdfStoreProvider#probeContent(StorageConnector)} for an input stream which shall
      * be recognized as a classic NetCDF file.
      *
      * @throws DataStoreException Should never happen.
      */
     @Test
-    public void testCanOpenFromStream() throws DataStoreException {
+    public void testProbeContentFromStream() throws DataStoreException {
         final StorageConnector c = new StorageConnector(IOTestCase.class.getResourceAsStream(NCEP));
         final NetcdfStoreProvider provider = new NetcdfStoreProvider();
-        assertEquals(ProbeResult.SUPPORTED, provider.canOpen(c));
+        final ProbeResult probe = provider.probeContent(c);
+        assertTrue  ("isSupported", probe.isSupported());
+        assertEquals("getMimeType", NetcdfStoreProvider.MIME_TYPE, probe.getMimeType());
+        assertEquals("getVersion",  new Version("1"), probe.getVersion());
         c.closeAllExcept(null);
     }
 
     /**
-     * Tests {@link NetcdfStoreProvider#canOpen(StorageConnector)} for a UCAR {@link NetcdfFile} object.
+     * Tests {@link NetcdfStoreProvider#probeContent(StorageConnector)} for a UCAR {@link NetcdfFile} object.
      *
      * @throws IOException If an error occurred while opening the NetCDF file.
      * @throws DataStoreException Should never happen.
      */
     @Test
-    public void testCanOpenFromUCAR() throws IOException, DataStoreException {
+    public void testProbeContentFromUCAR() throws IOException, DataStoreException {
         final NetcdfFile file = open(NCEP);
         final StorageConnector c = new StorageConnector(file);
         final NetcdfStoreProvider provider = new NetcdfStoreProvider();
-        assertEquals(ProbeResult.SUPPORTED, provider.canOpen(c));
+        final ProbeResult probe = provider.probeContent(c);
+        assertTrue  ("isSupported", probe.isSupported());
+        assertEquals("getMimeType", NetcdfStoreProvider.MIME_TYPE, probe.getMimeType());
+        assertNull  ("getVersion",  probe.getVersion());
         file.close();
     }
 

Modified: sis/branches/JDK6/storage/sis-storage/pom.xml
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/storage/sis-storage/pom.xml?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/storage/sis-storage/pom.xml (original)
+++ sis/branches/JDK6/storage/sis-storage/pom.xml Tue Aug 20 10:35:42 2013
@@ -105,4 +105,19 @@ Provides the interfaces and base classes
     </plugins>
   </build>
 
+
+  <!-- ===========================================================
+           Dependencies
+       =========================================================== -->
+  <dependencies>
+    <!-- Test dependencies -->
+    <dependency>
+      <groupId>org.apache.sis.core</groupId>
+      <artifactId>sis-metadata</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
 </project>

Modified: sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/IOUtilities.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/IOUtilities.java?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/IOUtilities.java [UTF-8] (original)
+++ sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/IOUtilities.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -434,7 +434,11 @@ public final class IOUtilities extends S
              * URL uses HTTP or FTP protocols, because JDK7 does not provide file systems for them by default.
              */
             final URI uri = (URI) input;
-            try {
+            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(Errors.format(Errors.Keys.MissingSchemeInURI));
+            } else try {
                 input = new File(uri);
             } catch (IllegalArgumentException e) {
                 input = uri.toURL();

Copied: sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/MimeTypeDetector.java (from r1515760, sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/MimeTypeDetector.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/MimeTypeDetector.java?p2=sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/MimeTypeDetector.java&p1=sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/MimeTypeDetector.java&r1=1515760&r2=1515763&rev=1515763&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/MimeTypeDetector.java [UTF-8] (original)
+++ sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/MimeTypeDetector.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -46,7 +46,7 @@ abstract class MimeTypeDetector {
      * The mapping from XML namespace to MIME type.
      * This map shall be read-only, since we do not synchronize it.
      */
-    private static final Map<String,String> TYPES = new HashMap<>();
+    private static final Map<String,String> TYPES = new HashMap<String,String>();
     static {
         TYPES.put(Namespaces.GML, "application/gml+xml");
         TYPES.put(Namespaces.GMD, "application/vnd.iso.19139+xml");

Modified: sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/XMLStoreProvider.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/XMLStoreProvider.java?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/XMLStoreProvider.java [UTF-8] (original)
+++ sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/XMLStoreProvider.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -36,6 +36,17 @@ import org.apache.sis.storage.ProbeResul
  */
 public class XMLStoreProvider extends DataStoreProvider {
     /**
+     * The {@value} MIME type, used only of {@link #probeContent(StorageConnector)} can not determine
+     * a more accurate type.
+     */
+    public static final String MIME_TYPE = "application/xml";
+
+    /**
+     * The read-ahead limit when reading the XML document from a {@link Reader}.
+     */
+    private static final int READ_AHEAD_LIMIT = 2048;
+
+    /**
      * The expected XML header. According XML specification, this declaration is required to appear
      * at the document beginning (no space allowed before the declaration).
      */
@@ -54,7 +65,7 @@ public class XMLStoreProvider extends Da
      * header.
      */
     @Override
-    public ProbeResult canOpen(final StorageConnector storage) throws DataStoreException {
+    public ProbeResult probeContent(final StorageConnector storage) throws DataStoreException {
         /*
          * Usual case. This include InputStream, DataInput, File, Path, URL, URI.
          */
@@ -63,12 +74,25 @@ public class XMLStoreProvider extends Da
             if (buffer.remaining() < HEADER.length) {
                 return ProbeResult.INSUFFICIENT_BYTES;
             }
+            // Quick check for "<?xml " header.
             for (int i=0; i<HEADER.length; i++) {
                 if (buffer.get(i) != HEADER[i]) {
                     return ProbeResult.UNSUPPORTED_STORAGE;
                 }
             }
-            return ProbeResult.SUPPORTED;
+            // Now check for a more accurate MIME type.
+            buffer.position(HEADER.length);
+            final ProbeResult result = new MimeTypeDetector() {
+                @Override int read() {
+                    if (buffer.hasRemaining()) {
+                        return buffer.get();
+                    }
+                    insufficientBytes = (buffer.limit() != buffer.capacity());
+                    return -1;
+                }
+            }.probeContent();
+            buffer.position(0);
+            return result;
         }
         /*
          * We should enter in this block only if the user gave us explicitely a Reader.
@@ -76,15 +100,23 @@ public class XMLStoreProvider extends Da
          */
         final Reader reader = storage.getStorageAs(Reader.class);
         if (reader != null) try {
-            reader.mark(HEADER.length);
+            // Quick check for "<?xml " header.
+            reader.mark(HEADER.length + READ_AHEAD_LIMIT);
             for (int i=0; i<HEADER.length; i++) {
                 if (reader.read() != HEADER[i]) {
                     reader.reset();
                     return ProbeResult.UNSUPPORTED_STORAGE;
                 }
             }
+            // Now check for a more accurate MIME type.
+            final ProbeResult result = new MimeTypeDetector() {
+                private int remaining = READ_AHEAD_LIMIT;
+                @Override int read() throws IOException {
+                    return (--remaining >= 0) ? reader.read() : -1;
+                }
+            }.probeContent();
             reader.reset();
-            return ProbeResult.SUPPORTED;
+            return result;
         } catch (IOException e) {
             throw new DataStoreException(e);
         }

Modified: sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreProvider.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreProvider.java?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreProvider.java [UTF-8] (original)
+++ sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreProvider.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -16,7 +16,6 @@
  */
 package org.apache.sis.storage;
 
-import java.util.Set;
 import org.apache.sis.util.ThreadSafe;
 
 
@@ -71,7 +70,7 @@ public abstract class DataStoreProvider 
      *       supported by this {@code DataStoreProvider}.</li>
      * </ul>
      *
-     * Note that the {@code SUPPORTED_FORMAT} value does not guarantee that reading or writing will succeed,
+     * Note that the {@code SUPPORTED} 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.
      *
@@ -85,7 +84,7 @@ public abstract class DataStoreProvider 
      * with the format, as in the following example:
      *
      * {@preformat java
-     *     public ProbeResult canOpen(StorageConnector storage) throws DataStoreException {
+     *     public ProbeResult probeContent(StorageConnector storage) throws DataStoreException {
      *         final ByteBuffer buffer = storage.getStorageAs(ByteBuffer.class);
      *         if (buffer == null) {
      *             // If StorageConnector can not provide a ByteBuffer, then the storage is
@@ -113,7 +112,7 @@ public abstract class DataStoreProvider 
      * @throws DataStoreException if an I/O or SQL error occurred. The error shall be unrelated to the logical
      *         structure of the storage.
      */
-    public abstract ProbeResult canOpen(StorageConnector storage) throws DataStoreException;
+    public abstract ProbeResult probeContent(StorageConnector storage) throws DataStoreException;
 
     /**
      * Returns a data store implementation associated with this provider.
@@ -130,4 +129,25 @@ public abstract class DataStoreProvider 
      * @see DataStores#open(Object)
      */
     public abstract DataStore open(StorageConnector storage) throws DataStoreException;
+
+    /**
+     * Returns {@code TRUE} if the given storage appears to be supported by the {@code DataStore}.
+     *
+     * @param  storage Information about the storage (URL, stream, JDBC connection, <i>etc</i>).
+     * @return {@link Boolean#TRUE} if the given storage seems to be usable by the {@code DataStore} instances
+     *         create by this provider, {@link Boolean#FALSE} if the {@code DataStore} will not be able to use
+     *         the given storage, or {@code null} if this method does not have enough information.
+     * @throws DataStoreException if an I/O or SQL error occurred. The error shall be unrelated to the logical
+     *         structure of the storage.
+     *
+     * @deprecated Replaced by {@link #probeContent(StorageConnector)}.
+     */
+    @Deprecated
+    public Boolean canOpen(final StorageConnector storage) throws DataStoreException {
+        final ProbeResult probe = probeContent(storage);
+        if (ProbeResult.INSUFFICIENT_BYTES.equals(probe) || ProbeResult.UNDETERMINED.equals(probe)) {
+            return null;
+        }
+        return probe.isSupported();
+    }
 }

Modified: sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreRegistry.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreRegistry.java?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreRegistry.java [UTF-8] (original)
+++ sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreRegistry.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -51,7 +51,7 @@ final class DataStoreRegistry {
      * Creates a new registry which will use the current thread
      * {@linkplain Thread#getContextClassLoader() context class loader}.
      */
-    public DataStoreRegistry() {
+    DataStoreRegistry() {
         loader = ServiceLoader.load(DataStoreProvider.class);
     }
 
@@ -60,12 +60,25 @@ final class DataStoreRegistry {
      *
      * @param loader The class loader to use for loading {@link DataStoreProvider} implementations.
      */
-    public DataStoreRegistry(final ClassLoader loader) {
+    DataStoreRegistry(final ClassLoader loader) {
         ArgumentChecks.ensureNonNull("loader", loader);
         this.loader = ServiceLoader.load(DataStoreProvider.class, loader);
     }
 
     /**
+     * Returns the MIME type of the storage file format, or {@code null} if unknown or not applicable.
+     *
+     * @param  storage The input/output object as a URL, file, image input stream, <i>etc.</i>.
+     * @return The storage MIME type, or {@code null} if unknown or not applicable.
+     * @throws DataStoreException If an error occurred while opening the storage.
+     */
+    public String probeContentType(final Object storage) throws DataStoreException {
+        ArgumentChecks.ensureNonNull("storage", storage);
+        final ProbeProviderPair p = lookup(storage, false);
+        return (p != null) ? p.probe.getMimeType() : null;
+    }
+
+    /**
      * Creates a {@link DataStore} for reading the given storage.
      * The {@code storage} argument can be any of the following types:
      *
@@ -84,51 +97,62 @@ final class DataStoreRegistry {
      * @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) throws DataStoreException {
+    public DataStore open(final Object storage) throws UnsupportedStorageException, DataStoreException {
         ArgumentChecks.ensureNonNull("storage", storage);
+        return lookup(storage, true).store;
+    }
+
+    /**
+     * Implementation of {@link #probeContentType(Object)} and {@link #open(Object)}.
+     *
+     * @param  storage The input/output object as a URL, file, image input stream, <i>etc.</i>.
+     * @param  open {@code true} for creating a {@link DataStore}, or {@code false} if not needed.
+     * @throws UnsupportedStorageException if no {@link DataStoreProvider} is found for a given storage object.
+     * @throws DataStoreException If an error occurred while opening the storage.
+     */
+    private ProbeProviderPair lookup(final Object storage, final boolean open) throws DataStoreException {
         StorageConnector connector;
         if (storage instanceof StorageConnector) {
             connector = (StorageConnector) storage;
         } else {
             connector = new StorageConnector(storage);
         }
-        DataStoreProvider provider = null;
-        List<DataStoreProvider> deferred = null;
+        ProbeProviderPair selected = null;
+        List<ProbeProviderPair> deferred = null;
         try {
             /*
              * All usages of 'loader' and its 'providers' iterator must be protected in a synchronized block,
              * because ServiceLoader is not thread-safe. We try to keep the synhronization block as small as
-             * possible for less contention. In particular, the canOpen(connector) method call may be costly.
+             * possible for less contention. In particular, the probeContent(connector) method call may be costly.
              */
             final Iterator<DataStoreProvider> providers;
-            DataStoreProvider candidate;
+            DataStoreProvider provider;
             synchronized (loader) {
                 providers = loader.iterator();
-                candidate = providers.hasNext() ? providers.next() : null;
+                provider = providers.hasNext() ? providers.next() : null;
             }
-search:     while (candidate != null) {
-                switch (candidate.canOpen(connector)) {
+            while (provider != null) {
+                final ProbeResult probe = provider.probeContent(connector);
+                if (probe.isSupported()) {
                     /*
                      * Stop at the first provider claiming to be able to read the storage.
                      * Do not iterate over the list of deferred providers (if any).
                      */
-                    case SUPPORTED: {
-                        provider = candidate;
-                        deferred = null;
-                        break search;
-                    }
+                    selected = new ProbeProviderPair(provider, probe);
+                    deferred = null;
+                    break;
+                }
+                if (ProbeResult.INSUFFICIENT_BYTES.equals(probe)) {
                     /*
                      * If a provider doesn't have enough bytes for answering the question,
                      * try again after this loop with more bytes in the buffer, unless we
                      * found an other provider.
                      */
-                    case INSUFFICIENT_BYTES: {
-                        if (deferred == null) {
-                            deferred = new LinkedList<DataStoreProvider>();
-                        }
-                        deferred.add(candidate);
-                        break;
+                    if (deferred == null) {
+                        deferred = new LinkedList<ProbeProviderPair>();
                     }
+                    deferred.add(new ProbeProviderPair(provider, probe));
+                } else if (ProbeResult.UNDETERMINED.equals(probe)) {
                     /*
                      * If a provider doesn't know whether it can open the given storage,
                      * we will try it only if we find no provider retuning SUPPORTED.
@@ -137,30 +161,32 @@ search:     while (candidate != null) {
                      *       provider.open(connector) in a try … catch block because it may leave
                      *       the StorageConnector in an invalid state in case of failure.
                      */
-                    case UNDETERMINED: {
-                        provider = candidate;
-                        break;
-                    }
+                    selected = new ProbeProviderPair(provider, probe);
                 }
                 synchronized (loader) {
-                    candidate = providers.hasNext() ? providers.next() : null;
+                    provider = providers.hasNext() ? providers.next() : null;
                 }
             }
             /*
-             * If any provider did not had enough bytes for answering the 'canOpen(…)' question,
+             * If any provider did not had enough bytes for answering the 'probeContent(…)' question,
              * get more bytes and try again. We try to prefetch more bytes only if we have no choice
              * in order to avoid latency on network connection.
              */
             if (deferred != null) {
 search:         while (!deferred.isEmpty() && connector.prefetch()) {
-                    for (final Iterator<DataStoreProvider> it=deferred.iterator(); it.hasNext();) {
-                        candidate = it.next();
-                        switch (candidate.canOpen(connector)) {
-                            case SUPPORTED:          provider = candidate; break search;
-                            case UNDETERMINED:       provider = candidate; break;
-                            case INSUFFICIENT_BYTES: continue; // Will try again in next iteration.
+                    for (final Iterator<ProbeProviderPair> it=deferred.iterator(); it.hasNext();) {
+                        final ProbeProviderPair p = it.next();
+                        p.probe = provider.probeContent(connector);
+                        if (p.probe.isSupported()) {
+                            selected = p;
+                            break search;
+                        }
+                        if (!ProbeResult.INSUFFICIENT_BYTES.equals(p.probe)) {
+                            if (ProbeResult.UNDETERMINED.equals(p.probe)) {
+                                selected = p; // To be used only if we don't find a better match.
+                            }
+                            it.remove(); // UNSUPPORTED_* or UNDETERMINED: do not try again those providers.
                         }
-                        it.remove(); // UNSUPPORTED_* or UNDETERMINED: do not try again those providers.
                     }
                 }
             }
@@ -171,16 +197,18 @@ search:         while (!deferred.isEmpty
              * shall avoid the UNDETERMINED value as much as possible (this value should be used
              * only for RAW image format).
              */
-            if (provider != null) {
-                final DataStore data = provider.open(connector);
+            if (open && selected != null) {
+                selected.store = selected.provider.open(connector);
                 connector = null; // For preventing it to be closed.
-                return data;
             }
         } finally {
             if (connector != null && connector != storage) {
                 connector.closeAllExcept(null);
             }
         }
-        throw new UnsupportedStorageException(Errors.format(Errors.Keys.UnknownFormatFor_1, connector.getStorageName()));
+        if (open && selected == null) {
+            throw new UnsupportedStorageException(Errors.format(Errors.Keys.UnknownFormatFor_1, connector.getStorageName()));
+        }
+        return selected;
     }
 }

Modified: sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStores.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStores.java?rev=1515763&r1=1515762&r2=1515763&view=diff
==============================================================================
--- sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStores.java [UTF-8] (original)
+++ sis/branches/JDK6/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStores.java [UTF-8] Tue Aug 20 10:35:42 2013
@@ -62,6 +62,33 @@ public final class DataStores extends St
     }
 
     /**
+     * Returns the registry, created when first needed.
+     */
+    private static DataStoreRegistry registry() {
+        DataStoreRegistry r = registry;
+        if (r == null) {
+            synchronized (DataStores.class) {
+                r = registry;
+                if (r == null) {
+                    registry = r = new DataStoreRegistry();
+                }
+            }
+        }
+        return r;
+    }
+
+    /**
+     * Returns the MIME type of the storage file format, or {@code null} if unknown or not applicable.
+     *
+     * @param  storage The input/output object as a URL, file, image input stream, <i>etc.</i>.
+     * @return The storage MIME type, or {@code null} if unknown or not applicable.
+     * @throws DataStoreException If an error occurred while opening the storage.
+     */
+    public static String probeContentType(final Object storage) throws DataStoreException {
+        return registry().probeContentType(storage);
+    }
+
+    /**
      * Creates a {@link DataStore} for the given storage.
      * The {@code storage} argument can be any of the following types:
      *
@@ -80,16 +107,7 @@ public final class DataStores extends St
      * @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 {
-        DataStoreRegistry r = registry;
-        if (r == null) {
-            synchronized (DataStores.class) {
-                r = registry;
-                if (r == null) {
-                    registry = r = new DataStoreRegistry();
-                }
-            }
-        }
-        return r.open(storage);
+    public static DataStore open(final Object storage) throws UnsupportedStorageException, DataStoreException {
+        return registry().open(storage);
     }
 }



Mime
View raw message