This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new 7eee5e5401 Test warning by registering a listener instead of watching
the logger.
7eee5e5401 is described below
commit 7eee5e5401d1ed74ddcf66043b230632917c990f
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Thu Sep 3 18:02:37 2026 +0900
Test warning by registering a listener instead of watching the logger.
---
.../sis/storage/landsat/LandsatStoreProvider.java | 2 +-
.../storage/landsat/LandsatStoreProviderTest.java | 40 ++++++++---
.../org/apache/sis/storage/event/WarningEvent.java | 18 ++++-
.../org/apache/sis/storage/event/package-info.java | 4 +-
.../sis/util/internal/AutoMessageFormat.java | 22 ++++--
.../apache/sis/util/internal/shared/Strings.java | 78 ++++++++++++++++++++++
.../apache/sis/util/logging/MonolineFormatter.java | 44 +-----------
.../sis/util/resources/IndexedResourceBundle.java | 18 +----
8 files changed, 146 insertions(+), 80 deletions(-)
diff --git
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/LandsatStoreProvider.java
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/LandsatStoreProvider.java
index 00293599ed..8fa79319a9 100644
---
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/LandsatStoreProvider.java
+++
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/LandsatStoreProvider.java
@@ -59,7 +59,7 @@ public class LandsatStoreProvider extends DataStoreProvider {
*
* @see #getLogger()
*/
- static final Logger LOGGER =
Logger.getLogger("org.apache.sis.storage.landsat");
+ private static final Logger LOGGER =
Logger.getLogger("org.apache.sis.storage.landsat");
/**
* The parameter descriptor to be returned by {@link #getOpenParameters()}.
diff --git
a/endorsed/src/org.apache.sis.storage.earthobservation/test/org/apache/sis/storage/landsat/LandsatStoreProviderTest.java
b/endorsed/src/org.apache.sis.storage.earthobservation/test/org/apache/sis/storage/landsat/LandsatStoreProviderTest.java
index d976dfac47..9932219678 100644
---
a/endorsed/src/org.apache.sis.storage.earthobservation/test/org/apache/sis/storage/landsat/LandsatStoreProviderTest.java
+++
b/endorsed/src/org.apache.sis.storage.earthobservation/test/org/apache/sis/storage/landsat/LandsatStoreProviderTest.java
@@ -29,13 +29,15 @@ import org.apache.sis.storage.OptionKey;
import org.apache.sis.storage.ProbeResult;
import org.apache.sis.storage.StorageConnector;
import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.event.StoreListener;
+import org.apache.sis.storage.event.WarningEvent;
// Test dependencies
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import static org.junit.jupiter.api.Assertions.*;
import static org.apache.sis.test.Assertions.assertSingleton;
-import org.apache.sis.test.TestCaseWithLogs;
+import org.apache.sis.test.TestCase;
/**
@@ -44,12 +46,16 @@ import org.apache.sis.test.TestCaseWithLogs;
* @author Martin Desruisseaux (Geomatys)
*/
@SuppressWarnings("exports")
-public final class LandsatStoreProviderTest extends TestCaseWithLogs {
+public final class LandsatStoreProviderTest extends TestCase implements
StoreListener<WarningEvent> {
+ /**
+ * Whether a warning is expected.
+ */
+ private boolean isWarningExpected;
+
/**
* Creates a new test case.
*/
public LandsatStoreProviderTest() {
- super(LandsatStoreProvider.LOGGER);
}
/**
@@ -63,7 +69,6 @@ public final class LandsatStoreProviderTest extends
TestCaseWithLogs {
connector.setOption(OptionKey.ENCODING, StandardCharsets.UTF_8);
final var provider = new LandsatStoreProvider();
assertEquals(ProbeResult.SUPPORTED, provider.probeContent(connector));
- loggings.assertNoUnexpectedLog();
}
/**
@@ -77,7 +82,7 @@ public final class LandsatStoreProviderTest extends
TestCaseWithLogs {
* @throws IOException if an error occurred while writing the temporary
file.
* @throws DataStoreException if an error occurred while reading the
temporary file.
*/
- private static Collection<Path> readSingleBand(final Path tmpDir, final
String sceneName, final String tiffFile)
+ private Collection<Path> readSingleBand(final Path tmpDir, final String
sceneName, final String tiffFile)
throws IOException, DataStoreException
{
final Path sceneDir =
Files.createDirectories(tmpDir.resolve(sceneName));
@@ -92,6 +97,7 @@ public final class LandsatStoreProviderTest extends
TestCaseWithLogs {
final var paths = new ArrayList<Path>();
try (var store = new LandsatStore(null, new
StorageConnector(sceneDir))) {
+ store.addListener(WarningEvent.class, this);
for (Resource component : store.components()) {
Aggregate group = assertInstanceOf(Aggregate.class, component);
Resource band = assertSingleton(group.components());
@@ -109,15 +115,27 @@ public final class LandsatStoreProviderTest extends
TestCaseWithLogs {
* @throws DataStoreException if an error occurred while reading the
temporary file.
*/
@Test
- public void testBandPathValidation(@TempDir final Path tmpDir)
- throws IOException, DataStoreException
- {
+ public void testBandPathValidation(@TempDir final Path tmpDir) throws
IOException, DataStoreException {
final Path expected = tmpDir.resolve("valid", "B1.TIFF");
final Path actual = assertSingleton(readSingleBand(tmpDir, "valid",
"B1.TIFF"));
assertEquals(expected.toAbsolutePath(), actual.toAbsolutePath());
- loggings.assertNoUnexpectedLog();
+ isWarningExpected = true;
assertTrue(readSingleBand(tmpDir, "invalid",
"../outside/secret.tiff").isEmpty());
- loggings.assertNextLogContains("../outside/secret.tiff", "Coastal
Aerosol");
- loggings.assertNoUnexpectedLog();
+ assertFalse(isWarningExpected, "Warning should have been emitted.");
+ }
+
+ /**
+ * Invoked when a warning is emitted.
+ * Verifies if the warning was expected, and if so, if it contains the
expected message.
+ *
+ * @param event the warning.
+ */
+ @Override
+ public void eventOccurred(final WarningEvent event) {
+ final String message = event.getMessage(null);
+ assertTrue(isWarningExpected, message);
+ assertTrue(message.contains("../outside/secret.tiff"),
"../outside/secret.tiff");
+ assertTrue(message.contains("Coastal Aerosol"), "Coastal Aerosol");
+ isWarningExpected = false;
}
}
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/event/WarningEvent.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/event/WarningEvent.java
index 910ec2dd87..a2b68b629e 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/event/WarningEvent.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/event/WarningEvent.java
@@ -16,10 +16,12 @@
*/
package org.apache.sis.storage.event;
+import java.util.Locale;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import org.apache.sis.storage.Resource;
+import org.apache.sis.util.internal.shared.Strings;
/**
@@ -29,8 +31,8 @@ import org.apache.sis.storage.Resource;
* {@linkplain LogRecord#getInstant() log time}, <i>etc.</i>) in addition of
warning message.
*
* @author Martin Desruisseaux (Geomatys)
+ * @version 1.7
* @since 1.0
- * @version 1.0
*/
public class WarningEvent extends StoreEvent {
/**
@@ -66,6 +68,18 @@ public class WarningEvent extends StoreEvent {
return description;
}
+ /**
+ * Returns the warning message, preferably in the given locale.
+ * The locale is used on a best-effort basis and may be ignored if
unsupported.
+ *
+ * @param locale the desired locale, or {@code null} for the default
locale.
+ * @return the warning message, preferably in the given locale.
+ * @since 1.7
+ */
+ public String getMessage(final Locale locale) {
+ return Strings.formatMessage(description, locale, null, null, null);
+ }
+
/**
* Returns a string representation of this warning for debugging purpose.
*
@@ -73,7 +87,7 @@ public class WarningEvent extends StoreEvent {
*/
@Override
public String toString() {
- final StringBuilder b = new StringBuilder();
+ final var b = new StringBuilder();
final Level level = description.getLevel();
if (level != null) {
b.append(level.getLocalizedName()).append(": ");
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/event/package-info.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/event/package-info.java
index f38c736143..35d79d8856 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/event/package-info.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/event/package-info.java
@@ -35,7 +35,7 @@
*
* @author Johann Sorel (Geomatys)
* @author Martin Desruisseaux (Geomatys)
- * @since 1.7
- * @version 1.0
+ * @version 1.7
+ * @since 1.0
*/
package org.apache.sis.storage.event;
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/AutoMessageFormat.java
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/AutoMessageFormat.java
index 3b86c72da0..7e51838f3f 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/AutoMessageFormat.java
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/AutoMessageFormat.java
@@ -37,6 +37,13 @@ public final class AutoMessageFormat extends MessageFormat {
*/
private transient NumberFormat[] formatsToConfigure;
+ /**
+ * Value of the last call to {@link MessageFormat#applyPattern(String)}.
Saved in order to avoid
+ * calling {@code super.applyPattern(String)} in the common case where the
same message is logged
+ * many times with different arguments.
+ */
+ private transient String currentPattern;
+
/**
* Whether the {@link #formatsToConfigure} needs to be updated.
*/
@@ -49,6 +56,7 @@ public final class AutoMessageFormat extends MessageFormat {
*/
public AutoMessageFormat(final String pattern) {
super(pattern);
+ currentPattern = pattern;
}
/**
@@ -59,17 +67,23 @@ public final class AutoMessageFormat extends MessageFormat {
*/
public AutoMessageFormat(final String pattern, final Locale locale) {
super(pattern, locale);
+ currentPattern = pattern;
}
/**
* Modifies the pattern used by this message format.
+ * This method does nothing if this formatter is already applying the
given pattern.
*
* @param pattern the new pattern for this message format
*/
@Override
public void applyPattern(final String pattern) {
- super.applyPattern(pattern);
- update = true;
+ if (!pattern.equals(currentPattern)) {
+ currentPattern = null;
+ super.applyPattern(pattern);
+ currentPattern = pattern;
+ update = true;
+ }
}
/**
@@ -82,7 +96,7 @@ public final class AutoMessageFormat extends MessageFormat {
if (update) {
formatsToConfigure = null;
final Format[] fc = getFormatsByArgumentIndex();
- for (int i=fc.length; --i >= 0;) {
+ for (int i = fc.length; --i >= 0;) {
final Format c = fc[i];
if (c instanceof NumberFormat) {
if (formatsToConfigure == null) {
@@ -93,7 +107,7 @@ public final class AutoMessageFormat extends MessageFormat {
}
}
if (formatsToConfigure != null) {
- for (int i=Math.min(formatsToConfigure.length, arguments.length);
--i >= 0;) {
+ for (int i = Math.min(formatsToConfigure.length,
arguments.length); --i >= 0;) {
final NumberFormat f = formatsToConfigure[i];
if (f != null) {
final Object value = arguments[i];
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/Strings.java
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/Strings.java
index d37ee4cd22..ed17df182a 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/Strings.java
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/Strings.java
@@ -17,14 +17,24 @@
package org.apache.sis.util.internal.shared;
import java.lang.reflect.Array;
+import java.text.FieldPosition;
+import java.text.MessageFormat;
import java.util.Locale;
import java.util.Formatter;
import java.util.FormattableFlags;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.function.Consumer;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
import org.apache.sis.util.Classes;
import org.apache.sis.util.ArraysExt;
import org.apache.sis.util.Characters;
import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.logging.Logging;
+import org.apache.sis.util.internal.AutoMessageFormat;
import org.apache.sis.pending.jdk.JDK15;
+import org.apache.sis.system.Modules;
/**
@@ -458,4 +468,72 @@ public final class Strings {
}
formatter.format(format, args);
}
+
+ /**
+ * Returns the localized message from the given log record.
+ * This is the implementation of {@link
org.apache.sis.util.logging.MonolineFormatter#formatMessage(LogRecord)}.
+ * See the javadoc of that method for more information.
+ *
+ * <h4>Source</h4>
+ * This method does the same work as {@link
java.util.logging.Formatter#formatMessage(LogRecord)} except for the
+ * synchronization lock, the reuse of existing {@link MessageFormat} and
{@link StringBuffer} instances, and not
+ * catching formatting exceptions (we want to know if our messages have a
problem).
+ *
+ * @param record the log record from which to get a localized message.
+ * @param locale the desired locale, or {@code null} for the default.
+ * @param buffer a preexisting buffer to reuse, or {@code null} if none.
+ * @param format a preexisting formatter to reuse, or {@code null} if
none.
+ * @param cache where to cache new {@link AutoMessageFormat}, of {@code
null} if none.
+ * @return the localized message.
+ */
+ public static String formatMessage(final LogRecord record, final Locale
locale,
+ StringBuffer buffer, AutoMessageFormat format,
Consumer<AutoMessageFormat> cache)
+ {
+ String message = record.getMessage();
+ ResourceBundle resources = null;
+ if (locale != null) {
+ final String baseName = record.getResourceBundleName();
+ if (baseName != null) try {
+ resources = ResourceBundle.getBundle(baseName, locale);
+ } catch (MissingResourceException e) {
+
Logging.ignorableException(Logger.getLogger(Modules.UTILITIES), null, null, e);
+ }
+ }
+ if (resources == null) {
+ resources = record.getResourceBundle();
+ }
+ if (resources != null) {
+ message = resources.getString(message);
+ }
+ final Object[] parameters = record.getParameters();
+ if (parameters != null && parameters.length != 0) {
+ int i = message.indexOf('{');
+ if (i >= 0 && ++i < message.length()) {
+ final char c = message.charAt(i);
+ if (c >= '0' && c <= '9') {
+ if (buffer == null) {
+ buffer = new StringBuffer();
+ }
+ synchronized (buffer) {
+ if (format != null) {
+ format.applyPattern(message);
+ } else {
+ format = new AutoMessageFormat(message);
+ if (cache != null) {
+ cache.accept(format);
+ }
+ }
+ final int base = buffer.length();
+ try {
+ format.configure(parameters);
+ message = format.format(parameters, buffer, new
FieldPosition(0)).substring(base);
+ } finally {
+ buffer.setLength(base);
+ }
+ }
+ }
+ }
+ }
+ return message;
+ }
}
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/logging/MonolineFormatter.java
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/logging/MonolineFormatter.java
index f6f6d83b35..ed79855b93 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/logging/MonolineFormatter.java
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/logging/MonolineFormatter.java
@@ -30,7 +30,6 @@ import java.util.Arrays;
import java.util.TreeMap;
import java.util.SortedMap;
import java.util.Comparator;
-import java.util.ResourceBundle;
import java.util.logging.*;
import java.util.function.IntSupplier;
import org.apache.sis.system.Modules;
@@ -246,13 +245,6 @@ public class MonolineFormatter extends Formatter {
*/
private transient AutoMessageFormat messageFormat;
- /**
- * Value of the last call to {@link MessageFormat#applyPattern(String)}.
Saved in order to avoid
- * calling {@code applyPattern(String)} in the common case where the same
message is logged many
- * times with different arguments.
- */
- private transient String messagePattern;
-
/**
* One of the following constants: {@link #NO_SOURCE}, {@link
#LOGGER_SHORT},
* {@link #LOGGER_LONG}, {@link #CLASS_SHORT}, {@link #CLASS_LONG} or
{@link #METHOD}.
@@ -855,41 +847,7 @@ loop: for (int i=0; ; i++) {
*/
@Override
public String formatMessage(final LogRecord record) {
- /*
- * Same work as java.util.logging.Formatter.formatMessage(LogRecord)
except for the synchronization lock,
- * the reuse of existing MessageFormat and StringBuffer instances, and
not catching formatting exceptions
- * (we want to know if our messages have a problem).
- */
- String message = record.getMessage();
- ResourceBundle resources = record.getResourceBundle();
- if (resources != null) {
- message = resources.getString(message);
- }
- final Object[] parameters = record.getParameters();
- if (parameters != null && parameters.length != 0) {
- int i = message.indexOf('{');
- if (i >= 0 && ++i < message.length()) {
- final char c = message.charAt(i);
- if (c >= '0' && c <= '9') {
- synchronized (buffer) {
- if (messageFormat == null) {
- messageFormat = new AutoMessageFormat(message);
- } else if (!message.equals(messagePattern)) {
- messageFormat.applyPattern(message);
- }
- messagePattern = message;
- final int base = buffer.length();
- try {
- messageFormat.configure(parameters);
- message = messageFormat.format(parameters, buffer,
new FieldPosition(0)).substring(base);
- } finally {
- buffer.setLength(base);
- }
- }
- }
- }
- }
- return message;
+ return Strings.formatMessage(record, null, buffer, messageFormat,
(created) -> messageFormat = created);
}
/**
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/IndexedResourceBundle.java
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/IndexedResourceBundle.java
index 034f41e792..998e711792 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/IndexedResourceBundle.java
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/IndexedResourceBundle.java
@@ -131,13 +131,6 @@ public abstract class IndexedResourceBundle extends
ResourceBundle implements Lo
*/
private transient AutoMessageFormat format;
- /**
- * The key of the last resource requested. If the same resource is
requested multiple times,
- * knowing its key allows us to avoid invoking the costly {@link
MessageFormat#applyPattern}
- * method.
- */
- private transient short lastKey;
-
/**
* Constructs a new resource bundle loading data from a UTF file derived
from the class name.
*/
@@ -557,18 +550,9 @@ public abstract class IndexedResourceBundle extends
ResourceBundle implements Lo
final Object[] arguments = toArray(arg0);
synchronized (this) {
if (format == null) {
- /*
- * Constructs a new MessageFormat for formatting the arguments.
- */
format = new AutoMessageFormat(pattern, getLocale());
- lastKey = key;
- } else if (key != lastKey) {
- /*
- * Method MessageFormat.applyPattern(…) is costly! We will
avoid
- * calling it again if the format already has the right
pattern.
- */
+ } else {
format.applyPattern(pattern);
- lastKey = key;
}
try {
format.configure(arguments);