diff --git a/src/main/java/info/ronjenkins/slf4bukkit/AnsiColorMapper.java b/src/main/java/info/ronjenkins/slf4bukkit/AnsiColorMapper.java
new file mode 100644
index 0000000..6ced4e0
--- /dev/null
+++ b/src/main/java/info/ronjenkins/slf4bukkit/AnsiColorMapper.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 Ronald Jack Jenkins Jr.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package info.ronjenkins.slf4bukkit;
+
+import com.google.common.collect.ImmutableMap;
+
+import org.bukkit.ChatColor;
+import org.fusesource.jansi.Ansi;
+import org.fusesource.jansi.Ansi.Attribute;
+
+import java.util.Map;
+
+/**
+ * Maps {@link ChatColor} values to their JAnsi equivalents.
+ *
+ *
This class might not always be instantiable as jansi might not be present at runtime.
+ *
+ * @author Ronald Jack Jenkins Jr.
+ */
+final class AnsiColorMapper implements ColorMapper {
+
+ AnsiColorMapper() throws Throwable {
+ // Calling this constructor could result in a Throwable because JAnsi, which is required to execute code
+ // in this class, might not be present at runtime, thus expected classes are not found.
+ }
+
+ // @formatter:off
+ private final Map MAP = ImmutableMap.builder()
+ .put(ChatColor.BLACK, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLACK).boldOff().toString())
+ .put(ChatColor.DARK_BLUE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLUE).boldOff().toString())
+ .put(ChatColor.DARK_GREEN, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.GREEN).boldOff().toString())
+ .put(ChatColor.DARK_AQUA, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.CYAN).boldOff().toString())
+ .put(ChatColor.DARK_RED, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.RED).boldOff().toString())
+ .put(ChatColor.DARK_PURPLE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.MAGENTA).boldOff().toString())
+ .put(ChatColor.GOLD, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.YELLOW).boldOff().toString())
+ .put(ChatColor.GRAY, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.WHITE).boldOff().toString())
+ .put(ChatColor.DARK_GRAY, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLACK).bold().toString())
+ .put(ChatColor.BLUE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLUE).bold().toString())
+ .put(ChatColor.GREEN, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.GREEN).bold().toString())
+ .put(ChatColor.AQUA, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.CYAN).bold().toString())
+ .put(ChatColor.RED, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.RED).bold().toString())
+ .put(ChatColor.LIGHT_PURPLE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.MAGENTA).bold().toString())
+ .put(ChatColor.YELLOW, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.YELLOW).bold().toString())
+ .put(ChatColor.WHITE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.WHITE).bold().toString())
+ .put(ChatColor.MAGIC, Ansi.ansi().a(Attribute.BLINK_SLOW).toString())
+ .put(ChatColor.BOLD, Ansi.ansi().a(Attribute.UNDERLINE_DOUBLE).toString())
+ .put(ChatColor.STRIKETHROUGH, Ansi.ansi().a(Attribute.STRIKETHROUGH_ON).toString())
+ .put(ChatColor.UNDERLINE, Ansi.ansi().a(Attribute.UNDERLINE).toString())
+ .put(ChatColor.ITALIC, Ansi.ansi().a(Attribute.ITALIC).toString())
+ .put(ChatColor.RESET, Ansi.ansi().a(Attribute.RESET).toString())
+ .build();
+ // @formatter:on
+
+ @Override
+ public String map(final String input) {
+ if (input == null) {
+ return "";
+ }
+ String output = input;
+ for (final Map.Entry mapping : MAP.entrySet()) {
+ output = output.replace(mapping.getKey().toString(), mapping.getValue());
+ }
+ return output;
+ }
+
+}
diff --git a/src/main/java/info/ronjenkins/slf4bukkit/ColorMapper.java b/src/main/java/info/ronjenkins/slf4bukkit/ColorMapper.java
index 506b490..bafaccb 100644
--- a/src/main/java/info/ronjenkins/slf4bukkit/ColorMapper.java
+++ b/src/main/java/info/ronjenkins/slf4bukkit/ColorMapper.java
@@ -16,63 +16,21 @@
*/
package info.ronjenkins.slf4bukkit;
-import java.util.Map;
-
import org.bukkit.ChatColor;
-import org.fusesource.jansi.Ansi;
-import org.fusesource.jansi.Ansi.Attribute;
-
-import com.google.common.collect.ImmutableMap;
/**
- * Utility class that maps {@link ChatColor} values to their JAnsi equivalents,
+ * Utility class that maps {@link ChatColor} values to their equivalents,
* so that messages logged to the console are formatted correctly.
- *
- * @author Ronald Jack Jenkins Jr.
*/
-public final class ColorMapper {
-
- // @formatter:off
- private static final Map MAP = ImmutableMap.builder()
- .put(ChatColor.BLACK, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLACK).boldOff().toString())
- .put(ChatColor.DARK_BLUE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLUE).boldOff().toString())
- .put(ChatColor.DARK_GREEN, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.GREEN).boldOff().toString())
- .put(ChatColor.DARK_AQUA, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.CYAN).boldOff().toString())
- .put(ChatColor.DARK_RED, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.RED).boldOff().toString())
- .put(ChatColor.DARK_PURPLE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.MAGENTA).boldOff().toString())
- .put(ChatColor.GOLD, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.YELLOW).boldOff().toString())
- .put(ChatColor.GRAY, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.WHITE).boldOff().toString())
- .put(ChatColor.DARK_GRAY, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLACK).bold().toString())
- .put(ChatColor.BLUE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLUE).bold().toString())
- .put(ChatColor.GREEN, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.GREEN).bold().toString())
- .put(ChatColor.AQUA, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.CYAN).bold().toString())
- .put(ChatColor.RED, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.RED).bold().toString())
- .put(ChatColor.LIGHT_PURPLE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.MAGENTA).bold().toString())
- .put(ChatColor.YELLOW, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.YELLOW).bold().toString())
- .put(ChatColor.WHITE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.WHITE).bold().toString())
- .put(ChatColor.MAGIC, Ansi.ansi().a(Attribute.BLINK_SLOW).toString())
- .put(ChatColor.BOLD, Ansi.ansi().a(Attribute.UNDERLINE_DOUBLE).toString())
- .put(ChatColor.STRIKETHROUGH, Ansi.ansi().a(Attribute.STRIKETHROUGH_ON).toString())
- .put(ChatColor.UNDERLINE, Ansi.ansi().a(Attribute.UNDERLINE).toString())
- .put(ChatColor.ITALIC, Ansi.ansi().a(Attribute.ITALIC).toString())
- .put(ChatColor.RESET, Ansi.ansi().a(Attribute.RESET).toString())
- .build();
- // @formatter:on
+public interface ColorMapper {
/**
- * Translates {@link ChatColor} directives to their JAnsi equivalents.
+ * Translates {@link ChatColor} directives to their equivalents.
*
* @param input
* null is coerced to the empty string.
* @return never null.
*/
- public static String map(final String input) {
- if (input == null) { return ""; }
- String output = input;
- for (final Map.Entry mapping : ColorMapper.MAP.entrySet()) {
- output = output.replace(mapping.getKey().toString(), mapping.getValue());
- }
- return output;
- }
+ String map(String input);
}
diff --git a/src/main/java/info/ronjenkins/slf4bukkit/ColorMapperFactory.java b/src/main/java/info/ronjenkins/slf4bukkit/ColorMapperFactory.java
new file mode 100644
index 0000000..67a0c58
--- /dev/null
+++ b/src/main/java/info/ronjenkins/slf4bukkit/ColorMapperFactory.java
@@ -0,0 +1,23 @@
+package info.ronjenkins.slf4bukkit;
+
+/**
+ * Creates {@code ColorMapper} instances.
+ *
+ * @see ColorMapper
+ */
+public final class ColorMapperFactory {
+
+ /**
+ * Creates an new {@code ColorMapper} instance.
+ *
+ * @return a new instance
+ */
+ public static ColorMapper create() {
+ try {
+ return new AnsiColorMapper();
+ } catch (Throwable throwable) {
+ return new NotSupportedColorMapper();
+ }
+ }
+
+}
diff --git a/src/main/java/info/ronjenkins/slf4bukkit/NotSupportedColorMapper.java b/src/main/java/info/ronjenkins/slf4bukkit/NotSupportedColorMapper.java
new file mode 100644
index 0000000..d67fda4
--- /dev/null
+++ b/src/main/java/info/ronjenkins/slf4bukkit/NotSupportedColorMapper.java
@@ -0,0 +1,12 @@
+package info.ronjenkins.slf4bukkit;
+
+/**
+ * Does not do any mapping but simply returns the given string or, if {@code null} is given, an empty string.
+ */
+final class NotSupportedColorMapper implements ColorMapper {
+
+ @Override
+ public String map(final String input) {
+ return input == null ? "" : input;
+ }
+}
diff --git a/src/main/java/org/slf4j/impl/BukkitLoggerAdapter.java b/src/main/java/org/slf4j/impl/BukkitLoggerAdapter.java
index 9ffb5e9..1e53511 100644
--- a/src/main/java/org/slf4j/impl/BukkitLoggerAdapter.java
+++ b/src/main/java/org/slf4j/impl/BukkitLoggerAdapter.java
@@ -45,6 +45,7 @@
package org.slf4j.impl;
import info.ronjenkins.slf4bukkit.ColorMapper;
+import info.ronjenkins.slf4bukkit.ColorMapperFactory;
import info.ronjenkins.slf4bukkit.ColorMarker;
import java.io.IOException;
@@ -218,6 +219,7 @@ public final class BukkitLoggerAdapter implements Logger {
// The logger name.
private final String name;
// The short name of this simple log instance
+ private final ColorMapper mapper = ColorMapperFactory.create();
private transient String shortLogName = null;
// NOTE: BukkitPluginLoggerAdapter constructor should have only package access
@@ -1043,6 +1045,6 @@ public final class BukkitLoggerAdapter implements Logger {
// Log the message.
logger.log(BukkitLoggerAdapter.slf4jLevelIntToBukkitJULLevel(level),
- ColorMapper.map(buf.toString()));
+ mapper.map(buf.toString()));
}
}