sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1519087 [2/2] - in /sis/trunk: ./ application/sis-console/ application/sis-console/src/main/java/org/apache/sis/console/ application/sis-console/src/test/java/org/apache/sis/console/ application/sis-console/src/test/java/org/apache/sis/tes...
Date Fri, 30 Aug 2013 21:00:41 GMT
Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/CollectionsExt.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/CollectionsExt.java?rev=1519087&r1=1519086&r2=1519087&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/CollectionsExt.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/CollectionsExt.java [UTF-8] Fri Aug 30 21:00:40 2013
@@ -50,7 +50,7 @@ import org.apache.sis.internal.jdk8.Func
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.3 (derived from geotk-3.00)
- * @version 0.3
+ * @version 0.4
  * @module
  */
 public final class CollectionsExt extends Static {
@@ -92,25 +92,79 @@ public final class CollectionsExt extend
     }
 
     /**
+     * Returns the given collection if non-empty, or {@code null} if the given collection is null or empty.
+     * This method is generally not recommended, since public API should prefer empty collection instead of
+     * null. However it is occasionally useful for managing private fields, especially for inter-operability
+     * with frameworks that may expect or return null (e.g. if we want to exclude completely an empty collection
+     * from marshalling with JAXB).
+     *
+     * @param  <T> The type of the collection.
+     * @param  <E> The type of elements in the collection.
+     * @param  c   The collection, or {@code null}.
+     * @return The given collection, or an empty set of the given collection was null.
+     */
+    public static <T extends Collection<E>, E> T nonEmpty(final T c) {
+        return (c != null && c.isEmpty()) ? null : c;
+    }
+
+    /**
+     * Returns the given collection, or {@link Collections#EMPTY_SET} if the given collection is null.
+     *
+     * @param  <E> The type of elements in the collection.
+     * @param  c The collection, or {@code null}.
+     * @return The given collection, or an empty set of the given collection was null.
+     */
+    public static <E> Collection<E> nonNull(final Collection<E> c) {
+        return (c != null) ? c : Collections.<E>emptySet();
+    }
+
+    /**
+     * Returns the given set, or {@link Collections#EMPTY_SET} if the given set is null.
+     *
+     * @param  <E> The type of elements in the collection.
+     * @param  c The collection, or {@code null}.
+     * @return The given collection, or an empty set of the given collection was null.
+     */
+    public static <E> Set<E> nonNull(final Set<E> c) {
+        return (c != null) ? c : Collections.<E>emptySet();
+    }
+
+    /**
      * Returns the specified array as an immutable set, or {@code null} if the array is null.
      * If the given array contains duplicated elements, i.e. elements that are equal in the
      * sense of {@link Object#equals(Object)}, then only the last instance of the duplicated
      * values will be included in the returned set.
      *
-     * @param  <E> The type of array elements.
-     * @param  array The array to copy in a set. May be {@code null}.
+     * @param  <E>         The type of array elements.
+     * @param  excludeNull {@code true} for excluding the {@code null} element from the returned set.
+     * @param  array       The array to copy in a set. May be {@code null} or contain null elements.
      * @return A set containing the array elements, or {@code null} if the given array was null.
      *
      * @see Collections#unmodifiableSet(Set)
      */
