sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1490027 - in /sis/branches/JDK7: core/sis-utility/src/main/java/org/apache/sis/util/logging/ core/sis-utility/src/test/java/org/apache/sis/test/suite/ core/sis-utility/src/test/java/org/apache/sis/util/logging/ storage/sis-netcdf/src/main/...
Date Wed, 05 Jun 2013 20:55:08 GMT
Author: desruisseaux
Date: Wed Jun  5 20:55:08 2013
New Revision: 1490027

URL: http://svn.apache.org/r1490027
Log:
Replaced the WarningProducer/WarningConsummer pair by a more classical and straightforward WarningListeners list.

Added:
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/WarningListeners.java
      - copied, changed from r1489882, sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/WarningConsumer.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/logging/EmptyWarningListeners.java   (with props)
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/logging/WarningListenersTest.java
      - copied, changed from r1489882, sis/branches/JDK7/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/WarningConsumerTest.java
Removed:
    sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/WarningConsumer.java
    sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/WarningProducer.java
    sis/branches/JDK7/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/WarningConsumerTest.java
Modified:
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/WarningListener.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
    sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java
    sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java
    sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/DecoderWrapper.java
    sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
    sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java
    sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java
    sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/TestCase.java
    sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/ChannelDecoderTest.java
    sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/ConformanceTest.java
    sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java
    sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java
    sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/AbstractDataStore.java
    sis/branches/JDK7/storage/sis-storage/src/test/java/org/apache/sis/test/suite/StorageTestSuite.java

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/WarningListener.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/WarningListener.java?rev=1490027&r1=1490026&r2=1490027&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/WarningListener.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/WarningListener.java [UTF-8] Wed Jun  5 20:55:08 2013
@@ -34,7 +34,7 @@ import java.util.logging.LogRecord;
  * The difference between using this listener or configuring the logging {@link java.util.logging.Handler} is
  * that listeners allow to handle the warnings on a per-{@code DataStore} (or any other emitter) instance.
  *
- * @param <T> The type of the warnings emitter.
+ * @param <S> The type of the source of warnings.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
@@ -43,7 +43,7 @@ import java.util.logging.LogRecord;
  *
  * @see org.apache.sis.storage.DataStore#addWarningListener(WarningListener)
  */
