sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1817597 [12/19] - in /sis/branches/ISO-19115-3: ./ application/ application/sis-console/ application/sis-console/src/main/artifact/ application/sis-console/src/main/artifact/lib/ application/sis-console/src/main/artifact/lib/darwin/ applic...
Date Sat, 09 Dec 2017 10:57:47 GMT
Modified: sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/iso/TypeNames.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/iso/TypeNames.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/iso/TypeNames.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/iso/TypeNames.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -67,7 +67,7 @@ final class TypeNames {
         m.put("Real",            Double.class);
         m.put("Decimal",         Double.class);
         m.put("Integer",         Integer.class);
-    };
+    }
 
     /**
      * The "OGC" namespace.

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/iso/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/iso/package-info.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/iso/package-info.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/iso/package-info.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -128,4 +128,4 @@ import javax.xml.bind.annotation.XmlAcce
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;
 import org.apache.sis.xml.Namespaces;
-import org.apache.sis.internal.jaxb.gco.*;
+import org.apache.sis.internal.jaxb.gco.GO_GenericName;

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/logging/Logging.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/logging/Logging.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/logging/Logging.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/logging/Logging.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -21,6 +21,7 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.logging.LogRecord;
 
+import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.Configuration;
 import org.apache.sis.util.Static;
 import org.apache.sis.util.Exceptions;
@@ -47,7 +48,7 @@ import org.apache.sis.internal.system.Mo
  * </ul>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.6
+ * @version 0.8
  * @since   0.3
  * @module
  */
@@ -204,21 +205,101 @@ public final class Logging extends Stati
      * @param  method  the name of the method which is logging a record.
      * @param  record  the record to log.
      */