-    public static <E> Set<E> immutableSet(final E... array) {
+    @SuppressWarnings("fallthrough")
+    public static <E> Set<E> immutableSet(final boolean excludeNull, final E... array) {
         if (array == null) {
             return null;
         }
         switch (array.length) {
-            case 0:  return Collections.emptySet();
-            case 1:  return Collections.singleton(array[0]);
-            default: return Collections.unmodifiableSet(new LinkedHashSet<E>(Arrays.asList(array)));
+            case 1: {
+                final E element = array[0];
+                if (element != null || !excludeNull) {
+                    return Collections.singleton(element);
+                }
+                // Fallthrough for an empty set.
+            }
+            case 0: {
+                return Collections.emptySet();
+            }
+            default: {
+                final Set<E> set = new LinkedHashSet<E>(Arrays.asList(array));
+                if (excludeNull) {
+                    set.remove(null);
+                }
+                return unmodifiableOrCopy(set);
+            }
         }
     }
 

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/math/FunctionProperty.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/math/FunctionProperty.java?rev=1519087&r1=1519086&r2=1519087&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/math/FunctionProperty.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/math/FunctionProperty.java [UTF-8] Fri Aug 30 21:00:40 2013
@@ -140,7 +140,7 @@ public enum FunctionProperty {
     ORDER_REVERSING;
 
     /**
-     * Bijective functions shall contains all the value in this set.
+     * Bijective functions shall contain all the value in this set.
      *
      * @see #isBijective(Set)
      */

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/ArgumentChecks.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/ArgumentChecks.java?rev=1519087&r1=1519086&r2=1519087&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/ArgumentChecks.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/ArgumentChecks.java [UTF-8] Fri Aug 30 21:00:40 2013
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.util;
 
+import java.util.Map; // For javadoc
 import org.opengis.referencing.cs.CoordinateSystem;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.geometry.Envelope;
@@ -155,8 +156,9 @@ public final class ArgumentChecks extend
      *         Can be {@code null} if the name is unknown.
      * @param  expectedType the expected type (class or interface).
      * @param  value The value to check, or {@code null}.
-     * @throws IllegalArgumentException if {@code value} is non-null and is not assignable
-     *         to the given type.
+     * @throws IllegalArgumentException if {@code value} is non-null and is not assignable to the given type.
+     *
+     * @see org.apache.sis.util.collection.Containers#property(Map, Object, Class)
      */
     public static void ensureCanCast(final String name, final Class<?> expectedType, final Object value)
             throws IllegalArgumentException

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java?rev=1519087&r1=1519086&r2=1519087&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java [UTF-8] Fri Aug 30 21:00:40 2013
@@ -1518,7 +1518,7 @@ cmp:    while (ia < lga) {
      * Unicode identifier start} and all remaining characters (if any) are
      * {@linkplain Character#isUnicodeIdentifierPart(int) Unicode identifier parts}.
      *
-     * @param identifier The character sequence to test.
+     * @param  identifier The character sequence to test.
      * @return {@code true} if the given character sequence is a legal Unicode identifier.
      * @throws NullPointerException if the argument is null.
      */

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/Locales.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/Locales.java?rev=1519087&r1=1519086&r2=1519087&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/Locales.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/Locales.java [UTF-8] Fri Aug 30 21:00:40 2013
@@ -208,20 +208,33 @@ public final class Locales extends Stati
      * anyway.</p>
      *
      * @param  code The language code, which may be followed by country code.
-     * @return The language for the given code.
+     * @return The language for the given code (never {@code null}).
      * @throws IllegalArgumentException If the given code doesn't seem to be a valid locale.
      *
      * @see Locale#forLanguageTag(String)
      */
     public static Locale parse(final String code) throws IllegalArgumentException {
+        ArgumentChecks.ensureNonNull("code", code);
+        return parse(code, 0);
+    }
+
+    /**
+     * Implementation of {@link #parse(String)} which start the parsing process from the given {@code fromIndex}.
+     *
+     * @param  code The language code, which may be followed by country code.
+     * @param  fromIndex Index of the first character to parse.
+     * @return The language for the given code (never {@code null}).
+     * @throws IllegalArgumentException If the given code doesn't seem to be a valid locale.
+     */
+    private static Locale parse(final String code, final int fromIndex) throws IllegalArgumentException {
         final String language, country, variant;
-        int ci = code.indexOf('_');
+        int ci = code.indexOf('_', fromIndex);
         if (ci < 0) {
-            language = trimWhitespaces(code);
+            language = (String) trimWhitespaces(code, fromIndex, code.length());
             country  = "";
             variant  = "";
         } else {
-            language = (String) trimWhitespaces(code, 0, ci);
+            language = (String) trimWhitespaces(code, fromIndex, ci);
             int vi = code.indexOf('_', ++ci);
             if (vi < 0) {
                 country = (String) trimWhitespaces(code, ci, code.length());
@@ -230,7 +243,8 @@ public final class Locales extends Stati
                 country = (String) trimWhitespaces(code, ci, vi);
                 variant = (String) trimWhitespaces(code, ++vi, code.length());
                 if (code.indexOf('_', vi) >= 0) {
-                    throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalLanguageCode_1, code));
+                    throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalLanguageCode_1,
+                            code.substring(fromIndex)));
                 }
             }
         }
@@ -289,18 +303,23 @@ public final class Locales extends Stati
      * </ul>
      *
      * @param  prefix The prefix to skip at the beginning of the {@code key}.
-     * @param  key    The property key from which to extract the locale.
-     * @return {@code true} if the key has been recognized, or {@code false} otherwise.
+     * @param  key    The property key from which to extract the locale, or {@code null}.
+     * @return The locale encoded in the given key name, or {@code null} if the key has not been recognized.
      * @throws IllegalArgumentException if the locale after the prefix is an illegal code.