-public interface WarningListener<T> extends EventListener {
+public interface WarningListener<S> extends EventListener {
     /**
      * Reports the occurrence of a non-fatal error. The emitter process (often a
      * {@link org.apache.sis.storage.DataStore} in the midst of a reading process)
@@ -61,5 +61,5 @@ public interface WarningListener<T> exte
      * @param source  The object that emitted a warning.
      * @param warning The warning message together with programmatic information.
      */
-    void warningOccured(T source, LogRecord warning);
+    void warningOccured(S source, LogRecord warning);
 }

Copied: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/WarningListeners.java (from r1489882, sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/WarningConsumer.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/WarningListeners.java?p2=sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/WarningListeners.java&p1=sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/WarningConsumer.java&r1=1489882&r2=1490027&rev=1490027&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/WarningConsumer.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/WarningListeners.java [UTF-8] Wed Jun  5 20:55:08 2013
@@ -14,64 +14,79 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.sis.internal.storage;
+package org.apache.sis.util.logging;
 
 import java.util.Locale;
+import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.logging.LogRecord;
 import java.util.NoSuchElementException;
+import net.jcip.annotations.ThreadSafe;
 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.util.logging.WarningListener;
 
 
 /**
- * The leaf of a chain of {@link WarningProducer}, which hold the list of {@link WarningListener}s to notify.
+ * Holds a list of {@link WarningListener} instances and provides convenience methods for emitting warnings.
+ * The convenience {@code warning(…)} methods can build {@code LogRecord} from an exception or from a string.
  *
- * @param <T> The type of the object declared as warnings emitter.
+ * <p>In the default implementation, all {@code warning(…)} methods delegate to {@link #warning(LogRecord)},
+ * thus providing a single point that subclasses can override for intercepting all warnings.
+ * The default behavior is:</p>
+ *
+ * <ul>
+ *   <li>If at least one {@link WarningListener} is registered,
+ *       then all listeners are notified and the warning is <strong>not</strong> logged.
+ *   <li>Otherwise the warning is logged to the logger returned by {@link #getLogger()}.</li>
+ * </ul>
+ *
+ * @param <S> The type of the source of warnings.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
  * @version 0.3
  * @module
  */
-public final class WarningConsumer<T> extends WarningProducer {
+@ThreadSafe
+public class WarningListeners<S> implements Localized {
     /**
      * The declared source of warnings. This is not necessarily the real source,
-     * but this is the source that we declare in public API.
+     * but this is the source that the implementor wants to declare as public API.
      */
-    private final T source;
+    private final S source;
 
     /**
-     * Where to log the warnings when there is no registered listener.
+     * The listeners, or {@code null} if none. This is a <cite>copy on write</cite> array:
+     * no elements are modified once the array have been created.
      */
-    private final Logger logger;
+    private WarningListener<? super S>[] listeners;
 
     /**
-     * The listeners, or {@code null} if none. This is a <cite>copy on write</cite> array:
-     * no elements are modified once the array have been created.
+     * Creates a new instance without source. This constructor is for {@link #empty(Locale, Logger)}
+     * usage only, because it requires some method to be overloaded.
      */
-    private WarningListener<? super T>[] listeners;
+    WarningListeners() {
+        source = null;
+    }
 
     /**
      * Creates a new instance with initially no listener.
      * Warnings will be logger to the given logger, unless at least one listener is registered.
      *
      * @param source The declared source of warnings. This is not necessarily the real source,
-     *               but this is the source that we declare in public API.
-     * @param logger Where to log the warnings when there is no registered listener.
+     *               but this is the source that the implementor wants to declare as public API.
      */
-    public WarningConsumer(final T source, final Logger logger) {
-        super(null);
+    public WarningListeners(final S source) {
+        ArgumentChecks.ensureNonNull("source", source);
         this.source = source;
-        this.logger = logger;
     }
 
     /**
      * The locale to use for formatting warning messages, or {@code null} for the default locale.
-     * This method returns the {@link #source} locale if it implements the {@link Localized} interface,
-     * or {@code null} otherwise.
+     * 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}.
      */
     @Override
     public Locale getLocale() {
@@ -79,42 +94,85 @@ public final class WarningConsumer<T> ex
     }
 
     /**
-     * Invoked when a new warning has been emitted. This method notifies the listeners if any,
-     * or log the warning otherwise.
+     * Returns the logger where to send the warnings. The default implementation returns a logger for
+     * the package name of the {@code source} object. Subclasses should override this method if they
+     * can provide a fixed logger instance (typically a static final constant).
+     *
+     * @return The logger where to send the warnings when there is no registered listeners.
      */
-    @Override
-    void sendWarning(final LogRecord record) {
+    public Logger getLogger() {
+        return Logging.getLogger(source.getClass());
+    }
+
+    /**
+     * Reports a warning represented by the given log record. The default implementation notifies the listeners
+     * if any, or logs the message to the logger returned by {@link #getLogger()} otherwise.
+     *
+     * @param record The warning as a log record.
+     */
+    public void warning(final LogRecord record) {
         final WarningListener[] current;
         synchronized (this) {
             current = listeners;
         }
         if (current != null) {
-            for (final WarningListener<? super T> listener : listeners) {
+            for (final WarningListener<? super S> listener : listeners) {
                 listener.warningOccured(source, record);
             }
         } else {
+            final Logger logger = getLogger();
             record.setLoggerName(logger.getName());
             logger.log(record);
         }
     }
 
     /**
-     * Adds a listener to be notified when a warning occurred while reading from or writing to the storage.
+     * Reports a warning represented by the given message and exception.
+     * At least one of {@code message} and {@code exception} shall be non-null.
+     *
+     * @param methodName The name of the method in which the warning occurred.
+     * @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(final String methodName, String message, final Exception exception) {
+        if (exception != null) {
+            message = Exceptions.formatChainedMessages(getLocale(), message, exception);
+            if (message == null) {
+                message = exception.toString();
+            }
+        }
+        ArgumentChecks.ensureNonEmpty("message", message);
+        final LogRecord record = new LogRecord(Level.WARNING, message);
+        record.setSourceClassName(getClass().getCanonicalName());
+        record.setSourceMethodName(methodName);
+        warning(record);
+    }
+
+    /**
+     * Adds a listener to be notified when a warning occurred.
+     * When a warning occurs, there is a choice:
+     *
+     * <ul>
+     *   <li>If this object has no warning listener, then the warning is logged at
+     *       {@link java.util.logging.Level#WARNING}.</li>
+     *   <li>If this object has at least one warning listener, then all listeners are notified
+     *       and the warning is <strong>not</strong> logged by this object.</li>
+     * </ul>
      *
      * @param  listener The listener to add.
-     * @throws IllegalArgumentException If the given listener is already registered in this data store.
+     * @throws IllegalArgumentException If the given listener is already registered.
      */
-    public synchronized void addWarningListener(final WarningListener<? super T> listener)
+    public synchronized void addWarningListener(final WarningListener<? super S> listener)
             throws IllegalArgumentException
     {
         ArgumentChecks.ensureNonNull("listener", listener);
-        final WarningListener<? super T>[] current = listeners;
+        final WarningListener<? super S>[] current = listeners;
         final int length = (current != null) ? current.length : 0;
 
         @SuppressWarnings({"unchecked", "rawtypes"}) // Generic array creation.
-        final WarningListener<? super T>[] copy = new WarningListener[length + 1];
+        final WarningListener<? super S>[] copy = new WarningListener[length + 1];
         for (int i=0; i<length; i++) {
-            final WarningListener<? super T> c = current[i];
+            final WarningListener<? super S> c = current[i];
             if (c == listener) {
                 throw new IllegalArgumentException(Errors.format(Errors.Keys.ElementAlreadyPresent_1, listener));
             }
@@ -128,12 +186,13 @@ public final class WarningConsumer<T> ex
      * Removes a previously registered listener.
      *
      * @param  listener The listener to remove.
-     * @throws NoSuchElementException If the given listener is not registered in this data store.
+     * @throws NoSuchElementException If the given listener is not registered.
      */
-    public synchronized void removeWarningListener(final WarningListener<? super T> listener)
+    public synchronized void removeWarningListener(final WarningListener<? super S> listener)
             throws NoSuchElementException
     {
-        final WarningListener<? super T>[] current = listeners;
+        ArgumentChecks.ensureNonNull("listener", listener);
+        final WarningListener<? super S>[] current = listeners;
         if (current != null) {
             for (int i=0; i<current.length; i++) {
                 if (current[i] == listener) {
@@ -141,7 +200,7 @@ public final class WarningConsumer<T> ex
                         listeners = null;
                     } else {
                         @SuppressWarnings({"unchecked", "rawtypes"}) // Generic array creation.
-                        final WarningListener<? super T>[] copy = new WarningListener[current.length - 1];
+                        final WarningListener<? super S>[] copy = new WarningListener[current.length - 1];
                         System.arraycopy(current, 0, copy, 0, i);
                         System.arraycopy(current, i+1, copy, i, copy.length - i);
                         listeners = copy;

Modified: sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java?rev=1490027&r1=1490026&r2=1490027&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java [UTF-8] Wed Jun  5 20:55:08 2013
@@ -48,6 +48,7 @@ import org.junit.BeforeClass;
     org.apache.sis.util.resources.LoaderTest.class,
     org.apache.sis.util.resources.IndexedResourceBundleTest.class,
     org.apache.sis.util.logging.PerformanceLevelTest.class,
+    org.apache.sis.util.logging.WarningListenersTest.class,
     org.apache.sis.math.MathFunctionsTest.class,
     org.apache.sis.math.StatisticsTest.class,
     org.apache.sis.math.StatisticsFormatTest.class,

Added: sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/logging/EmptyWarningListeners.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/logging/EmptyWarningListeners.java?rev=1490027&view=auto
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/logging/EmptyWarningListeners.java (added)
+++ sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/logging/EmptyWarningListeners.java [UTF-8] Wed Jun  5 20:55:08 2013
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.util.logging;
+
+import java.util.Locale;
+import java.util.logging.Logger;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.resources.Errors;
+
+
+/**
+ * A unmodifiable empty list of listeners. Calls to {@link #addWarningListener(WarningListener) addWarningListener(…)}
+ * will throw {@link UnsupportedOperationException}. Since this listener list is empty, it doesn't need a source.
+ *
+ * <p>This class is used in some modules like {@code sis-netcdf}, when a JUnit test is testing some low-level
+ * component where the real {@link WarningListeners} instance is not yet available.</p>
+ *
+ * @param <S> If the listener list had a source, that would be type type of the source.
+ */
+public final strictfp class EmptyWarningListeners<S> extends WarningListeners<S> {
+    /**
+     * The locale to be returned by {@link #getLocale()}. Can be {@code null}.
+     */
+    private final Locale locale;
+
+    /**
+     * The logger to be returned by {@link #getLogger()}.
+     */
+    private final Logger logger;
+
+    /**
+     * Creates a new instance for the given locale and logger.
+     *
+     * @param locale The locale to be returned by {@link #getLocale()}. Can be {@code null}.
+     * @param logger The logger to be returned by {@link #getLogger()}.
+     */
+    public EmptyWarningListeners(final Locale locale, final Logger logger) {
+        ArgumentChecks.ensureNonNull("logger", logger);
+        this.locale = locale;
+        this.logger = logger;
+    }
+
+    /**
+     * Convenience constructor for an instance with null locale and the logger of the given name.
+     *
+     * @param logger The name of the logger to be returned by {@link #getLogger()}.
+     */
+    public EmptyWarningListeners(final String logger) {
+        this(null, Logging.getLogger(logger));
+    }
+
+    /** Returns the value given at construction time. */ @Override public Locale getLocale() {return locale;}
+    /** Returns the value given at construction time. */ @Override public Logger getLogger() {return logger;}
+
+    /** Do not allow registration of warning listeners. */
+    @Override public void addWarningListener(WarningListener<? super S> listener) {
+        throw new UnsupportedOperationException(Errors.format(Errors.Keys.UnmodifiableObject_1, "WarningListeners"));
+    }
+}

Propchange: sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/logging/EmptyWarningListeners.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/logging/EmptyWarningListeners.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Copied: sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/logging/WarningListenersTest.java (from r1489882, sis/branches/JDK7/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/WarningConsumerTest.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/logging/WarningListenersTest.java?p2=sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/logging/WarningListenersTest.java&p1=sis/branches/JDK7/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/WarningConsumerTest.java&r1=1489882&r2=1490027&rev=1490027&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/WarningConsumerTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/logging/WarningListenersTest.java [UTF-8] Wed Jun  5 20:55:08 2013
@@ -14,12 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.sis.internal.storage;
+package org.apache.sis.util.logging;
 
-import java.util.NoSuchElementException;
 import java.util.logging.LogRecord;
-import org.apache.sis.util.logging.Logging;
-import org.apache.sis.util.logging.WarningListener;
+import java.util.NoSuchElementException;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
@@ -28,18 +26,18 @@ import static org.junit.Assert.*;
 
 
 /**
- * Tests the {@link WarningConsumer} class.
+ * Tests the {@link WarningListeners} class.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
  * @version 0.3
  * @module
  */
-public final strictfp class WarningConsumerTest extends TestCase implements WarningListener<String> {
+public final strictfp class WarningListenersTest extends TestCase implements WarningListener<String> {
     /**
      * The object to be tested. Its source will be set to the string {@code "source"}.
      */
-    private final WarningConsumer<String> consumer;
+    private final WarningListeners<String> listeners;
 
     /**
      * The warning received by {@link #warningOccured(String, LogRecord)}.
@@ -50,13 +48,13 @@ public final strictfp class WarningConsu
     /**
      * Creates a new test case.
      */
-    public WarningConsumerTest() {
-        consumer = new WarningConsumer<>("source", Logging.getLogger("org.apache.sis.storage"));
+    public WarningListenersTest() {
+        listeners = new WarningListeners<>("source");
     }
 
     /**
      * Invoked when a warning occurred. The implementation in this test verifies that the {@code source} argument has
-     * the expected values, then store the log record in the {@link #warning} field for inspection by the test method.
+     * the expected values, then stores the log record in the {@link #warning} field for inspection by the test method.
      */
     @Override
     public void warningOccured(final String source, final LogRecord warning) {
@@ -73,21 +71,21 @@ public final strictfp class WarningConsu
     }
 
     /**
-     * Tests {@link WarningProducer#addWarningListener(WarningListener)} followed by
-     * {@link WarningProducer#removeWarningListener(WarningListener)}
+     * Tests {@link WarningListeners#addWarningListener(WarningListener)} followed by
+     * {@link WarningListeners#removeWarningListener(WarningListener)}
      */
     @Test
     public void testAddAndRemoveWarningListener() {
-        consumer.addWarningListener(this);
+        listeners.addWarningListener(this);
         try {
-            consumer.addWarningListener(this);
+            listeners.addWarningListener(this);
         } catch (IllegalArgumentException e) {
             // This is the expected exception.
             assertTrue(e.getMessage().contains("TestListener"));
         }
-        consumer.removeWarningListener(this);
+        listeners.removeWarningListener(this);
         try {
-            consumer.removeWarningListener(this);
+            listeners.removeWarningListener(this);
         } catch (NoSuchElementException e) {
             // This is the expected exception.
             assertTrue(e.getMessage().contains("TestListener"));
@@ -95,14 +93,14 @@ public final strictfp class WarningConsu
     }
 
     /**
-     * Tests {@link WarningProducer#warning(String, String, Exception)} with a registered listener.
+     * Tests {@link WarningListeners#warning(String, String, Exception)} with a registered listener.
      */
     @Test
     @DependsOnMethod("testAddAndRemoveWarningListener")
     public void testWarning() {
-        consumer.addWarningListener(this);
-        consumer.warning("testWarning", "The message", null);
-        consumer.removeWarningListener(this);
+        listeners.addWarningListener(this);
+        listeners.warning("testWarning", "The message", null);
+        listeners.removeWarningListener(this);
         assertNotNull("Listener has not been notified.", warning);
         assertEquals("testWarning", warning.getSourceMethodName());
         assertEquals("The message", warning.getMessage());

Modified: sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java?rev=1490027&r1=1490026&r2=1490027&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java [UTF-8] (original)
+++ sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java [UTF-8] Wed Jun  5 20:55:08 2013
@@ -21,7 +21,10 @@ import java.io.Closeable;
 import java.io.IOException;
 import javax.measure.unit.Unit;
 import org.apache.sis.measure.Units;
-import org.apache.sis.internal.storage.WarningProducer;
+import org.apache.sis.util.logging.WarningListeners;
+
+// Related to JDK7.
+import java.util.Objects;
 
 
 /**
@@ -32,7 +35,12 @@ import org.apache.sis.internal.storage.W
  * @version 0.3
  * @module
  */
-public abstract class Decoder extends WarningProducer implements Closeable {
+public abstract class Decoder implements Closeable {
+    /**
+     * Where to send the warnings.
+     */
+    public final WarningListeners<?> listeners;
+
     /**
      * Sets to {@code true} for canceling a reading process.
      * This flag is honored on a <cite>best effort</cite> basis only.
@@ -42,10 +50,11 @@ public abstract class Decoder extends Wa
     /**
      * Creates a new decoder.
      *
-     * @param sink Where to send the warnings, or {@code null} if none.
+     * @param listeners Where to send the warnings.
      */
-    protected Decoder(final WarningProducer sink) {
-        super(sink);
+    protected Decoder(final WarningListeners<?> listeners) {
+        Objects.requireNonNull(listeners);
+        this.listeners = listeners;
     }
 
     /**
@@ -103,7 +112,7 @@ public abstract class Decoder extends Wa
         try {
             return Double.valueOf(value);
         } catch (NumberFormatException e) {
-            warning("numericValue", null, e);
+            listeners.warning("numericValue", null, e);
         }
         return null;
     }
@@ -133,7 +142,7 @@ public abstract class Decoder extends Wa
         if (unit != null) try {
             return Units.valueOf(unit);
         } catch (IllegalArgumentException e) {
-            warning("unitValue", null, e);
+            listeners.warning("unitValue", null, e);
         }
         return null;
     }

Modified: sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java?rev=1490027&r1=1490026&r2=1490027&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java [UTF-8] (original)
+++ sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java [UTF-8] Wed Jun  5 20:55:08 2013
@@ -37,7 +37,6 @@ import org.apache.sis.internal.jdk8.Func
 import org.apache.sis.internal.netcdf.Decoder;
 import org.apache.sis.internal.netcdf.Variable;
 import org.apache.sis.internal.netcdf.GridGeometry;
-import org.apache.sis.internal.storage.WarningProducer;
 import org.apache.sis.internal.storage.ChannelDataInput;
 import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.internal.jdk8.JDK8;
@@ -45,6 +44,7 @@ import org.apache.sis.storage.DataStoreE
 import org.apache.sis.util.iso.DefaultNameSpace;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.resources.Vocabulary;
+import org.apache.sis.util.logging.WarningListeners;
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.measure.Units;
 
@@ -184,15 +184,15 @@ public final class ChannelDecoder extend
      * Creates a new decoder for the given file.
      * This constructor parses immediately the header.
      *
-     * @param  sink     Where to send the warnings, or {@code null} if none.
-     * @param  input    The channel and the buffer from where data are read.
+     * @param  listeners Where to send the warnings.
+     * @param  input     The channel and the buffer from where data are read.
      * @throws IOException If an error occurred while reading the channel.
      * @throws DataStoreException If the content of the given channel is not a NetCDF file.
      */
-    public ChannelDecoder(final WarningProducer sink, final ChannelDataInput input)
+    public ChannelDecoder(final WarningListeners<?> listeners, final ChannelDataInput input)
             throws IOException, DataStoreException
     {
-        super(sink);
+        super(listeners);
         this.input = input;
         /*
          * Check the magic number, which is expected to be exactly 3 bytes forming the "CDF" string.
@@ -256,6 +256,15 @@ public final class ChannelDecoder extend
     }
 
     /**
+     * Returns the localized error resource bundle for the locale given by {@link #getLocale()}.
+     *
+     * @return The localized error resource bundle.
+     */
+    private Errors errors() {
+        return Errors.getResources(listeners.getLocale());
+    }
+
+    /**
      * Returns an exception for a malformed header. This is used only after we have determined
      * that the file should be a NetCDF one, but we found some inconsistency or unknown tags.
      */
@@ -611,7 +620,7 @@ public final class ChannelDecoder extend
             if (attribute.value instanceof String) try {
                 return JDK8.parseDateTime((String) attribute.value, DEFAULT_TIMEZONE_IS_UTC);
             } catch (IllegalArgumentException e) {
-                warning("dateValue", null, e);
+                listeners.warning("dateValue", null, e);
             }
         }
         return null;
@@ -638,7 +647,7 @@ public final class ChannelDecoder extend
                 }
             }
         } catch (ConversionException | IllegalArgumentException e) {
-            warning("numberToDate", null, e);
+            listeners.warning("numberToDate", null, e);
         }
         return dates;
     }

Modified: sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/DecoderWrapper.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/DecoderWrapper.java?rev=1490027&r1=1490026&r2=1490027&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/DecoderWrapper.java [UTF-8] (original)
+++ sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/DecoderWrapper.java [UTF-8] Wed Jun  5 20:55:08 2013
@@ -33,10 +33,10 @@ import ucar.nc2.time.Calendar;
 import ucar.nc2.time.CalendarDate;
 import ucar.nc2.time.CalendarDateFormatter;
 import org.apache.sis.util.ArraysExt;
+import org.apache.sis.util.logging.WarningListeners;
 import org.apache.sis.internal.netcdf.Decoder;
 import org.apache.sis.internal.netcdf.Variable;
 import org.apache.sis.internal.netcdf.GridGeometry;
-import org.apache.sis.internal.storage.WarningProducer;
 
 
 /**
@@ -86,23 +86,23 @@ public final class DecoderWrapper extend
      * {@link NetcdfFile} instance, the {@link NetcdfDataset} subclass is necessary in order to
      * get coordinate system information.
      *
-     * @param sink Where to send the warnings, or {@code null} if none.
+     * @param listeners Where to send the warnings.
      * @param file The NetCDF file from which to read data.
      */
-    public DecoderWrapper(final WarningProducer sink, final NetcdfFile file) {
-        super(sink);
+    public DecoderWrapper(final WarningListeners<?> listeners, final NetcdfFile file) {
+        super(listeners);
         this.file = file;
     }
 
     /**
      * Creates a new decoder for the given filename.
      *
-     * @param  sink     Where to send the warnings, or {@code null} if none.
-     * @param  filename The name of the NetCDF file from which to read data.
+     * @param  listeners Where to send the warnings.
+     * @param  filename  The name of the NetCDF file from which to read data.
      * @throws IOException If an error occurred while opening the NetCDF file.
      */
-    public DecoderWrapper(final WarningProducer sink, final String filename) throws IOException {
-        super(sink);
+    public DecoderWrapper(final WarningListeners<?> listeners, final String filename) throws IOException {
+        super(listeners);
         file = NetcdfDataset.openDataset(filename, false, this);
     }
 
@@ -229,7 +229,7 @@ public final class DecoderWrapper extend
                         try {
                             date = CalendarDateFormatter.isoStringToCalendarDate(Calendar.proleptic_gregorian, value);
                         } catch (IllegalArgumentException e) {
-                            warning("dateValue", null, e);
+                            listeners.warning("dateValue", null, e);
                             continue;
                         }
                         return new Date(date.getMillis());
@@ -254,7 +254,7 @@ public final class DecoderWrapper extend
         try {
             unit = new DateUnit(symbol);
         } catch (Exception e) { // Declared by the DateUnit constructor.
-            warning("numberToDate", null, e);
+            listeners.warning("numberToDate", null, e);
             return dates;
         }
         for (int i=0; i<values.length; i++) {
@@ -341,7 +341,7 @@ public final class DecoderWrapper extend
      */
     @Override
     public void setError(final String message) {
-        warning(null, message, null);
+        listeners.warning(null, message, null);
     }
 
     /**

Modified: sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java?rev=1490027&r1=1490026&r2=1490027&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java [UTF-8] (original)
+++ sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java [UTF-8] Wed Jun  5 20:55:08 2013
@@ -64,7 +64,6 @@ import org.apache.sis.internal.netcdf.Ax
 import org.apache.sis.internal.netcdf.Decoder;
 import org.apache.sis.internal.netcdf.Variable;
 import org.apache.sis.internal.netcdf.GridGeometry;
-import org.apache.sis.internal.storage.WarningProducer;
 import org.apache.sis.internal.util.DefaultFactories;
 import org.apache.sis.internal.metadata.MetadataUtilities;
 
@@ -105,7 +104,7 @@ import static org.apache.sis.storage.net
  * @version 0.3
  * @module
  */
-final class MetadataReader extends WarningProducer {
+final class MetadataReader {
     /**
      * Names of groups where to search for metadata, in precedence order.
      * The {@code null} value stands for global attributes.
@@ -173,7 +172,6 @@ final class MetadataReader extends Warni
      * @throws IOException If an I/O operation was necessary but failed.
      */
     MetadataReader(final Decoder decoder) throws IOException {
-        super(decoder.sink);
         this.decoder = decoder;
         decoder.setSearchPath(SEARCH_PATH);
         searchPath = decoder.getSearchPath();
@@ -272,7 +270,7 @@ final class MetadataReader extends Warni
             resource.setFunction(OnLineFunction.INFORMATION);
             return resource;
         } catch (URISyntaxException e) {
-            warning("createOnlineResource", null, e);
+            decoder.listeners.warning("createOnlineResource", null, e);
         }
         return null;
     }
@@ -677,7 +675,7 @@ final class MetadataReader extends Warni
             }
             extent.getTemporalElements().add(t);
         } catch (UnsupportedOperationException e) {
-            warning("createExtent", null, e);
+            decoder.listeners.warning("createExtent", null, e);
         }
         /*
          * Add the geographic identifier, if present.
@@ -700,7 +698,7 @@ final class MetadataReader extends Warni
         if (source != null) try {
             return source.getConverterToAny(target);
         } catch (ConversionException e) {
-            warning("getConverterTo", null, e);
+            decoder.listeners.warning("getConverterTo", null, e);
         }
         return null;
     }

Modified: sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java?rev=1490027&r1=1490026&r2=1490027&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java [UTF-8] (original)
+++ sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java [UTF-8] Wed Jun  5 20:55:08 2013
@@ -59,7 +59,7 @@ public class NetcdfStore extends Abstrac
     public NetcdfStore(final DataStoreConnection storage) throws DataStoreException {
         ArgumentChecks.ensureNonNull("storage", storage);
         try {
-            decoder = NetcdfStoreProvider.decoder(null, storage);
+            decoder = NetcdfStoreProvider.decoder(listeners, storage);
         } catch (IOException e) {
             throw new DataStoreException(e);
         }

Modified: sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java?rev=1490027&r1=1490026&r2=1490027&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java [UTF-8] (original)
+++ sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java [UTF-8] Wed Jun  5 20:55:08 2013
@@ -26,11 +26,11 @@ import org.apache.sis.internal.netcdf.De
 import org.apache.sis.internal.netcdf.impl.ChannelDecoder;
 import org.apache.sis.internal.netcdf.ucar.DecoderWrapper;
 import org.apache.sis.internal.storage.ChannelDataInput;
-import org.apache.sis.internal.storage.WarningProducer;
 import org.apache.sis.storage.DataStore;
 import org.apache.sis.storage.DataStoreProvider;
 import org.apache.sis.storage.DataStoreConnection;
 import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.util.logging.WarningListeners;
 
 
 /**
@@ -156,25 +156,25 @@ public class NetcdfStoreProvider extends
      * Creates a decoder for the given input. This method invokes
      * {@link DataStoreConnection#closeAllExcept(Object)} after the decoder has been created.
      *
-     * @param  sink    Where to send the warnings, or {@code null} if none.
+     * @param  listeners Where to send the warnings.
      * @param  storage Information about the input (file, input stream, <i>etc.</i>)
      * @return The decoder for the given input.
      * @throws IOException If an error occurred while opening the NetCDF file.
      * @throws DataStoreException If a logical error (other than I/O) occurred.
      */
-    static Decoder decoder(final WarningProducer sink, final DataStoreConnection storage)
+    static Decoder decoder(final WarningListeners<?> listeners, final DataStoreConnection storage)
             throws IOException, DataStoreException
     {
         Decoder decoder;
         Object keepOpen;
         final ChannelDataInput input = storage.getStorageAs(ChannelDataInput.class);
         if (input != null) try {
-            decoder = new ChannelDecoder(sink, input);
+            decoder = new ChannelDecoder(listeners, input);
             keepOpen = input;
         } catch (DataStoreException e) {
             final String path = storage.getStorageAs(String.class);
             if (path != null) try {
-                decoder = createByReflection(sink, path, false);
+                decoder = createByReflection(listeners, path, false);
                 keepOpen = path;
             } catch (IOException | DataStoreException s) {
                 e.addSuppressed(s);
@@ -182,7 +182,7 @@ public class NetcdfStoreProvider extends
             throw e;
         } else {
             keepOpen = storage.getStorage();
-            decoder = createByReflection(sink, keepOpen, true);
+            decoder = createByReflection(listeners, keepOpen, true);
         }
         storage.closeAllExcept(keepOpen);
         return decoder;
@@ -193,7 +193,7 @@ public class NetcdfStoreProvider extends
      * not create our embedded NetCDF decoder. This method uses reflection for creating the wrapper, in order
      * to keep the UCAR dependency optional.
      *
-     * @param  sink   Where to send the warnings, or {@code null} if none.
+     * @param  listeners Where to send the warnings.
      * @param  input  The NetCDF file object of filename string from which to read data.
      * @param  isUCAR {@code true} if {@code input} is an instance of the UCAR {@link ucar.nc2.NetcdfFile} object,
      *                or {@code false} if it is the filename as a {@code String}.
@@ -201,7 +201,7 @@ public class NetcdfStoreProvider extends
      * @throws IOException If an error occurred while opening the NetCDF file.
      * @throws DataStoreException If a logical error (other than I/O) occurred.
      */
-    private static Decoder createByReflection(final WarningProducer sink, final Object input, final boolean isUCAR)
+    private static Decoder createByReflection(final WarningListeners<?> listeners, final Object input, final boolean isUCAR)
             throws IOException, DataStoreException
     {
         ensureInitialized();
@@ -222,7 +222,7 @@ public class NetcdfStoreProvider extends
             return null;
         }
         try {
-            return constructor.newInstance(sink, input);
+            return constructor.newInstance(listeners, input);
         } catch (InvocationTargetException e) {
             final Throwable cause = e.getCause();
             if (cause instanceof IOException)        throw (IOException)        cause;
@@ -260,7 +260,7 @@ public class NetcdfStoreProvider extends
                  */
                 final Class<? extends Decoder> wrapper =
                         Class.forName("org.apache.sis.internal.netcdf.ucar.DecoderWrapper").asSubclass(Decoder.class);
-                final Class<?>[] parameterTypes = new Class<?>[] {WarningProducer.class, netcdfFileClass};
+                final Class<?>[] parameterTypes = new Class<?>[] {WarningListeners.class, netcdfFileClass};
                 createFromUCAR = wrapper.getConstructor(parameterTypes);
                 parameterTypes[1] = String.class;
                 createFromPath = wrapper.getConstructor(parameterTypes);

Modified: sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/TestCase.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/TestCase.java?rev=1490027&r1=1490026&r2=1490027&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/TestCase.java [UTF-8] (original)
+++ sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/TestCase.java [UTF-8] Wed Jun  5 20:55:08 2013
@@ -22,6 +22,7 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.io.IOException;
 import java.lang.reflect.UndeclaredThrowableException;
+import org.apache.sis.util.logging.EmptyWarningListeners;
 import org.apache.sis.internal.netcdf.ucar.DecoderWrapper;
 import org.opengis.wrapper.netcdf.IOTestCase;
 import ucar.nc2.dataset.NetcdfDataset;
@@ -42,6 +43,12 @@ import static org.junit.Assert.*;
  */
 public abstract strictfp class TestCase extends IOTestCase {
     /**
+     * A dummy list of listeners which can be given to the {@link Decoder} constructor.
+     */
+    public static EmptyWarningListeners<Decoder> LISTENERS =
+            new EmptyWarningListeners<>("org.apache.sis.storage.netcdf");
+
+    /**
      * The {@code searchPath} argument value to be given to the {@link Decoder#setSearchPath(String[])}
      * method when the decoder shall search only in global attributes.
      */
@@ -98,7 +105,7 @@ public abstract strictfp class TestCase 
      * @throws IOException If an error occurred while opening the file.
      */
     protected Decoder createDecoder(final String name) throws IOException {
-        return new DecoderWrapper(null, new NetcdfDataset(open(name)));
+        return new DecoderWrapper(LISTENERS, new NetcdfDataset(open(name)));
     }
 
     /**

Modified: sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/ChannelDecoderTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/ChannelDecoderTest.java?rev=1490027&r1=1490026&r2=1490027&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/ChannelDecoderTest.java [UTF-8] (original)
+++ sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/ChannelDecoderTest.java [UTF-8] Wed Jun  5 20:55:08 2013
@@ -71,7 +71,7 @@ public final strictfp class ChannelDecod
         final ChannelDataInput input = new ChannelDataInput(name,
                 Channels.newChannel(in), ByteBuffer.allocate(4096), false);
         try {
-            return new ChannelDecoder(null, input);
+            return new ChannelDecoder(LISTENERS, input);
         } catch (DataStoreException e) {
             throw new AssertionError(e);
         }

Modified: sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/ConformanceTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/ConformanceTest.java?rev=1490027&r1=1490026&r2=1490027&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/ConformanceTest.java [UTF-8] (original)
+++ sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/ConformanceTest.java [UTF-8] Wed Jun  5 20:55:08 2013
@@ -29,6 +29,7 @@ import org.opengis.metadata.maintenance.
 import org.opengis.wrapper.netcdf.NetcdfMetadataTest;
 import org.apache.sis.internal.netcdf.Decoder;
 import org.apache.sis.internal.netcdf.ucar.DecoderWrapper;
+import org.apache.sis.internal.netcdf.TestCase;
 import org.apache.sis.test.DependsOn;
 import org.junit.Test;
 
@@ -65,7 +66,7 @@ public final strictfp class ConformanceT
      */
     @Override
     protected Metadata wrap(final NetcdfFile file) throws IOException {
-        final Decoder decoder = new DecoderWrapper(null, file);
+        final Decoder decoder = new DecoderWrapper(TestCase.LISTENERS, file);
         final MetadataReader ncISO = new MetadataReader(decoder);
         return ncISO.read();
         // Do not close the file, as this will be done by the parent test class.

Modified: sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java?rev=1490027&r1=1490026&r2=1490027&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java [UTF-8] (original)
+++ sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java [UTF-8] Wed Jun  5 20:55:08 2013
@@ -20,6 +20,7 @@ import java.io.IOException;
 import ucar.nc2.dataset.NetcdfDataset;
 import org.opengis.metadata.Metadata;
 import org.opengis.wrapper.netcdf.IOTestCase;
+import org.apache.sis.internal.netcdf.TestCase;
 import org.apache.sis.internal.netcdf.Decoder;
 import org.apache.sis.internal.netcdf.ucar.DecoderWrapper;
 import org.apache.sis.internal.netcdf.impl.ChannelDecoderTest;
@@ -67,7 +68,7 @@ public final strictfp class MetadataRead
     @Test
     public void testUCAR() throws IOException {
         final Metadata metadata;
-        try (Decoder input = new DecoderWrapper(null, new NetcdfDataset(open(NCEP)))) {
+        try (Decoder input = new DecoderWrapper(TestCase.LISTENERS, new NetcdfDataset(open(NCEP)))) {
             metadata = new MetadataReader(input).read();
         }
         compareToExpected(metadata);

Modified: sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java?rev=1490027&r1=1490026&r2=1490027&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java [UTF-8] (original)
+++ sis/branches/JDK7/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java [UTF-8] Wed Jun  5 20:55:08 2013
@@ -19,6 +19,7 @@ package org.apache.sis.storage.netcdf;
 import java.io.IOException;
 import ucar.nc2.NetcdfFile;
 import org.opengis.wrapper.netcdf.IOTestCase;
+import org.apache.sis.internal.netcdf.TestCase;
 import org.apache.sis.internal.netcdf.Decoder;
 import org.apache.sis.internal.netcdf.ucar.DecoderWrapper;
 import org.apache.sis.internal.netcdf.impl.ChannelDecoder;
@@ -73,7 +74,7 @@ public final strictfp class NetcdfStoreP
     }
 
     /**
-     * Tests {@link NetcdfStoreProvider#decoder(WarningProducer, DataStoreConnection)} for an input stream which
+     * Tests {@link NetcdfStoreProvider#decoder(WarningListeners, DataStoreConnection)} for an input stream which
      * shall be recognized as a classic NetCDF file. The provider shall instantiate a {@link ChannelDecoder}.
      *
      * @throws IOException If an error occurred while opening the NetCDF file.
@@ -82,13 +83,13 @@ public final strictfp class NetcdfStoreP
     @Test
     public void testDecoderFromStream() throws IOException, DataStoreException {
         final DataStoreConnection c = new DataStoreConnection(IOTestCase.class.getResourceAsStream(NCEP));
-        final Decoder decoder = NetcdfStoreProvider.decoder(null, c);
+        final Decoder decoder = NetcdfStoreProvider.decoder(TestCase.LISTENERS, c);
         assertInstanceOf(NCEP, ChannelDecoder.class, decoder);
         decoder.close();
     }
 
     /**
-     * Tests {@link NetcdfStoreProvider#decoder(WarningProducer, DataStoreConnection)} for a UCAR
+     * Tests {@link NetcdfStoreProvider#decoder(WarningListeners, DataStoreConnection)} for a UCAR
      * {@link NetcdfFile} object. The provider shall instantiate a {@link DecoderWrapper}.
      *
      * @throws IOException If an error occurred while opening the NetCDF file.
@@ -97,7 +98,7 @@ public final strictfp class NetcdfStoreP
     @Test
     public void testDecoderFromUCAR() throws IOException, DataStoreException {
         final DataStoreConnection c = new DataStoreConnection(open(NCEP));
-        final Decoder decoder = NetcdfStoreProvider.decoder(null, c);
+        final Decoder decoder = NetcdfStoreProvider.decoder(TestCase.LISTENERS, c);
         assertInstanceOf(NCEP, DecoderWrapper.class, decoder);
         decoder.close();
     }

Modified: sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/AbstractDataStore.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/AbstractDataStore.java?rev=1490027&r1=1490026&r2=1490027&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/AbstractDataStore.java [UTF-8] (original)
+++ sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/AbstractDataStore.java [UTF-8] Wed Jun  5 20:55:08 2013
@@ -17,14 +17,11 @@
 package org.apache.sis.storage;
 
 import java.util.Locale;
-import java.util.logging.Logger;
-import java.util.logging.LogRecord;
 import java.util.NoSuchElementException;
 import org.apache.sis.util.Localized;
 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.logging.WarningListener;
+import org.apache.sis.util.logging.WarningListeners;
 
 
 /**
@@ -45,16 +42,16 @@ public abstract class AbstractDataStore 
     private Locale locale;
 
     /**
-     * The listeners, or {@code null} if none. This is a <cite>copy on write</cite> array:
-     * no elements are modified once the array have been created.
+     * The set of registered {@link WarningListener}s for this data store.
      */
-    private WarningListener<? super DataStore>[] listeners;
+    protected final WarningListeners<DataStore> listeners;
 
     /**
      * Creates a new instance with initially no listener.
      */
-    public AbstractDataStore() {
+    protected AbstractDataStore() {
         locale = Locale.getDefault(Locale.Category.DISPLAY);
+        listeners = new WarningListeners<DataStore>(this);
     }
 
     /**
@@ -85,24 +82,10 @@ public abstract class AbstractDataStore 
      * @throws IllegalArgumentException If the given listener is already registered in this data store.
      */
     @Override
-    public synchronized void addWarningListener(final WarningListener<? super DataStore> listener)
+    public void addWarningListener(final WarningListener<? super DataStore> listener)
             throws IllegalArgumentException
     {
-        ArgumentChecks.ensureNonNull("listener", listener);
-        final WarningListener<? super DataStore>[] current = listeners;
-        final int length = (current != null) ? current.length : 0;
-
-        @SuppressWarnings({"unchecked", "rawtypes"}) // Generic array creation.
-        final WarningListener<? super DataStore>[] copy = new WarningListener[length + 1];
-        for (int i=0; i<length; i++) {
-            final WarningListener<? super DataStore> c = current[i];
-            if (c == listener) {
-                throw new IllegalArgumentException(Errors.format(Errors.Keys.ElementAlreadyPresent_1, listener));
-            }
-            copy[i] = c;
-        }
-        copy[length] = listener;
-        listeners = copy;
+        listeners.addWarningListener(listener);
     }
 
     /**
@@ -112,69 +95,9 @@ public abstract class AbstractDataStore 
      * @throws NoSuchElementException If the given listener is not registered in this data store.
      */
     @Override
-    public synchronized void removeWarningListener(final WarningListener<? super DataStore> listener)
+    public void removeWarningListener(final WarningListener<? super DataStore> listener)
             throws NoSuchElementException
     {
-        final WarningListener<? super DataStore>[] current = listeners;
-        if (current != null) {
-            for (int i=0; i<current.length; i++) {
-                if (current[i] == listener) {
-                    if (current.length == 1) {
-                        listeners = null;
-                    } else {
-                        @SuppressWarnings({"unchecked", "rawtypes"}) // Generic array creation.
-                        final WarningListener<? super DataStore>[] copy = new WarningListener[current.length - 1];
-                        System.arraycopy(current, 0, copy, 0, i);
-                        System.arraycopy(current, i+1, copy, i, copy.length - i);
-                        listeners = copy;
-                    }
-                    return;
-                }
-            }
-        }
-        throw new NoSuchElementException(Errors.format(Errors.Keys.NoSuchElement_1, listener));
-    }
-
-    /**
-     * Invoked when a new warning has been emitted.
-     * The default implementation makes the following choice:
-     *
-     * <ul>
-     *   <li>If at least one warning listener has been {@linkplain #addWarningListener(WarningListener) registered},
-     *       then this method notifies all listeners and the log record is <strong>not</strong> logged.</li>
-     *   <li>Otherwise this method logs the given record to the logger returned by {@link #getLogger()}</li>
-     * </ul>
-     *
-     * @param warning The warning message together with programmatic information.
-     *
-     * @see WarningListener#warningOccured(Object, LogRecord)
-     */
-    protected void fireWarningOccurred(final LogRecord warning) {
-        final WarningListener[] current;
-        synchronized (this) {
-            current = listeners;
-        }
-        if (current != null) {
-            for (final WarningListener<? super DataStore> listener : listeners) {
-                listener.warningOccured(this, warning);
-            }
-        } else {
-            final Logger logger = getLogger();
-            warning.setLoggerName(logger.getName());
-            logger.log(warning);
-        }
-    }
-
-    /**
-     * Returns the logger where to send warnings when there is registered warning listeners.
-     * This logger may also be used for other purpose like configuration or debugging information.
-     *
-     * <p>The default implementation returns the {@code "org.apache.sis.storage"} logger.
-     * Subclasses should override for specifying a logger in their own namespace.</p>
-     *
-     * @return The logger where to send warnings and other messages produced by this data store.
-     */
-    protected Logger getLogger() {
-        return Logging.getLogger(DataStore.class);
+        listeners.removeWarningListener(listener);
     }
 }

Modified: sis/branches/JDK7/storage/sis-storage/src/test/java/org/apache/sis/test/suite/StorageTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-storage/src/test/java/org/apache/sis/test/suite/StorageTestSuite.java?rev=1490027&r1=1490026&r2=1490027&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-storage/src/test/java/org/apache/sis/test/suite/StorageTestSuite.java [UTF-8] (original)
+++ sis/branches/JDK7/storage/sis-storage/src/test/java/org/apache/sis/test/suite/StorageTestSuite.java [UTF-8] Wed Jun  5 20:55:08 2013
@@ -30,7 +30,6 @@ import org.junit.BeforeClass;
  * @module
  */
 @Suite.SuiteClasses({
-    org.apache.sis.internal.storage.WarningConsumerTest.class,
     org.apache.sis.internal.storage.IOUtilitiesTest.class,
     org.apache.sis.internal.storage.ChannelDataInputTest.class,
     org.apache.sis.internal.storage.ChannelImageInputStreamTest.class,



Mime
View raw message