-    public static void log(final Class<?> classe, final String method, final LogRecord record) {
-        record.setSourceClassName(classe.getCanonicalName());
-        record.setSourceMethodName(method);
+    public static void log(final Class<?> classe, String method, final LogRecord record) {
+        ArgumentChecks.ensureNonNull("record", record);
         final String loggerName = record.getLoggerName();
-        final Logger logger;
+        Logger logger;
         if (loggerName == null) {
             logger = getLogger(classe);
             record.setLoggerName(logger.getName());
         } else {
             logger = getLogger(loggerName);
         }
+        if (classe != null && method != null) {
+            record.setSourceClassName(classe.getCanonicalName());
+            record.setSourceMethodName(method);
+        } else {
+            /*
+             * If the given class or method is null, infer them from stack trace. We do not document this feature
+             * in public API because the rules applied here are heuristic and may change in any future SIS version.
+             */
+            logger = inferCaller(logger, (classe != null) ? classe.getCanonicalName() : null,
+                            method, Thread.currentThread().getStackTrace(), record);
+        }
         logger.log(record);
     }
 
     /**
+     * Sets the {@code LogRecord} source class and method names according values inferred from the given stack trace.
+     * This method inspects the given stack trace, skips what looks like internal API based on heuristic rules, then
+     * if some arguments are non-null tries to match them.
+     *
+     * @param  logger  where the log record will be sent after this method call, or {@code null} if unknown.
+     * @param  classe  the name of the class to report in the log record, or {@code null} if unknown.
+     * @param  method  the name of the method to report in the log record, or {@code null} if unknown.
+     * @param  trace   the stack trace to use for inferring the class and method names.
+     * @param  record  the record where to set the class and method names.
+     * @return the record to use for logging the record.
+     */
+    private static Logger inferCaller(Logger logger, String classe, String method,
+            final StackTraceElement[] trace, final LogRecord record)
+    {
+        for (final StackTraceElement element : trace) {
+            /*
+             * Search for the first stack trace element with a classname matching the expected one.
+             * We compare against the name of the class given in argument if it was non-null.
+             *
+             * Note: a previous version also compared logger name with package name.
+             * This has been removed because those names are only loosely related.
+             */
+            final String classname = element.getClassName();
+            if (classe != null) {
+                if (!classname.equals(classe)) {
+                    continue;
+                }
+            } else if (!WarningListeners.isPublic(element)) {
+                continue;
+            }
+            /*
+             * Now that we have a stack trace element from the expected class (or any
+             * element if we don't know the class), make sure that we have the right method.
+             */
+            final String methodName = element.getMethodName();
+            if (method != null && !methodName.equals(method)) {
+                continue;
+            }
+            /*
+             * Now computes every values that are null, and stop the loop.
+             */
+            if (logger == null) {
+                final int separator = classname.lastIndexOf('.');
+                logger = getLogger((separator >= 1) ? classname.substring(0, separator-1) : "");
+            }
+            if (classe == null) {
+                classe = classname;
+            }
+            if (method == null) {
+                method = methodName;
+            }
+            break;
+        }
+        /*
+         * The logger may stay null if we have been unable to find a suitable stack trace.
+         * Fallback on the global logger.
+         */
+        if (logger == null) {
+            logger = getLogger(Logger.GLOBAL_LOGGER_NAME);
+        }
+        if (classe != null) {
+            record.setSourceClassName(classe);
+        }
+        if (method != null) {
+            record.setSourceMethodName(method);
+        }
+        return logger;
+    }
+
+    /**
      * Invoked when an unexpected error occurred. This method logs a message at {@link Level#WARNING}
      * to the specified logger. The originating class name and method name can optionally be specified.
      * If any of them is {@code null}, then it will be inferred from the error stack trace as described below.
@@ -290,79 +371,6 @@ public final class Logging extends Stati
             return false;
         }
         /*
-         * Loggeable, so complete the null argument from the stack trace if we can.
-         */
-        if (logger == null || classe == null || method == null) {
-            String paquet = (logger != null) ? logger.getName() : null;
-            for (final StackTraceElement element : error.getStackTrace()) {
-                /*
-                 * Searches for the first stack trace element with a classname matching the
-                 * expected one. We compare preferably against the name of the class given
-                 * in argument, or against the logger name (taken as the package name) otherwise.
-                 */
-                final String classname = element.getClassName();
-                if (classe != null) {
-                    if (!classname.equals(classe)) {
-                        continue;
-                    }
-                } else if (paquet != null) {
-                    if (!classname.startsWith(paquet)) {
-                        continue;
-                    }
-                    final int length = paquet.length();
-                    if (classname.length() > length) {
-                        /*
-                         * We expect '.' but we accept also '$' or end of string.
-                         */
-                        final char separator = classname.charAt(length);
-                        if (Character.isJavaIdentifierPart(separator)) {
-                            continue;
-                        }
-                    }
-                }
-                /*
-                 * Now that we have a stack trace element from the expected class (or any
-                 * element if we don't know the class), make sure that we have the right method.
-                 */
-                final String methodName = element.getMethodName();
-                if (method != null && !methodName.equals(method)) {
-                    continue;
-                }
-                /*
-                 * Now computes every values that are null, and stop the loop.
-                 */
-                if (paquet == null) {
-                    final int separator = classname.lastIndexOf('.');
-                    paquet = (separator >= 1) ? classname.substring(0, separator-1) : "";
-                    logger = getLogger(paquet);
-                    if (!logger.isLoggable(level)) {
-                        return false;
-                    }
-                }
-                if (classe == null) {
-                    classe = classname;
-                }
-                if (method == null) {
-                    method = methodName;
-                }
-                break;
-            }
-            /*
-             * The logger may stay null if we have been unable to find a suitable
-             * stack trace. Fallback on the global logger.
-             */
-            if (logger == null) {
-                logger = getLogger(Logger.GLOBAL_LOGGER_NAME);
-                if (!logger.isLoggable(level)) {
-                    return false;
-                }
-            }
-        }
-        /*
-         * Now prepare the log message. If we have been unable to figure out a source class and
-         * method name, we will fallback on JDK logging default mechanism, which may returns a
-         * less relevant name than our attempt to use the logger name as the package name.
-         *
          * The message is fetched using Exception.getMessage() instead than getLocalizedMessage()
          * because in a client-server architecture, we want the locale on the server-side instead
          * than the locale on the client side. See LocalizedException policy.
@@ -375,15 +383,15 @@ public final class Logging extends Stati
         message = buffer.toString();
         message = Exceptions.formatChainedMessages(null, message, error);
         final LogRecord record = new LogRecord(level, message);
-        if (classe != null) {
-            record.setSourceClassName(classe);
-        }
-        if (method != null) {
-            record.setSourceMethodName(method);
-        }
         if (level.intValue() >= LEVEL_THRESHOLD_FOR_STACKTRACE) {
             record.setThrown(error);
         }
+        if (logger == null || classe == null || method == null) {
+            logger = inferCaller(logger, classe, method, error.getStackTrace(), record);
+        } else {
+            record.setSourceClassName(classe);
+            record.setSourceMethodName(method);
+        }
         record.setLoggerName(logger.getName());
         logger.log(record);
         return true;

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/logging/MonolineFormatter.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/logging/MonolineFormatter.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/logging/MonolineFormatter.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/logging/MonolineFormatter.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -109,7 +109,7 @@ import static org.apache.sis.internal.ut
  * from multiple threads.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.0
  *
  * @see SimpleFormatter
  * @see Handler#setFormatter(Formatter)
@@ -164,6 +164,11 @@ public class MonolineFormatter extends F
     private static final boolean SHOW_LEVEL = true;
 
     /**
+     * Number of spaces to colorize at the beginning of lines that are continuation of a single log record.
+     */
+    private static final int CONTINUATION_MARGIN = 4;
+
+    /**
      * Minimal number of stack trace elements to print before and after the "interesting" elements.
      * The "interesting" elements are the first stack trace elements, and the element which point
      * to the method that produced the log record.
@@ -173,6 +178,11 @@ public class MonolineFormatter extends F
     private static final int CONTEXT_STACK_TRACE_ELEMENTS = 2;
 
     /**
+     * Maximal amount of causes to print in stack traces. This is an arbitrary limit.
+     */
+    private static final int MAX_CAUSES = 10;
+
+    /**
      * The string to write on the left side of the first line of every log records.
      * The default value is an empty string. This field can not be null.
      *
@@ -330,7 +340,7 @@ public class MonolineFormatter extends F
 
     /**
      * Returns the length of the widest level name, taking in account only the standard levels
-     * equals or greater then the given threshold.
+     * equals or greater than the given threshold.
      */
     static int levelWidth(final Level threshold) {
         int levelWidth = 0;
@@ -624,11 +634,18 @@ loop:   for (int i=0; ; i++) {
      */
     @Override
     public String format(final LogRecord record) {
+        boolean faint = false;                      // Whether to use faint text for level < INFO.
+        String emphaseStart = "";                   // ANSI escape sequence for bold text if we use it.
+        String emphaseEnd   = "";                   // ANSI escape sequence for stopping bold text if we use it.
         final Level level = record.getLevel();
         final StringBuffer buffer = this.buffer;
         synchronized (buffer) {
-            final boolean colors  = (this.colors != null);
-            final boolean emphase = !faintSupported || (level.intValue() >= LEVEL_THRESHOLD.intValue());
+            final boolean colors = (this.colors != null);
+            if (colors && level.intValue() >= LEVEL_THRESHOLD.intValue()) {
+                emphaseStart = X364.BOLD.sequence();
+                emphaseEnd   = X364.NORMAL.sequence();
+                faint        = faintSupported;
+            }
             buffer.setLength(header.length());
             /*
              * Appends the time (e.g. "00:00:12.365"). The time pattern can be set either
@@ -651,10 +668,10 @@ loop:   for (int i=0; ; i++) {
                     levelColor = colorAt(level);
                     levelReset = X364.BACKGROUND_DEFAULT.sequence();
                 }
-                final int offset = buffer.append(levelColor).length();
-                buffer.append(level.getLocalizedName())
-                      .append(CharSequences.spaces(levelWidth - (buffer.length() - offset)));
-                margin += buffer.length() - offset;
+                final int offset = buffer.append(levelColor).append(emphaseStart).length();
+                final int length = buffer.append(level.getLocalizedName()).length() - offset;
+                buffer.append(emphaseEnd).append(CharSequences.spaces(levelWidth - length));
+                margin += buffer.length() - emphaseEnd.length() - offset;
                 buffer.append(levelReset).append(' ');
             }
             /*
@@ -683,14 +700,7 @@ loop:   for (int i=0; ; i++) {
                 if (sourceFormat == METHOD) {
                     source = source + '.' + record.getSourceMethodName();
                 }
-                if (colors && emphase) {
-                    buffer.append(X364.BOLD.sequence());
-                }
-                buffer.append('[').append(source).append(']');
-                if (colors && emphase) {
-                    buffer.append(X364.NORMAL.sequence());
-                }
-                buffer.append(' ');
+                buffer.append(emphaseStart).append('[').append(source).append(']').append(emphaseEnd).append(' ');
             }
             /*
              * Now prepare the LineAppender for the message. We set a line separator prefixed by some
@@ -699,10 +709,12 @@ loop:   for (int i=0; ; i++) {
             String bodyLineSeparator = writer.getLineSeparator();
             final String lineSeparator = System.lineSeparator();
             if (bodyLineSeparator.length() != lineSeparator.length() + margin + 1) {
-                bodyLineSeparator = lineSeparator + levelColor + CharSequences.spaces(margin) + levelReset + ' ';
+                final int highlight = Math.min(CONTINUATION_MARGIN, margin);
+                bodyLineSeparator = lineSeparator + levelColor + CharSequences.spaces(highlight)
+                                                  + levelReset + CharSequences.spaces(margin - highlight + 1);
                 writer.setLineSeparator(bodyLineSeparator);
             }
-            if (colors && !emphase) {
+            if (faint) {
                 buffer.append(X364.FAINT.sequence());
             }
             final Throwable exception = record.getThrown();
@@ -736,7 +748,7 @@ loop:   for (int i=0; ; i++) {
                 throw new AssertionError(e);
             }
             buffer.setLength(CharSequences.skipTrailingWhitespaces(buffer, 0, buffer.length()));
-            if (colors && !emphase) {
+            if (faint) {
                 buffer.append(X364.NORMAL.sequence());
             }
             buffer.append(lineSeparator);
@@ -812,8 +824,7 @@ loop:   for (int i=0; ; i++) {
             final String loggerName, final String sourceClassName, final String sourceMethodName) throws IOException
     {
         StackTraceElement previous = null;
-        // Arbitrary limit of 10 causes to format.
-        for (int numCauses=0; numCauses<10; numCauses++) {
+        for (int numCauses=0; numCauses<MAX_CAUSES; numCauses++) {
             final StackTraceElement[] trace = exception.getStackTrace();
             /*
              * Find the index of the stack trace element where the log has been produced.

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/logging/QuietLogRecord.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/logging/QuietLogRecord.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/logging/QuietLogRecord.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/logging/QuietLogRecord.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -24,7 +24,7 @@ import java.util.logging.LogRecord;
  * A log record to be logged without stack trace, unless the user specified it explicitely.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.3
+ * @version 0.8
  * @since   0.3
  * @module
  */
@@ -43,8 +43,8 @@ final class QuietLogRecord extends LogRe
     /**
      * Creates a new log record for the given message and exception.
      */
-    QuietLogRecord(final String message, final Exception exception) {
-        super(Level.WARNING, message);
+    QuietLogRecord(final Level level, final String message, final Exception exception) {
+        super(level, message);
         super.setThrown(exception);
     }
 

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/logging/WarningListeners.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/logging/WarningListeners.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/logging/WarningListeners.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/logging/WarningListeners.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -27,6 +27,7 @@ import org.apache.sis.util.Localized;
 import org.apache.sis.util.Exceptions;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
+import org.apache.sis.internal.system.Modules;
 import org.apache.sis.internal.util.UnmodifiableArrayList;
 
 
@@ -120,6 +121,18 @@ public class WarningListeners<S> impleme
     }
 
     /**
+     * Returns the source declared source of warnings.
+     * This value is specified at construction time.
+     *
+     * @return the declared source of warnings.
+     *
+     * @since 0.8
+     */
+    public S getSource() {
+        return source;
+    }
+
+    /**
      * The locale to use for formatting warning messages, or {@code null} for the default locale.
      * If the {@code source} object given to the constructor implements the {@link Localized} interface,
      * then this method delegates to its {@code getLocale()} method. Otherwise this method returns {@code null}.
@@ -191,6 +204,24 @@ public class WarningListeners<S> impleme
      * Reports a warning represented by the given message and exception.
      * At least one of {@code message} and {@code exception} shall be non-null.
      * If both are non-null, then the exception message will be concatenated after the given message.
+     * If the exception is non-null, its stack trace will be omitted at logging time for avoiding to
+     * pollute console output (keeping in mind that this method should be invoked only for non-fatal
+     * warnings). See {@linkplain #warning(Level, String, Exception) below} for more explanation.
+     *
+     * <p>This method is a shortcut for <code>{@linkplain #warning(Level, String, Exception)
+     * warning}({@linkplain Level#WARNING}, message, exception)</code>.
+     *
+     * @param message    the message to log, or {@code null} if none.
+     * @param exception  the exception to log, or {@code null} if none.
+     */
+    public void warning(String message, Exception exception) {
+        warning(Level.WARNING, message, exception);
+    }
+
+    /**
+     * Reports a warning at the given level represented by the given message and exception.
+     * At least one of {@code message} and {@code exception} shall be non-null.
+     * If both are non-null, then the exception message will be concatenated after the given message.
      *
      * <div class="section">Stack trace omission</div>
      * If there is no registered listener, then the {@link #warning(LogRecord)} method will send the record to the
@@ -204,10 +235,12 @@ public class WarningListeners<S> impleme
      *   <li>register a listener which will log the record itself.</li>
      * </ul>
      *
+     * @param level      the warning level.
      * @param message    the message to log, or {@code null} if none.
      * @param exception  the exception to log, or {@code null} if none.
      */
-    public void warning(String message, final Exception exception) {
+    public void warning(final Level level, String message, final Exception exception) {
+        ArgumentChecks.ensureNonNull("level", level);
         final LogRecord record;
         final StackTraceElement[] trace;
         if (exception != null) {
@@ -216,11 +249,11 @@ public class WarningListeners<S> impleme
             if (message == null) {
                 message = exception.toString();
             }
-            record = new QuietLogRecord(message, exception);
+            record = new QuietLogRecord(level, message, exception);
         } else {
             ArgumentChecks.ensureNonEmpty("message", message);
             trace = Thread.currentThread().getStackTrace();
-            record = new LogRecord(Level.WARNING, message);
+            record = new LogRecord(level, message);
         }
         for (final StackTraceElement e : trace) {
             if (isPublic(e)) {
@@ -235,6 +268,7 @@ public class WarningListeners<S> impleme
     /**
      * Returns {@code true} if the given stack trace element describes a method considered part of public API.
      * This method is invoked in order to infer the class and method names to declare in a {@link LogRecord}.
+     * We do not document this feature in public Javadoc because it is based on heuristic rules that may change.
      *
      * <p>The current implementation compares the class name against a hard-coded list of classes to hide.
      * This implementation may change in any future SIS version.</p>
@@ -242,11 +276,17 @@ public class WarningListeners<S> impleme
      * @param  e  a stack trace element.
      * @return {@code true} if the class and method specified by the given element can be considered public API.
      */
-    private static boolean isPublic(final StackTraceElement e) {
-        final String classname  = e.getClassName();
-        return !classname.equals("org.apache.sis.util.logging.WarningListeners") &&
-               !classname.contains(".internal.") && !classname.startsWith("java") &&
-                classname.indexOf('$') < 0 && e.getMethodName().indexOf('$') < 0;
+    static boolean isPublic(final StackTraceElement e) {
+        final String classname = e.getClassName();
+        if (classname.startsWith("java") || classname.contains(".internal.") ||
+            classname.indexOf('$') >= 0 || e.getMethodName().indexOf('$') >= 0)
+        {
+            return false;
+        }
+        if (classname.startsWith(Modules.CLASSNAME_PREFIX + "util.logging.")) {
+            return classname.endsWith("Test");      // Consider JUnit tests as public.
+        }
+        return true;    // TODO: with StackWalker on JDK9, check if the class is public.
     }
 
     /**

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/logging/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/logging/package-info.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/logging/package-info.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/logging/package-info.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -50,7 +50,7 @@
  * order to give SIS a chance to redirect log events to an other logging framework.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.3
+ * @version 1.0
  *
  * @see <a href="http://download.oracle.com/javase/6/docs/technotes/guides/logging/overview.html">Java Logging Overview</a>
  *

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -483,28 +483,6 @@ public class IndexedResourceBundle exten
     }
 
     /**
-     * Gets a string for the given key and appends ":" to it.
-     * A space may or may not be added before ":", depending on the locale.
-     * No space is added after the string; it is up to the caller to add such space if needed.
-     *
-     * @param  key  the key for the desired string.
-     * @return the string for the given key.
-     * @throws MissingResourceException if no object for the given key can be found.
-     *
-     * @deprecated Replaced by {@link #appendLabel(short, Appendable)}.
-     */
-    @Deprecated
-    public final String getLabel(final short key) throws MissingResourceException {
-        String label = getString(key);
-        if (Locale.FRENCH.getLanguage().equals(getLocale().getLanguage())) {
-            label += "\u00A0:";
-        } else {
-            label += ':';
-        }
-        return label;
-    }
-
-    /**
      * Gets a string for the given key from this resource bundle or one of its parents.
      *
      * @param  key  the key for the desired string.

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/NilReason.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/NilReason.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/NilReason.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/NilReason.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -145,7 +145,7 @@ public final class NilReason implements
 
     /**
      * Either the XML value as a {@code String} (including the explanation if the prefix
-     * is "{@code other}", or an {@link URI}.
+     * is "{@code other}", or a {@link URI}.
      */
     private final Object reason;
 
@@ -253,7 +253,7 @@ public final class NilReason implements
                 }
                 String result = buffer.toString();
                 if (result.equals(reason)) {
-                    result = reason; // Use the existing instance.
+                    result = reason;                            // Use the existing instance.
                 }
                 return POOL.unique(new NilReason(result));
             }
@@ -422,7 +422,7 @@ public final class NilReason implements
                 PrimitiveTypeProperties.associate(object, this);
             }
             if (nilObjects.put(type, object) != null) {
-                throw new AssertionError(type); // Should never happen.
+                throw new AssertionError(type);                                 // Should never happen.
             }
         }
         return type.cast(object);

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/Pooled.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/Pooled.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/Pooled.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/Pooled.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -399,11 +399,9 @@ abstract class Pooled {
         if (internal) {
             name = Implementation.toInternal(name);
         }
-        if (!initialProperties.containsKey(name)) {
-            if (initialProperties.put(name, getStandardProperty(name)) != null) {
-                // Should never happen, unless on concurrent changes in a backgroung thread.
-                throw new ConcurrentModificationException(name);
-            }
+        if (!initialProperties.containsKey(name) && initialProperties.put(name, getStandardProperty(name)) != null) {
+            // Should never happen, unless on concurrent changes in a backgroung thread.
+            throw new ConcurrentModificationException(name);
         }
         setStandardProperty(name, value);
     }

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/ReferenceResolver.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/ReferenceResolver.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/ReferenceResolver.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/ReferenceResolver.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -112,7 +112,7 @@ public class ReferenceResolver {
      * The default implementation performs the following lookups:
      *
      * <ul>
-     *   <li>If the {@link XLink#getHRef() xlink:href} attribute is an {@linkplain URI#getFragment() URI fragment}
+     *   <li>If the {@link XLink#getHRef() xlink:href} attribute is a {@linkplain URI#getFragment() URI fragment}
      *       of the form {@code "#foo"} and if an object of class {@code type} with the {@code gml:id="foo"} attribute
      *       has previously been seen in the same XML document, then that object is returned.</li>
      *   <li>Otherwise returns {@code null}.</li>

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/main/resources/org/apache/sis/measure/UnitNames.properties
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/main/resources/org/apache/sis/measure/UnitNames.properties?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/main/resources/org/apache/sis/measure/UnitNames.properties [ISO-8859-1] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/main/resources/org/apache/sis/measure/UnitNames.properties [ISO-8859-1] Sat Dec  9 10:57:44 2017
@@ -45,6 +45,7 @@ psu=practical salinity unit
 pt=point
 px=pixel
 rad=radian
+rad\u2215s=radians per second
 s=second
 S=siemens
 sr=steradian

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/main/resources/org/apache/sis/measure/UnitNames_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/main/resources/org/apache/sis/measure/UnitNames_fr.properties?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/main/resources/org/apache/sis/measure/UnitNames_fr.properties [ISO-8859-1] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/main/resources/org/apache/sis/measure/UnitNames_fr.properties [ISO-8859-1] Sat Dec  9 10:57:44 2017
@@ -24,6 +24,7 @@ mm=millimètre
 ms=milliseconde
 nm=nanomètre
 ppm=parties par million
+rad\u2215s=radians par seconde
 s=seconde
 sr=stéradian
 unity=unité

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/internal/converter/PathConverterTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/internal/converter/PathConverterTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/internal/converter/PathConverterTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/internal/converter/PathConverterTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -30,7 +30,7 @@ import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static org.junit.Assume.*;
+import static org.junit.Assume.assumeTrue;
 import static org.apache.sis.test.Assert.*;
 
 
@@ -49,7 +49,7 @@ public final strictfp class PathConverte
      * Windows platform has driver letters instead, like "C:\\",
      * which are not correctly tested by this class.
      */
-    static void assumeUnixRoot() {
+    private static void assumeUnixRoot() {
         assumeTrue(ArraysExt.contains(File.listRoots(), new File("/")));
     }
 

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/internal/util/CitationsTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/internal/util/CitationsTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/internal/util/CitationsTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/internal/util/CitationsTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -23,8 +23,6 @@ import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
 import org.apache.sis.internal.simple.SimpleCitation;
 import org.apache.sis.internal.simple.SimpleIdentifier;
-import org.apache.sis.xml.IdentifierSpace;
-import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
@@ -114,40 +112,4 @@ public final strictfp class CitationsTes
         assertEquals("OGC:06-042", Citations.getIdentifier(citation, false));
         assertEquals("ISO_19128",  Citations.getIdentifier(citation, true));
     }
-
-    /**
-     * Tests {@link Citations#getCodeSpace(Citation)} with some ignorable characters.
-     * Ignorable character used in this test are:
-     *
-     * <ul>
-     *   <li>200B: zero width space</li>
-     *   <li>2060: word joiner</li>
-     * </ul>
-     */
-    @Test
-    @DependsOnMethod("testGetIdentifier")
-    public void testGetCodeSpace() {
-        final SimpleCitation citation = new SimpleCitation(" Valid\u2060Id\u200Bentifier ");
-        assertEquals("ValidIdentifier", Citations.getCodeSpace(citation));
-
-        assertNull("Shall not be taken as a valid identifier.",
-                Citations.getCodeSpace(new SimpleCitation("Proj.4")));
-        assertEquals("Shall fallback on the the identifier space name.",
-                "TheProj4Space", Citations.getCodeSpace(new Proj4()));
-    }
-
-    /**
-     * A citation which is also an {@link IdentifierSpace}, for {@link #testGetCodeSpace()} purpose.
-     */
-     @SuppressWarnings("serial")
-     private static final class Proj4 extends SimpleCitation implements IdentifierSpace<Integer> {
-        Proj4() {
-            super("Proj.4");
-        }
-
-        @Override
-        public String getName() {
-            return "TheProj4Space";         // Intentionally a very different name than "Proj4".
-        }
-    }
 }

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/internal/util/DefinitionURITest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/internal/util/DefinitionURITest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/internal/util/DefinitionURITest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/internal/util/DefinitionURITest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -27,7 +27,7 @@ import static org.junit.Assert.*;
  * Tests {@link DefinitionURI}.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 0.8
  * @since   0.4
  * @module
  */
@@ -143,6 +143,51 @@ public final strictfp class DefinitionUR
     }
 
     /**
+     * Tests comma-separated URNs in the {@code "urn:ogc:def"} namespace.
+     * Example: {@code "urn:ogc:def:crs,crs:EPSG:6.3:27700,crs:EPSG:6.3:5701"}.
+     */
+    @Test
+    @DependsOnMethod("testParse")
+    public void testCompoundURN() {
+        DefinitionURI parsed = DefinitionURI.parse("urn:ogc:def:crs, crs :EPSG:9.1:27700, crs:EPSG: 9.1 :5701");
+        assertNotNull("components",                    parsed.components);
+        assertEquals("components.length", 2,           parsed.components.length);
+        assertEquals("urn:ogc:def:crs:EPSG:9.1:27700", parsed.components[0].toString());
+        assertEquals("urn:ogc:def:crs:EPSG:9.1:5701",  parsed.components[1].toString());
+        assertEquals("urn:ogc:def:crs,crs:EPSG:9.1:27700,crs:EPSG:9.1:5701", parsed.toString());
+        /*
+         * The following URN is malformed, but Apache SIS should be tolerant to some errors.
+         *
+         *   - the "urn:ogc:def" prefix should be omitted in components, but SIS should be able to skip them.
+         *   - the "ogc:crs" parts should not be accepted because "def" is missing between "ogc" and "crs".
+         */
+        parsed = DefinitionURI.parse("urn:ogc:def:crs,urn:ogc:def:crs:EPSG:9.1:27700,ogc:crs:EPSG:9.1:5701,def:crs:OGC::AnsiDate");
+        assertNotNull("components",                    parsed.components);
+        assertEquals("components.length", 3,           parsed.components.length);
+        assertEquals("urn:ogc:def:crs:EPSG:9.1:27700", parsed.components[0].toString());
+        assertNull  ("urn:ogc:def:crs:EPSG:9.1:5701",  parsed.components[1]);
+        assertEquals("urn:ogc:def:crs:OGC::AnsiDate",  parsed.components[2].toString());
+    }
+
+    /**
+     * Tests compound CRS in HTTP URL.
+     */
+    @Test
+    @DependsOnMethod("testParseHTTP")
+    public void testCompoundHTTP() {
+        DefinitionURI parsed = DefinitionURI.parse("http://www.opengis.net/def/crs-compound?"
+                + "1=http://www.opengis.net/def/crs/EPSG/9.1/27700&"
+                + "2=http://www.opengis.net/def/crs/EPSG/9.1/5701");
+        assertEquals("type", "crs-compound", parsed.type);
+        assertEquals("components.length", 2, parsed.components.length);
+        assertEquals("http://www.opengis.net/def/crs/EPSG/9.1/27700", parsed.components[0].toString());
+        assertEquals("http://www.opengis.net/def/crs/EPSG/9.1/5701",  parsed.components[1].toString());
+        assertEquals("http://www.opengis.net/def/crs-compound?"
+                 + "1=http://www.opengis.net/def/crs/EPSG/9.1/27700&"
+                 + "2=http://www.opengis.net/def/crs/EPSG/9.1/5701", parsed.toString());
+    }
+
+    /**
      * Tests {@link DefinitionURI#codeOf(String, String, String)} with URI like {@code "EPSG:4326"}.
      */
     @Test
@@ -187,13 +232,4 @@ public final strictfp class DefinitionUR
         assertNull  (        DefinitionURI.codeOf("uom", "EPSG", "http://www.opengis.net/gml/srs/epsg.xml#4326"));
         assertNull  (        DefinitionURI.codeOf("uom", "EPSG", "http://schemas.opengis.net/iso/19139/20070417/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])"));
     }
-
-    /**
-     * Tests {@link DefinitionURI#format(String, String, String, String)}.
-     */
-    @Test
-    public void testToURN() {
-        assertEquals("urn:ogc:def:crs:EPSG::4326", DefinitionURI.format("crs", "EPSG", null, "4326"));
-        assertNull  ("Authority is not optional.", DefinitionURI.format("crs", null,   null, "4326"));
-    }
 }

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/measure/RangeTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/measure/RangeTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/measure/RangeTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/measure/RangeTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -20,7 +20,7 @@ import java.util.Locale;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static org.junit.Assume.*;
+import static org.junit.Assume.assumeTrue;
 import static org.apache.sis.test.Assert.*;
 
 

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -90,6 +90,7 @@ public final strictfp class UnitFormatTe
         verify(declared, "WEEK",                "T",            "wk",    "week",                    Units.WEEK);
         verify(declared, "TROPICAL_YEAR",       "T",            "a",     "year",                    Units.TROPICAL_YEAR);
         verify(declared, "HERTZ",               "∕T",           "Hz",    "hertz",                   Units.HERTZ);
+        verify(declared, "RADIANS_PER_SECOND",  "∕T",           "rad∕s", "radians per second",      Units.RADIANS_PER_SECOND);
         verify(declared, "METRES_PER_SECOND",   "L∕T",          "m∕s",   "metres per second",       Units.METRES_PER_SECOND);
         verify(declared, "KILOMETRES_PER_HOUR", "L∕T",          "km∕h",  "kilometres per hour",     Units.KILOMETRES_PER_HOUR);
         verify(declared, "PASCAL",              "M∕(L⋅T²)",     "Pa",    "pascal",                  Units.PASCAL);

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -276,7 +276,7 @@ public final strictfp class UnitsTest ex
 
     /**
      * Tests {@link Units#valueOf(String)} with more advanced units.
-     * Those units are found in NetCDF files among others.
+     * Those units are found in netCDF files among others.
      */
     @Test
     public void testAdvancedValueOf() {

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/test/Assert.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/test/Assert.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/test/Assert.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/test/Assert.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -19,10 +19,13 @@ package org.apache.sis.test;
 import java.util.Set;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Iterator;
 import java.util.Collection;
 import java.util.Enumeration;
 import java.util.LinkedHashSet;
 import java.util.LinkedHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
@@ -37,12 +40,17 @@ import org.apache.sis.util.ComparisonMod
 import org.apache.sis.util.Exceptions;
 import org.apache.sis.util.Classes;
 
+// Branch-dependent imports
+import java.util.stream.Stream;
+import java.util.function.Consumer;
+
 
 /**
  * Assertion methods used by the SIS project in addition of the JUnit and GeoAPI assertions.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @author  Alexis Manin (Geomatys)
+ * @version 0.8
  * @since   0.3
  * @module
  */
@@ -169,6 +177,77 @@ public strictfp class Assert extends org
         }
     }
 
+    /**
+     * Verifies that the given stream produces the same values than the given iterator, in same order.
+     * This method assumes that the given stream is sequential.
+     *
+     * @param  <E>       the type of values to test.
+     * @param  expected  the expected values.
+     * @param  actual    the stream to compare with the expected values.
+     *
+     * @since 0.8
+     */
+    public static <E> void assertSequentialStreamEquals(final Iterator<E> expected, final Stream<E> actual) {
+        actual.forEach(new Consumer<E>() {
+            private int count;
+
+            @Override
+            public void accept(final Object value) {
+                if (!expected.hasNext()) {
+                    fail("Expected " + count + " elements, but the stream contains more.");
+                }
+                final Object ex = expected.next();
+                if (!Objects.equals(ex, value)) {
+                    fail("Expected " + ex + " at index " + count + " but got " + value);
+                }
+                count++;
+            }
+        });
+        assertFalse("Unexpected end of stream.", expected.hasNext());
+    }
+
+    /**
+     * Verifies that the given stream produces the same values than the given iterator, in any order.
+     * This method is designed for use with parallel streams, but works with sequential streams too.
+     *
+     * @param  <E>       the type of values to test.
+     * @param  expected  the expected values.
+     * @param  actual    the stream to compare with the expected values.
+     *
+     * @since 0.8
+     */
+    public static <E> void assertParallelStreamEquals(final Iterator<E> expected, final Stream<E> actual) {
+        final Integer ONE = 1;          // For doing autoboxing only once.
+        final ConcurrentMap<E,Integer> count = new ConcurrentHashMap<>();
+        while (expected.hasNext()) {
+            count.merge(expected.next(), ONE, (old, one) -> old + 1);
+        }
+        /*
+         * Following may be parallelized in an arbitrary amount of threads.
+         */
+        actual.forEach((value) -> {
+            if (count.computeIfPresent(value, (key, old) -> old - 1) == null) {
+                fail("Stream returned unexpected value: " + value);
+            }
+        });
+        /*
+         * Back to sequential order, verify that all elements have been traversed
+         * by the stream and no more.
+         */
+        for (final Map.Entry<E,Integer> entry : count.entrySet()) {
+            int n = entry.getValue();
+            if (n != 0) {
+                final String message;
+                if (n < 0) {
+                    message = "Stream returned too many occurrences of %s%n%d extraneous were found.";
+                } else {
+                    message = "Stream did not returned all expected occurrences of %s%n%d are missing.";
+                }
+                fail(String.format(message, entry.getKey(), StrictMath.abs(n)));
+            }
+        }
+    }
+
     /**
      * Asserts that the given set contains the same elements, ignoring order.
      * In case of failure, this method lists the missing or unexpected elements.

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/test/Assume.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/test/Assume.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/test/Assume.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/test/Assume.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -16,11 +16,9 @@
  */
 package org.apache.sis.test;
 
-import org.apache.sis.internal.system.DataDirectory;
-
-// Branch-specific imports
 import java.nio.file.Path;
 import java.nio.file.Files;
+import org.apache.sis.internal.system.DataDirectory;
 
 
 /**
@@ -52,11 +50,12 @@ public final strictfp class Assume exten
      * @return the path to the given file.
      */
     public static Path assumeDataExists(final DataDirectory type, final String file) {
-        assumeNotNull(System.getenv(DataDirectory.ENV));
+        assumeNotNull("$SIS_DATA environment variable not set.", System.getenv(DataDirectory.ENV));
         Path path = type.getDirectory();
-        assumeNotNull(path);
+        assumeNotNull("$SIS_DATA/" + type + " directory not found.", path);
         path = path.resolve(file);
-        assumeTrue(Files.isReadable(path));
+        assumeTrue("Specified directory not found.", Files.isDirectory(path));
+        assumeTrue("Specified directory not readable.", Files.isReadable(path));
         return path;
     }
 }

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/test/TestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/test/TestSuite.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/test/TestSuite.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/test/TestSuite.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -28,7 +28,9 @@ import java.net.URL;
 import java.net.URISyntaxException;
 import org.apache.sis.internal.system.Shutdown;
 import org.apache.sis.internal.system.SystemListener;
+import org.apache.sis.util.logging.MonolineFormatter;
 import org.apache.sis.util.Classes;
+import org.junit.BeforeClass;
 import org.junit.AfterClass;
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
@@ -40,7 +42,7 @@ import static org.junit.Assert.*;
  * Base class of Apache SIS test suites (except the ones that extend GeoAPI suites).
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.0
  * @since   0.3
  * @module
  */
@@ -240,6 +242,21 @@ public abstract strictfp class TestSuite
     }
 
     /**
+     * Installs Apache SIS monoline formatter for easier identification of Apache SIS log messages among Maven outputs.
+     * We perform this installation only for {@code *TestSuite}, not for individual {@code *Test}. Consequently this is
+     * typically enabled when building a whole module with Maven but not when debugging an individual class.
+     *
+     * @since 1.0
+     */
+    @BeforeClass
+    public static void configureLogging() {
+        MonolineFormatter f = MonolineFormatter.install();
+        f.setHeader(null);
+        f.setTimeFormat(null);
+        f.setSourceFormat("class.method");
+    }
+
+    /**
      * Simulates a module uninstall after all tests. This method will first notify any classpath-dependant
      * services that the should clear their cache, then stop the SIS daemon threads. Those operations are
      * actually not needed in non-server environment (it is okay to just let the JVM stop by itself), but

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/test/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/test/package-info.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/test/package-info.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/test/package-info.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -41,7 +41,7 @@
  * </ul>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.3
+ * @version 1.0
  * @since   0.3
  * @module
  */

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -83,7 +83,6 @@ import org.junit.BeforeClass;
     org.apache.sis.util.collection.CodeListSetTest.class,
     org.apache.sis.internal.util.CollectionsExtTest.class,
     org.apache.sis.internal.util.AbstractMapTest.class,
-    org.apache.sis.internal.util.LazySetTest.class,
 
     // GeoAPI most basic types.
     org.apache.sis.internal.util.DefinitionURITest.class,

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/util/collection/IntegerListTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/util/collection/IntegerListTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/util/collection/IntegerListTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/util/collection/IntegerListTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -21,7 +21,9 @@ import java.util.ArrayList;
 import java.util.Set;
 import java.util.HashSet;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.Random;
+import java.util.ConcurrentModificationException;
 import org.apache.sis.test.TestCase;
 import org.apache.sis.test.TestUtilities;
 import org.junit.Test;
@@ -29,66 +31,105 @@ import org.junit.Test;
 import static java.lang.StrictMath.*;
 import static org.apache.sis.test.Assert.*;
 
+// Branch-dependent imports
+import java.util.function.IntConsumer;
+import java.util.PrimitiveIterator;
+import java.util.stream.IntStream;
+
 
 /**
  * Tests {@link IntegerList} implementations.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @author  Alexis Manin (Geomatys)
+ * @version 0.8
  * @since   0.7
  * @module
  */
 public final strictfp class IntegerListTest extends TestCase {
     /**
-     * The list of integers.
+     * The list of integers being tested.
      */
     private IntegerList list;
 
     /**
      * Writes values and read them again for making sure they are the expected ones.
+     * This method tests also split iterators.
      *
      * @param maximalValue  the maximal value allowed.
      */
     private void testReadWrite(final int maximalValue) {
         final Random random = TestUtilities.createRandomNumberGenerator();
-        final int length = 400;
-        // Use half the lenght as initial capacity in order to test dynamic resizing.
+        final int length = 350 + random.nextInt(101);
+        /*
+         * Use half the lenght as initial capacity in order to test dynamic resizing.
+         * Dynamic resizing should happen in one of the call to list.add(value) after
+         * about 200 values.
+         */
         list = new IntegerList(length / 2, maximalValue);
-        assertTrue(list.maximalValue() >= maximalValue);
+        assertTrue("maximalValue()", list.maximalValue() >= maximalValue);
         final List<Integer> copy = new ArrayList<>(length);
         for (int i=0; i<length; i++) {
-            assertEquals(i, list.size());
+            assertEquals("size()", i, list.size());
             final Integer value = nextInt(random, maximalValue);
-            assertTrue(copy.add(value));
-            assertTrue(list.add(value));
+            assertTrue("add(Integer)", copy.add(value));
+            assertTrue("add(Integer)", list.add(value));
         }
-        assertEquals(copy, list);
-        assertEquals(copy.hashCode(), list.hashCode());
+        assertEquals("Comparison with reference implementation", copy, list);
+        assertEquals("hashCode()", copy.hashCode(), list.hashCode());
         /*
-         * Overwrite 1/10 of the values.
+         * Overwrite about 1/10 of the values in both the tested IntegerList and the
+         * reference ArrayList. Then compare the IntegerList against the reference.
          */
-        for (int i=0; i<length; i+=10) {
+        for (int i=0; i<length; i += 8 + random.nextInt(5)) {
             final Integer value = nextInt(random, maximalValue);
             final Integer old = copy.set(i, value);
-            assertNotNull(old);
-            assertEquals(old, list.set(i, value));
+            assertNotNull("set(Integer)", old);
+            assertEquals ("set(Integer)", old, list.set(i, value));
         }
         for (int i=0; i<length; i++) {
-            assertEquals(String.valueOf(i), copy.get(i), list.get(i));
+            if (!copy.get(i).equals(list.get(i))) {
+                fail("Mismatched value at index " + i);
+            }
         }
-        assertEquals(copy, list);
-        assertEquals(copy.hashCode(), list.hashCode());
-        assertNotSame(list, assertSerializedEquals(list));
-        /*
-         * Tests cloning and removal of values.
-         */
-        final List<Integer> clone = list.clone();
-        assertEquals(copy, clone);
-        assertEquals(copy.remove(100), clone.remove(100));
-        assertEquals(copy, clone);
+        assertEquals("Comparison with reference implementation", copy, list);
+        assertEquals("hashCode()", copy.hashCode(), list.hashCode());
+        /*
+         * Test the stream, using the ArrayList as a reference implementation. This will indirectly
+         * use the PrimitiveSpliterator.forEachRemaining(Consumer<? super Integer>) method. A more
+         * specific test using forEachRemaining(IntConsumer) is done by the testInts() method.
+         */
+        assertSequentialStreamEquals(copy.iterator(), list.stream());
+        /*
+         * Tests cloning and removal of values in a range of indices. The IntegerList.removeRange(…)
+         * method is invoked indirectly by subList(…).clear(). Again, we use ArrayList as a reference.
+         */
+        final IntegerList clone = list.clone();
+        assertEquals("clone()", copy, clone);
+        assertEquals("remove(int)", copy.remove(100), clone.remove(100));
+        assertEquals("remove(int)", copy, clone);
         copy .subList(128, 256).clear();
         clone.subList(128, 256).clear();
-        assertEquals(copy, clone);
+        assertEquals("After removeRange(…)", copy, clone);
+        /*
+         * Tests iterator on primitive integers, with random removal of some elements during traversal.
+         */
+        final PrimitiveIterator.OfInt it = clone.iterator();
+        final Iterator<Integer> itRef = copy.iterator();
+        while (itRef.hasNext()) {
+            assertTrue("hasNext()", it.hasNext());
+            assertEquals(itRef.next().intValue(), it.nextInt());
+            if (random.nextInt(10) == 0) {
+                itRef.remove();
+                it.remove();
+            }
+        }
+        assertFalse("hasNext()", it.hasNext());
+        assertEquals("After remove()", copy, clone);
+        /*
+         * Verify that serialization and deserialization gives a new list with identical content.
+         */
+        assertNotSame("Serialization", list, assertSerializedEquals(list));
     }
 
     /**
@@ -107,15 +148,14 @@ public final strictfp class IntegerListT
      * already filled with random values prior this method call.
      */
     private void testFill(final int value) {
-        assertEquals(400, list.size());
         final Set<Integer> set = new HashSet<>();
         list.fill(value);
         set.addAll(list);
-        assertEquals(Collections.singleton(value), set);
+        assertEquals("fill(value)", Collections.singleton(value), set);
         list.fill(0);
         set.clear();
         set.addAll(list);
-        assertEquals(Collections.singleton(0), set);
+        assertEquals("fill(0)", Collections.singleton(0), set);
     }
 
     /**
@@ -160,14 +200,13 @@ public final strictfp class IntegerListT
     @Test
     public void test100() {
         testReadWrite(100);
-        assertEquals(400, list.size());
         final int old100 = list.getInt(100);
         list.resize(101);
-        assertEquals(old100, list.getInt(100));
+        assertEquals("getInt(last)", old100, list.getInt(100));
         list.resize(200);
-        assertEquals(200, list.size());
-        assertEquals(old100, list.getInt(100));
-        assertEquals(0, list.getInt(101));
+        assertEquals("size()",              200, list.size());
+        assertEquals("getInt(existing)", old100, list.getInt(100));
+        assertEquals("getInt(new)",           0, list.getInt(101));
         for (int i=101; i<200; i++) {
             assertEquals(0, list.getInt(i));
         }
@@ -192,4 +231,68 @@ public final strictfp class IntegerListT
         testReadWrite(Integer.MAX_VALUE);
         testFill(17);
     }
+
+    /**
+     * Tests that primitive stream traversal is coherent with its list value.
+     * This method tests sequential stream only.
+     */
+    @Test
+    public void testStream() {
+        list = createRandomlyFilled(42, 404);
+        list.stream(false).forEach(new IntConsumer() {
+            private int index = 0;
+
+            @Override
+            public void accept(int value) {
+                assertEquals("Spliterator value differs from its original list", list.getInt(index++), value);
+            }
+        });
+    }
+
+    /**
+     * Tests that primitive stream traversal with parallelization.
+     */
+    @Test
+    public void testIntsParallel() {
+        list = createRandomlyFilled(80, 321);
+        assertParallelStreamEquals(list.iterator(), list.stream().parallel());
+    }
+
+    /**
+     * Ensures our stream is a fail-fast operator, i.e: it fails when the list has
+     * been modified before the end of its iteration.
+     */
+    @Test
+    public void testErrorOnCoModification() {
+        list = createRandomlyFilled(4, 10);
+        final PrimitiveIterator.OfInt values = list.stream(false).iterator();
+
+        // Start iteration normally.
+        assertEquals(list.getInt(0), values.nextInt());
+        assertEquals(list.getInt(1), values.nextInt());
+
+        // Now, if we alter the list and then try to use previously created stream, we should get an error.
+        list.add(0);
+        try {
+            values.next();
+            fail("Concurrent modification has not been detected.");
+        } catch (ConcurrentModificationException expected) {
+            // Expected behavior
+        }
+    }
+
+    /**
+     * Creates a new list whose capacity and value magnitude are defined as input.
+     * The list is filled by a random integer generator before return.
+     *
+     * @param  size      number of elements to insert in the list.
+     * @param  maxValue  maximum value to use for value insertion.
+     * @return a fresh and filled list.
+     */
+    private static IntegerList createRandomlyFilled(final int size, final int maxValue) {
+        final Random random = TestUtilities.createRandomNumberGenerator();
+        return IntStream.generate(() -> random.nextInt(maxValue))
+                .limit(size)
+                .collect(() -> new IntegerList(size, maxValue), IntegerList::addInt, null);
+    }
 }

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/util/logging/WarningListenersTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/util/logging/WarningListenersTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/util/logging/WarningListenersTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/util/logging/WarningListenersTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -110,6 +110,7 @@ public final strictfp class WarningListe
         listeners.warning("The message", null);
         listeners.removeWarningListener(this);
         assertNotNull("Listener has not been notified.", warning);
+        assertEquals(getClass().getName(), warning.getSourceClassName());
         assertEquals("testWarning", warning.getSourceMethodName());
         assertEquals("The message", warning.getMessage());
     }

Modified: sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/xml/OGCNamespacePrefixMapperTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/xml/OGCNamespacePrefixMapperTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/xml/OGCNamespacePrefixMapperTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/test/java/org/apache/sis/xml/OGCNamespacePrefixMapperTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -22,8 +22,8 @@ import org.apache.sis.util.Numbers;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static org.junit.Assume.*;
 import static org.junit.Assert.*;
+import static org.junit.Assume.assumeTrue;
 
 
 /**

Modified: sis/branches/ISO-19115-3/ide-project/NetBeans/build.xml
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/ide-project/NetBeans/build.xml?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/ide-project/NetBeans/build.xml (original)
+++ sis/branches/ISO-19115-3/ide-project/NetBeans/build.xml Sat Dec  9 10:57:44 2017
@@ -62,6 +62,9 @@
         <include name="**/*.utf"/>
       </fileset>
       -->
+      <fileset dir="${project.root}/application/sis-javafx/target/generated-resources">
+        <include name="**/*.utf"/>
+      </fileset>
 
       <!-- Other resources (properties files, SQL scripts, native libraries). -->
       <fileset dir="${project.root}/core/sis-utility/src/main/resources">
@@ -80,6 +83,10 @@
         <include name="**/*.dll"/>
         <include name="**/*.so"/>
       </fileset>
+      <fileset dir="${project.root}/application/sis-javafx/src/main/resources">
+        <include name="**/*.fxml"/>
+        <include name="**/*.png"/>
+      </fileset>
       <fileset dir="${project.root}/application/sis-console/src/main/resources">
         <include name="**/*.properties"/>
       </fileset>
@@ -226,6 +233,10 @@
         <include name="**/*.laa"/>
         <include name="**/*.loa"/>
       </fileset>
+      <fileset dir="${project.root}/storage/sis-storage/src/test/resources">
+        <include name="**/*.txt"/>
+        <include name="**/*.xml"/>
+      </fileset>
       <fileset dir="${project.root}/storage/sis-xmlstore/src/test/resources">
         <include name="**/*.gpx"/>
         <include name="**/*.xml"/>



Mime
View raw message