+     *
+     * @see org.apache.sis.util.iso.Types#toInternationalString(Map, String)
      */
     public static Locale parseSuffix(final String prefix, final String key) throws IllegalArgumentException {
-        if (key.startsWith(prefix)) {
-            final int offset = prefix.length();
-            if (key.length() == offset) {
-                return Locale.ROOT;
-            }
-            if (key.charAt(offset) == '_') {
-                return parse(key.substring(offset + 1));
+        ArgumentChecks.ensureNonNull("prefix", prefix);
+        if (key != null) { // Tolerance for Map that accept null keys.
+            if (key.startsWith(prefix)) {
+                final int offset = prefix.length();
+                if (key.length() == offset) {
+                    return Locale.ROOT;
+                }
+                if (key.charAt(offset) == '_') {
+                    return parse(key, offset + 1);
+                }
             }
         }
         return null;

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/collection/Containers.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/collection/Containers.java?rev=1519087&r1=1519086&r2=1519087&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/collection/Containers.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/collection/Containers.java [UTF-8] Fri Aug 30 21:00:40 2013
@@ -23,17 +23,18 @@ import java.util.Collection;
 import org.apache.sis.util.Static;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.ObjectConverter;
+import org.apache.sis.util.resources.Errors;
 import org.apache.sis.internal.util.UnmodifiableArrayList;
 
 
 /**
  * Static methods working on {@link Collection} or {@link CheckedContainer} objects.
- * Unless otherwise noted in the javadoc, every collections except {@link Map} returned
- * by the methods in this class implement the {@code CheckedContainer} interface.
+ * Unless otherwise noted in the javadoc, every collections returned by the methods
+ * in this class implement the {@code CheckedContainer} interface.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.3 (derived from geotk-3.00)
- * @version 0.3
+ * @version 0.4
  * @module
  */
 public final class Containers extends Static {
@@ -184,6 +185,10 @@ public final class Containers extends St
      * <p>The returned map can be serialized if the given map and converters are serializable.
      * The returned map is <strong>not</strong> thread-safe.</p>
      *
+     * <p>The returned map does not implement the {@link CheckedContainer} interface since {@code Map}
+     * is not {@code Collection} sub-type, but the derived map {@linkplain Map#keySet() key set} and
+     * {@linkplain Map#entrySet() entry set} do.</p>
+     *
      * @param <SK>         The type of keys   in the storage map.
      * @param <SV>         The type of values in the storage map.
      * @param <K>          The type of keys   in the derived map.
@@ -211,6 +216,41 @@ public final class Containers extends St
     }
 
     /**
+     * Returns the value mapped to the given key casted to the given type,
+     * or {@code null} if the map is null or does not contain a value for the key.
+     * If the mapped value is non-null but can not be casted to the given type, then this
+     * method throws an {@link IllegalArgumentException} with a message of the form
+     * "<cite>Property ‘{@code key}’ does not accept instances of ‘{@code value.class}’.</cite>".
+     *
+     * <p>This is a helper method for processing a {@code Map} argument containing property values of various
+     * kinds, as in the {@link org.apache.sis.referencing.AbstractIdentifiedObject#AbstractIdentifiedObject(Map)
+     * AbstractIdentifiedObject} constructor.</p>
+     *
+     * @param  <T>        The compile-time value of the {@code type} argument.
+     * @param  properties The map of properties from which to get a value, or {@code null} if none.
+     * @param  key        The key of the property value to return. Can be {@code null} if the map supports null key.
+     * @param  type       The expected type of the property value. Can not be null.
+     * @return The property value for the given key casted to the given type, or {@code null} if none.
+     * @throws IllegalArgumentException If a non-null property value exists for the given key but can
+     *         not be casted to the given type.
+     *
+     * @see ArgumentChecks#ensureCanCast(String, Class, Object)
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T property(final Map<?,?> properties, final Object key, final Class<T> type)
+            throws IllegalArgumentException
+    {
+        if (properties == null) {
+            return null;
+        }
+        final Object value = properties.get(key);
+        if (value != null && !type.isInstance(value)) {
+            throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalPropertyClass_2, key, value.getClass()));
+        }
+        return (T) value;
+    }
+
+    /**
      * Returns the capacity to be given to the {@link java.util.HashMap#HashMap(int) HashMap}
      * constructor for holding the given number of elements. This method computes the capacity
      * for the default <cite>load factor</cite>, which is 0.75.

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultInternationalString.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultInternationalString.java?rev=1519087&r1=1519086&r2=1519087&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultInternationalString.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultInternationalString.java [UTF-8] Fri Aug 30 21:00:40 2013
@@ -26,11 +26,15 @@ import java.util.LinkedHashMap;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.Locale;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
 import org.opengis.util.InternationalString;
 import org.apache.sis.util.Locales;
 import org.apache.sis.util.ThreadSafe;
 import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.logging.Logging;
 import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.resources.Messages;
 
 import static org.apache.sis.util.collection.Containers.isNullOrEmpty;
 
@@ -49,6 +53,8 @@ import org.apache.sis.internal.jdk7.Obje
  * @since   0.3 (derived from geotk-2.1)
  * @version 0.3
  * @module
+ *
+ * @see Types#toInternationalString(Map, String)
  */
 @ThreadSafe
 public class DefaultInternationalString extends AbstractInternationalString implements Serializable {
@@ -98,6 +104,8 @@ public class DefaultInternationalString 
      * will not be reflected into this international string.
      *
      * @param strings The strings in various locales, or {@code null} if none.
+     *
+     * @see Types#toInternationalString(Map, String)
      */
     public DefaultInternationalString(final Map<Locale,String> strings) {
         if (isNullOrEmpty(strings)) {
@@ -124,8 +132,7 @@ public class DefaultInternationalString 
      *
      * @param  locale The locale for the {@code string} value.
      * @param  string The localized string.
-     * @throws IllegalArgumentException if a different string value was already set for
-     *         the given locale.
+     * @throws IllegalArgumentException if a different string value was already set for the given locale.
      */
     public synchronized void add(final Locale locale, final String string) throws IllegalArgumentException {
         ArgumentChecks.ensureNonNull("locale", locale);
@@ -157,6 +164,32 @@ public class DefaultInternationalString 
     }
 
     /**
+     * Adds the given character sequence. If the given sequence is an other {@link InternationalString} instance,
+     * then only the string for the given locale is added. This method is for {@link Types} internal usage only.
+     *
+     * @param  locale The locale for the {@code string} value.
+     * @param  string The character sequence to add.
+     * @throws IllegalArgumentException if a different string value was already set for the given locale.
+     */
+    final void add(final Locale locale, final CharSequence string) throws IllegalArgumentException {
+        final boolean i18n = (string instanceof InternationalString);
+        add(locale, i18n ? ((InternationalString) string).toString(locale) : string.toString());
+        if (i18n && !(string instanceof SimpleInternationalString)) {
+            /*
+             * If the string may have more than one locale, log a warning telling that some locales
+             * may have been ignored. We declare Types.toInternationalString(…) as the source since
+             * it is the public facade invoking this method. We declare the source class using only
+             * its name rather than Types.class in order to avoid unnecessary real dependency.
+             */
+            final LogRecord record = Messages.getResources(null).getLogRecord(Level.WARNING, Messages.Keys.LocalesDiscarded);
+            record.setSourceClassName("org.apache.sis.util.iso.Types");
+            record.setSourceMethodName("toInternationalString");
+            record.setLoggerName("org.apache.sis.util.iso");
+            Logging.getLogger("org.apache.sis.util.iso").log(record);
+        }
+    }
+
+    /**
      * Returns the set of locales defined in this international string.
      *
      * @return The set of locales.

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java?rev=1519087&r1=1519086&r2=1519087&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java [UTF-8] Fri Aug 30 21:00:40 2013
@@ -221,10 +221,10 @@ public class DefaultNameFactory extends 
      * array is 1, or an instance of {@link DefaultScopedName} if the length of the array is 2
      * or more.
      *
-     * @param  scope The {@linkplain AbstractName#scope() scope} of the generic name to
-     *         be created, or {@code null} for a global namespace.
-     * @param  parsedNames The local names as an array of {@link String} or {@link InternationalString}
-     *         instances. This array shall contains at least one element.
+     * @param  scope The {@linkplain AbstractName#scope() scope} of the generic name to be created,
+     *         or {@code null} for a global namespace.
+     * @param  parsedNames The local names as an array of {@link String} or {@link InternationalString} instances.
+     *         This array shall contain at least one element.
      * @return The generic name for the given parsed names.
      * @throws NullArgumentException If the given array is empty.
      */

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java?rev=1519087&r1=1519086&r2=1519087&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java [UTF-8] Fri Aug 30 21:00:40 2013
@@ -18,6 +18,7 @@ package org.apache.sis.util.iso;
 
 import java.util.Map;
 import java.util.HashMap;
+import java.util.SortedMap;
 import java.util.Collection;
 import java.util.Locale;
 import java.util.Properties;
@@ -35,7 +36,9 @@ import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.Identifier;
 import org.apache.sis.util.Static;
+import org.apache.sis.util.Locales;
 import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.logging.Logging;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.collection.BackingStoreException;
@@ -59,7 +62,7 @@ import org.apache.sis.internal.system.De
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.3 (derived from geotk-3.19)
- * @version 0.3
+ * @version 0.4
  * @module
  */
 public final class Types extends Static {
@@ -552,6 +555,102 @@ public final class Types extends Static 
     }
 
     /**
+     * Returns an international strings for the values in the given properties map, or {@code null} if none.
+     * If the given map is {@code null}, then this method returns {@code null}.
+     * Otherwise this method iterates over the entries having a key that starts with the specified prefix.
+     * For each such key:
+     *
+     * <ul>
+     *   <li>The part after the prefix is parsed as specified by the {@link Locales#parseSuffix(String, String)}
+     *       method.</li>
+     *   <li>If {@code parseSuffix(…)} returned a non-null locale, then the value for that locale is added in the
+     *       international string to be returned.</li>
+     * </ul>
+     *
+     * For example the given map may contains a {@code "remarks"} property defined by values associated to the
+     * {@code "remarks_en"} and {@code "remarks_fr"} keys, for English and French locales respectively.
+     *
+     * @param  properties The map from which to get the string values for an international string, or {@code null}.
+     * @param  prefix     The prefix of keys to use for creating the international string.
+     * @return The international string, or {@code null} if the given map is null or does not contain values
+     *         associated to keys starting with the given prefix.
+     * @throws IllegalArgumentException If a key starts by the given prefix and:
+     *         <ul>
+     *           <li>The key suffix is an illegal {@link Locale} code,</li>
+     *           <li>or the value associated to that key is a not a {@link CharSequence}.</li>
+     *         </ul>
+     *
+     * @see Locales#parseSuffix(String, String)
+     * @see DefaultInternationalString#DefaultInternationalString(Map)
+     *
+     * @since 0.4
+     */
+    public static InternationalString toInternationalString(Map<String,?> properties, final String prefix)
+            throws IllegalArgumentException
+    {
+        ArgumentChecks.ensureNonEmpty("prefix", prefix);
+        if (properties == null) {
+            return null;
+        }
+        /*
+         * If the given map is an instance of SortedMap using the natural ordering of keys,
+         * we can skip all keys that lexicographically precedes the given prefix.
+         */
+        boolean isSorted = false;
+        if (properties instanceof SortedMap<?,?>) {
+            final SortedMap<String,?> sorted = (SortedMap<String,?>) properties;
+            if (sorted.comparator() == null) { // We want natural ordering.
+                properties = sorted.tailMap(prefix);
+                isSorted = true;
+            }
+        }
+        /*
+         * Now iterates over the map entry and lazily create the InternationalString
+         * only when first needed. In most cases, we have 0 or 1 matching entry.
+         */
+        CharSequence i18n = null;
+        Locale firstLocale = null;
+        DefaultInternationalString dis = null;
+        final int length = prefix.length();
+        for (final Map.Entry<String,?> entry : properties.entrySet()) {
+            final String key = entry.getKey();
+            final Locale locale = Locales.parseSuffix(prefix, key);
+            if (locale == null) {
+                if (isSorted) {
+                    /*
+                     * If the map is sorted using natural ordering, we can stop as soon as we find a key which
+                     * is lexicographically greater than prefix + '_'. We check 'startsWith' last since the other
+                     * tests are cheaper and usually sufficient.
+                     */
+                    if (key.length() <= length || key.charAt(length) > '_' || !key.startsWith(prefix)) {
+                        break;
+                    }
+                }
+            } else {
+                final Object value = entry.getValue();
+                if (value != null) {
+                    if (!(value instanceof CharSequence)) {
+                        throw new IllegalArgumentException(Errors.format(
+                                Errors.Keys.IllegalPropertyClass_2, key, value.getClass()));
+                    }
+                    if (i18n == null) {
+                        i18n = (CharSequence) value;
+                        firstLocale = locale;
+                    } else {
+                        if (dis == null) {
+                            dis = new DefaultInternationalString();
+                            dis.add(firstLocale, i18n);
+                            i18n = dis;
+                        }
+                        dis.add(locale, (CharSequence) value);
+                    }
+                }
+            }
+        }
+        return toInternationalString(i18n);
+    }
+
+    /**
      * Returns the given array of {@code CharSequence}s as an array of {@code InternationalString}s.
      * If the given array is null or an instance of {@code InternationalString[]}, then this method
      * returns it unchanged. Otherwise a new array of type {@code InternationalString[]} is created

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1519087&r1=1519086&r2=1519087&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] Fri Aug 30 21:00:40 2013
@@ -74,6 +74,11 @@ public final class Errors extends Indexe
         public static final int CanNotComputeDerivative = 44;
 
         /**
+         * Can not connect to “{0}”.
+         */
+        public static final int CanNotConnectTo_1 = 114;
+
+        /**
          * Can not convert from type ‘{0}’ to type ‘{1}’.
          */
         public static final int CanNotConvertFromType_2 = 72;
@@ -149,7 +154,7 @@ public final class Errors extends Indexe
         public static final int EmptyArgument_1 = 1;
 
         /**
-         * The dictionary shall contains at least one entry.
+         * The dictionary shall contain at least one entry.
          */
         public static final int EmptyDictionary = 54;
 
@@ -241,7 +246,7 @@ public final class Errors extends Indexe
         public static final int IllegalOrdinateRange_3 = 5;
 
         /**
-         * Property ‘{0}’ can be associated to an instance of ‘{1}’.
+         * Property ‘{0}’ does not accept instances of ‘{1}’.
          */
         public static final int IllegalPropertyClass_2 = 62;
 
@@ -541,6 +546,11 @@ public final class Errors extends Indexe
         public static final int UnknownCommand_1 = 102;
 
         /**
+         * Unknown enumeration value: {0}.
+         */
+        public static final int UnknownEnumValue_1 = 115;
+
+        /**
          * Format of “{0}” is not recognized.
          */
         public static final int UnknownFormatFor_1 = 107;

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1519087&r1=1519086&r2=1519087&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] Fri Aug 30 21:00:40 2013
@@ -25,6 +25,7 @@
 # can reorder the parameters as they want.
 #
 CanNotAddToExclusiveSet_2       = No element can be added to this set because properties \u2018{0}\u2019 and \u2018{1}\u2019 are mutually exclusive.
+CanNotConnectTo_1               = Can not connect to \u201c{0}\u201d.
 CanNotConvertFromType_2         = Can not convert from type \u2018{0}\u2019 to type \u2018{1}\u2019.
 CanNotConvertValue_2            = Can not convert value \u201c{0}\u201d to type \u2018{1}\u2019.
 CanNotComputeDerivative         = Can not compute the derivative.
@@ -41,7 +42,7 @@ DuplicatedOption_1              = Option
 DuplicatedIdentifier_1          = Identifier \u201c{0}\u201d is duplicated.
 ElementAlreadyPresent_1         = Element \u201c{0}\u201d is already present.
 EmptyArgument_1                 = Argument \u2018{0}\u2019 shall not be empty.
-EmptyDictionary                 = The dictionary shall contains at least one entry.
+EmptyDictionary                 = The dictionary shall contain at least one entry.
 EmptyEnvelope2D                 = Envelope must be at least two-dimensional and non-empty.
 EmptyProperty_1                 = Property named \u201c{0}\u201d shall not be empty.
 ExcessiveArgumentSize_3         = Argument \u2018{0}\u2019 shall not contain more than {1} elements. A number of {2} is excessive.
@@ -58,7 +59,7 @@ IllegalFormatPatternForClass_2  = The \u
 IllegalLanguageCode_1           = The \u201c{0}\u201d language is not recognized.
 IllegalMemberType_2             = Member \u201c{0}\u201d can not be associated to type \u201c{1}\u201d.
 IllegalOrdinateRange_3          = The [{0} \u2026 {1}] range of ordinate values is not valid for the \u201c{2}\u201d axis.
-IllegalPropertyClass_2          = Property \u2018{0}\u2019 can be associated to an instance of \u2018{1}\u2019.
+IllegalPropertyClass_2          = Property \u2018{0}\u2019 does not accept instances of \u2018{1}\u2019.
 IllegalRange_2                  = Range [{0} \u2026 {1}] is not valid.
 IllegalUnicodeCodePoint_2       = Value {1} for \u201c{0}\u201d is not a valid Unicode code point.
 IncompatiblePropertyValue_1     = Property \u201c{0}\u201d has an incompatible value.
@@ -120,6 +121,7 @@ UnexpectedEndOfFile_1           = Unexpe
 UnexpectedEndOfString_1         = More characters were expected at the end of \u201c{0}\u201d.
 UnexpectedFileFormat_2          = File \u201c{1}\u201d seems to be encoded in an other format than {0}.
 UnknownCommand_1                = Command \u201c{0}\u201d is not recognized.
+UnknownEnumValue_1              = Unknown enumeration value: {0}.
 UnknownFormatFor_1              = Format of \u201c{0}\u201d is not recognized.
 UnknownOption_1                 = Option \u201c{0}\u201d is not recognized.
 UnknownType_1                   = Type \u2018{0}\u2019 is unknown in this context.

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties?rev=1519087&r1=1519086&r2=1519087&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties [ISO-8859-1] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties [ISO-8859-1] Fri Aug 30 21:00:40 2013
@@ -15,6 +15,7 @@
 # limitations under the License.
 #
 CanNotAddToExclusiveSet_2       = Aucun \u00e9l\u00e9ment ne peut \u00eatre ajout\u00e9 \u00e0 cet ensemble car les propri\u00e9t\u00e9s \u2018{0}\u2019 et \u2018{1}\u2019 sont mutuellement exclusives.
+CanNotConnectTo_1               = Ne peut pas se connecter \u00e0 \u201c{0}\u201d.
 CanNotConvertFromType_2         = Ne peut pas convertir du type \u2018{0}\u2019 vers le type \u2018{1}\u2019.
 CanNotConvertValue_2            = La valeur \u201c{0}\u201d ne peut pas \u00eatre convertie vers le type \u2018{1}\u2019.
 CanNotComputeDerivative         = La d\u00e9riv\u00e9 ne peut pas \u00eatre calcul\u00e9e.
@@ -48,7 +49,7 @@ IllegalFormatPatternForClass_2  = Le mod
 IllegalLanguageCode_1           = Le code de langue \u201c{0}\u201d n\u2019est pas reconnu.
 IllegalMemberType_2             = Le membre \u201c{0}\u201d ne peut pas \u00eatre associ\u00e9 au type \u201c{1}\u201d.
 IllegalOrdinateRange_3          = La plage de valeurs de coordonn\u00e9es [{1} \u2026 {2}] n\u2019est pas valide pour l\u2019axe \u201c{0}\u201d.
-IllegalPropertyClass_2          = La propri\u00e9t\u00e9 \u2018{0}\u2019 ne peut pas \u00eatre associ\u00e9e \u00e0 une valeur de type \u2018{1}\u2019.
+IllegalPropertyClass_2          = La propri\u00e9t\u00e9 \u2018{0}\u2019 n\u2019accepte pas les valeurs de type \u2018{1}\u2019.
 IllegalRange_2                  = La plage [{0} \u2026 {1}] n\u2019est pas valide.
 IllegalUnicodeCodePoint_2       = La valeur {1} de \u201c{0}\u201d n\u2019est pas un code Unicode valide.
 IncompatiblePropertyValue_1     = La valeur de la propri\u00e9t\u00e9 \u201c{0}\u201d n\u2019est pas compatible.
@@ -109,6 +110,7 @@ UnexpectedEndOfFile_1           = Fin de
 UnexpectedEndOfString_1         = D\u2019autres caract\u00e8res \u00e9taient attendus \u00e0 la fin du texte \u201c{0}\u201d.
 UnexpectedFileFormat_2          = Le fichier \u201c{1}\u201d semble \u00eatre encod\u00e9 dans un autre format que {0}.
 UnknownCommand_1                = La commande \u201c{0}\u201d n\u2019est pas reconnue.
+UnknownEnumValue_1              = Valeur d\u2019\u00e9num\u00e9ration inconnue: {0}.
 UnknownFormatFor_1              = Le format de \u201c{0}\u201d n\u2019est pas reconnu.
 UnknownOption_1                 = L\u2019option \u201c{0}\u201d n\u2019est pas reconnue.
 UnknownType_1                   = Le type \u2018{0}\u2019 n\u2019est pas reconnu dans ce contexte.

Modified: sis/trunk/core/sis-utility/src/test/java/org/apache/sis/internal/converter/FallbackConverterTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/test/java/org/apache/sis/internal/converter/FallbackConverterTest.java?rev=1519087&r1=1519086&r2=1519087&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/test/java/org/apache/sis/internal/converter/FallbackConverterTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/test/java/org/apache/sis/internal/converter/FallbackConverterTest.java [UTF-8] Fri Aug 30 21:00:40 2013
@@ -60,7 +60,8 @@ public final strictfp class FallbackConv
         final EnumSet<FunctionProperty> SURJECTIVE = EnumSet.of(FunctionProperty.SURJECTIVE);
         final EnumSet<FunctionProperty> INVERTIBLE = EnumSet.of(FunctionProperty.SURJECTIVE, FunctionProperty.INVERTIBLE);
 
-        ObjectConverter<String,? extends Object> c = new StringConverter.Short();
+        // The "extends Object" part is unnecessary according Java specification, but Eclipse compiler insists for it.
+        ObjectConverter<String, ? extends Object> c = new StringConverter.Short();
         assertEquals(String.class, c.getSourceClass());
         assertEquals(Short.class,  c.getTargetClass());
         assertEquals(INVERTIBLE,   c.properties());

Modified: sis/trunk/core/sis-utility/src/test/java/org/apache/sis/util/iso/TypesTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/test/java/org/apache/sis/util/iso/TypesTest.java?rev=1519087&r1=1519086&r2=1519087&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/test/java/org/apache/sis/util/iso/TypesTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/test/java/org/apache/sis/util/iso/TypesTest.java [UTF-8] Fri Aug 30 21:00:40 2013
@@ -17,8 +17,11 @@
 package org.apache.sis.util.iso;
 
 import java.util.Set;
+import java.util.Map;
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.HashMap;
+import java.util.TreeMap;
 import java.util.Locale;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.Address;
@@ -31,7 +34,7 @@ import org.opengis.referencing.cs.AxisDi
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static org.junit.Assert.*;
+import static org.opengis.test.Assert.*;
 
 
 /**
@@ -39,11 +42,49 @@ import static org.junit.Assert.*;
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.3 (derived from geotk-2.1)
- * @version 0.3
+ * @version 0.4
  * @module
  */
 public final strictfp class TypesTest extends TestCase {
     /**
+     * Tests the {@link Types#toInternationalString(Map, String)} method.
+     */
+    @Test
+    public void testToInternationalString() {
+        testToInternationalString(new HashMap<String,Object>());
+        testToInternationalString(new TreeMap<String,Object>());
+    }
+
+    /**
+     * Implementation of {@link #testToInternationalString()} using the given map implementation.
+     */
+    private static void testToInternationalString(final Map<String,Object> properties) {
+        assertNull(properties.put("name",       "Some name"));
+        assertNull(properties.put("identifier", "Some identifier"));
+        assertNull(properties.put("code",       "Some code"));
+        assertNull(properties.put("codeSpace",  "Some code space"));
+        assertNull(properties.put("authority",  "Some authority"));
+        assertNull(properties.put("version",    "Some version"));
+        assertNull(properties.put("remarks",    "Some remarks"));
+        assertNull(Types.toInternationalString(properties, "dummy"));
+
+        InternationalString i18n = Types.toInternationalString(properties, "remarks");
+        assertInstanceOf("Single locale", SimpleInternationalString.class, i18n);
+        assertEquals("Some remarks", i18n.toString());
+
+        assertNull(properties.put("remarks_fr", "Une remarque"));
+        i18n = Types.toInternationalString(properties, "remarks");
+        assertInstanceOf("Two locales", DefaultInternationalString.class, i18n);
+        assertEquals("Some remarks", i18n.toString(Locale.ROOT));
+        assertEquals("Une remarque", i18n.toString(Locale.FRENCH));
+
+        assertNotNull(properties.remove("remarks"));
+        i18n = Types.toInternationalString(properties, "remarks");
+        assertInstanceOf("Single locale", SimpleInternationalString.class, i18n);
+        assertEquals("Une remarque", i18n.toString());
+    }
+
+    /**
      * Tests the {@link Types#getStandardName(Class)} method.
      */
     @Test

Modified: sis/trunk/pom.xml
URL: http://svn.apache.org/viewvc/sis/trunk/pom.xml?rev=1519087&r1=1519086&r2=1519087&view=diff
==============================================================================
--- sis/trunk/pom.xml (original)
+++ sis/trunk/pom.xml Fri Aug 30 21:00:40 2013
@@ -733,6 +733,14 @@ Apache SIS is a free software, Java lang
     </pluginRepository>
   </pluginRepositories>
 
+  <repositories>
+    <!--  UCAR repository from which to download the NetCDF library. -->
+    <repository>
+      <id>UCAR</id>
+      <name>UCAR repository</name>
+      <url>https://artifacts.unidata.ucar.edu/content/repositories/unidata-releases</url>
+    </repository>
+  </repositories>
 
 
   <!-- ==============================================================

Modified: sis/trunk/storage/sis-netcdf/pom.xml
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-netcdf/pom.xml?rev=1519087&r1=1519086&r2=1519087&view=diff
==============================================================================
--- sis/trunk/storage/sis-netcdf/pom.xml (original)
+++ sis/trunk/storage/sis-netcdf/pom.xml Fri Aug 30 21:00:40 2013
@@ -125,13 +125,4 @@ Bridge between NetCDF Climate and Foreca
     </dependency>
   </dependencies>
 
-  <!--  UCAR repository from which to download the NetCDF library. -->
-  <repositories>
-    <repository>
-      <id>UCAR</id>
-      <name>UCAR repository</name>
-      <url>https://artifacts.unidata.ucar.edu/content/repositories/unidata-releases</url>
-    </repository>
-  </repositories>
-
 </project>

Modified: sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java?rev=1519087&r1=1519086&r2=1519087&view=diff
==============================================================================
--- sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java [UTF-8] (original)
+++ sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java [UTF-8] Fri Aug 30 21:00:40 2013
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.storage.netcdf;
 
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.lang.reflect.Method;
@@ -34,6 +35,7 @@ import org.apache.sis.storage.StorageCon
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.ProbeResult;
 import org.apache.sis.util.logging.WarningListeners;
+import org.apache.sis.util.logging.Logging;
 import org.apache.sis.util.ThreadSafe;
 import org.apache.sis.util.Version;
 
@@ -139,6 +141,9 @@ public class NetcdfStoreProvider extends
          * 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.
+         *
+         * Note that the UCAR library expects a String argument, not a File, because it
+         * has special cases for "file:", "http:", "nodods:" and "slurp:" protocols.
          */
         if (!isSupported) {
             final String path = storage.getStorageAs(String.class);
@@ -155,6 +160,16 @@ public class NetcdfStoreProvider extends
                     if (cause instanceof DataStoreException) throw (DataStoreException) cause;
                     if (cause instanceof RuntimeException)   throw (RuntimeException)   cause;
                     if (cause instanceof Error)              throw (Error)              cause;
+                    if (cause instanceof FileNotFoundException) {
+                        /*
+                         * Happen if the String argument uses any protocol not recognized by the UCAR library,
+                         * in which case UCAR tries to open it as a file even if it is not a file. For example
+                         * we get this exception for "jar:file:/file.jar!/entry.nc".
+                         */
+                        Logging.recoverableException(
+                                Logging.getLogger("org.apache.sis.storage"), netcdfFileClass, "canOpen", cause);
+                        return ProbeResult.UNSUPPORTED_STORAGE;
+                    }
                     throw new DataStoreException(e); // The cause may be IOException.
                 }
             } else {

Modified: sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/IOUtilities.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/IOUtilities.java?rev=1519087&r1=1519086&r2=1519087&view=diff
==============================================================================
--- sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/IOUtilities.java [UTF-8] (original)
+++ sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/IOUtilities.java [UTF-8] Fri Aug 30 21:00:40 2013
@@ -112,7 +112,8 @@ public final class IOUtilities extends S
             if (path instanceof URL) {
                 name = ((URL) path).getPath();
             } else if (path instanceof URI) {
-                name = ((URI) path).getPath();
+                final URI uri = (URI) path;
+                name = uri.isOpaque() ? uri.getSchemeSpecificPart() : uri.getPath();
             } else if (path instanceof CharSequence) {
                 name = path.toString();
                 separator = File.separatorChar;

Modified: sis/trunk/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/IOUtilitiesTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/IOUtilitiesTest.java?rev=1519087&r1=1519086&r2=1519087&view=diff
==============================================================================
--- sis/trunk/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/IOUtilitiesTest.java [UTF-8] (original)
+++ sis/trunk/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/IOUtilitiesTest.java [UTF-8] Fri Aug 30 21:00:40 2013
@@ -35,7 +35,7 @@ import static org.junit.Assert.*;
  * @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 strictfp class IOUtilitiesTest extends TestCase {
@@ -75,6 +75,26 @@ public final strictfp class IOUtilitiesT
     }
 
     /**
+     * Tests again {@link IOUtilities#filename(Object)} and {@link IOUtilities#extension(Object)}, but with a URI
+     * that point to a JAR entry. Such URI are opaque, in which case {@link URI#getPath()} returns {@code null}.
+     *
+     * @throws URISyntaxException Should never happen.
+     * @throws MalformedURLException Should never happen.
+     */
+    @Test
+    @DependsOnMethod({"testFilename", "testExtension"})
+    public void testWithOpaqueURI() throws URISyntaxException, MalformedURLException {
+        final URI uri = new URI("jar:file:/sis-storage-tests.jar!/org/apache/sis/Any.xml");
+        assertTrue(uri.isOpaque()); // This test would be useless if this condition is false.
+        assertEquals("Any.xml", IOUtilities.filename (uri));
+        assertEquals(    "xml", IOUtilities.extension(uri));
+
+        final URL url = new URL("jar:file:/sis-storage-tests.jar!/org/apache/sis/Any.xml");
+        assertEquals("Any.xml", IOUtilities.filename (url));
+        assertEquals(    "xml", IOUtilities.extension(url));
+    }
+
+    /**
      * Tests {@link IOUtilities#toString(Object)}.
      *
      * @throws URISyntaxException Should never happen.



Mime
View raw message