From 7001052031438b1a896af2753dfc09025c671b16 Mon Sep 17 00:00:00 2001 From: Stefan Dollase Date: Mon, 21 Nov 2016 01:48:08 +0100 Subject: [PATCH] added the classes AmidstMessageBox and MessageFormatter --- src/main/java/amidst/Amidst.java | 8 +- src/main/java/amidst/gui/main/MainWindow.java | 16 +-- .../java/amidst/gui/main/UpdatePrompt.java | 24 +--- .../java/amidst/logging/AmidstLogger.java | 36 ++---- .../java/amidst/logging/AmidstMessageBox.java | 104 ++++++++++++++++++ .../java/amidst/logging/MessageFormatter.java | 56 ++++++++++ .../mojangapi/file/json/JsonReader.java | 4 +- .../amidst/logging/MessageFormatterTest.java | 83 ++++++++++++++ 8 files changed, 266 insertions(+), 65 deletions(-) create mode 100644 src/main/java/amidst/logging/AmidstMessageBox.java create mode 100644 src/main/java/amidst/logging/MessageFormatter.java create mode 100644 src/test/java/amidst/logging/MessageFormatterTest.java diff --git a/src/main/java/amidst/Amidst.java b/src/main/java/amidst/Amidst.java index 4fa5cf38..c6db77ec 100644 --- a/src/main/java/amidst/Amidst.java +++ b/src/main/java/amidst/Amidst.java @@ -5,7 +5,6 @@ import java.sql.Timestamp; import java.util.Date; import java.util.prefs.Preferences; -import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import org.kohsuke.args4j.CmdLineException; @@ -18,6 +17,7 @@ import amidst.documentation.CalledOnlyBy; import amidst.documentation.NotThreadSafe; import amidst.gui.crash.CrashWindow; import amidst.logging.AmidstLogger; +import amidst.logging.AmidstMessageBox; import amidst.logging.FileLogger; import amidst.mojangapi.file.DotMinecraftDirectoryNotFoundException; import amidst.util.OperatingSystemDetector; @@ -172,11 +172,9 @@ public class Amidst { } catch (DotMinecraftDirectoryNotFoundException e) { AmidstLogger.warn(e.getMessage()); e.printStackTrace(); - JOptionPane.showMessageDialog( - null, - "Amidst is not able to find your '.minecraft' directory, but it requires a working Minecraft installation.", + AmidstMessageBox.displayError( "Please install Minecraft", - JOptionPane.ERROR_MESSAGE); + "Amidst is not able to find your '.minecraft' directory, but it requires a working Minecraft installation."); } catch (Exception e) { handleCrash(e, Thread.currentThread()); } diff --git a/src/main/java/amidst/gui/main/MainWindow.java b/src/main/java/amidst/gui/main/MainWindow.java index d02b6ab2..9510b719 100644 --- a/src/main/java/amidst/gui/main/MainWindow.java +++ b/src/main/java/amidst/gui/main/MainWindow.java @@ -6,8 +6,6 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; import java.util.List; import java.util.concurrent.atomic.AtomicReference; @@ -27,6 +25,7 @@ import amidst.gui.main.viewer.ViewerFacade; import amidst.gui.main.viewer.ViewerFacadeBuilder; import amidst.gui.seedsearcher.SeedSearcher; import amidst.gui.seedsearcher.SeedSearcherWindow; +import amidst.logging.AmidstMessageBox; import amidst.mojangapi.MojangApi; import amidst.mojangapi.file.MojangApiParsingException; import amidst.mojangapi.minecraftinterface.MinecraftInterfaceException; @@ -283,24 +282,17 @@ public class MainWindow { @CalledOnlyBy(AmidstThread.EDT) public void displayMessage(String title, String message) { - JOptionPane.showMessageDialog(frame, message, title, JOptionPane.INFORMATION_MESSAGE); + AmidstMessageBox.displayInfo(frame, title, message); } @CalledOnlyBy(AmidstThread.EDT) public void displayError(String message) { - JOptionPane.showMessageDialog(frame, message, "Error", JOptionPane.ERROR_MESSAGE); + AmidstMessageBox.displayError(frame, "Error", message); } @CalledOnlyBy(AmidstThread.EDT) public void displayException(Exception exception) { - JOptionPane.showMessageDialog(frame, getStackTraceAsString(exception), "Error", JOptionPane.ERROR_MESSAGE); - } - - @CalledOnlyBy(AmidstThread.EDT) - private String getStackTraceAsString(Exception exception) { - StringWriter writer = new StringWriter(); - exception.printStackTrace(new PrintWriter(writer)); - return writer.toString(); + AmidstMessageBox.displayError(frame, "Error", exception); } @CalledOnlyBy(AmidstThread.EDT) diff --git a/src/main/java/amidst/gui/main/UpdatePrompt.java b/src/main/java/amidst/gui/main/UpdatePrompt.java index d19e2f31..cee5dda7 100644 --- a/src/main/java/amidst/gui/main/UpdatePrompt.java +++ b/src/main/java/amidst/gui/main/UpdatePrompt.java @@ -2,8 +2,6 @@ package amidst.gui.main; import java.awt.Desktop; import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; import java.net.URI; import java.net.URISyntaxException; import java.util.function.Consumer; @@ -17,6 +15,7 @@ import amidst.documentation.CalledOnlyBy; import amidst.documentation.NotNull; import amidst.documentation.NotThreadSafe; import amidst.logging.AmidstLogger; +import amidst.logging.AmidstMessageBox; import amidst.threading.WorkerExecutor; @NotThreadSafe @@ -56,30 +55,13 @@ public class UpdatePrompt { return new UpdatePrompt( currentVersion, workerExecutor, - exception -> displayExceptionDirectly(exception), - () -> displayMessageDirectly(NO_UPDATES_AVAILABLE), + exception -> AmidstMessageBox.displayError(TITLE, exception), + () -> AmidstMessageBox.displayInfo(TITLE, NO_UPDATES_AVAILABLE), message -> askToConfirmDirectly(message)); } } } - @CalledOnlyBy(AmidstThread.EDT) - private static void displayExceptionDirectly(Exception exception) { - JOptionPane.showMessageDialog(null, getStackTraceAsString(exception), TITLE, JOptionPane.ERROR_MESSAGE); - } - - @CalledOnlyBy(AmidstThread.EDT) - private static String getStackTraceAsString(Exception exception) { - StringWriter writer = new StringWriter(); - exception.printStackTrace(new PrintWriter(writer)); - return writer.toString(); - } - - @CalledOnlyBy(AmidstThread.EDT) - private static void displayMessageDirectly(String message) { - JOptionPane.showMessageDialog(null, message, TITLE, JOptionPane.INFORMATION_MESSAGE); - } - @CalledOnlyBy(AmidstThread.EDT) private static boolean askToConfirmDirectly(String message) { return JOptionPane.showConfirmDialog(null, message, TITLE, JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION; diff --git a/src/main/java/amidst/logging/AmidstLogger.java b/src/main/java/amidst/logging/AmidstLogger.java index c3060d95..f4181b34 100644 --- a/src/main/java/amidst/logging/AmidstLogger.java +++ b/src/main/java/amidst/logging/AmidstLogger.java @@ -1,7 +1,5 @@ package amidst.logging; -import java.io.PrintWriter; -import java.io.StringWriter; import java.util.HashMap; import java.util.Map; @@ -19,11 +17,13 @@ public class AmidstLogger { private static final boolean IS_USING_ALERTS = true; private static final boolean IS_SHOWING_DEBUG = true; - private static final Map LOGGER = new HashMap<>(); + private static final Map LOGGER = createLoggerMap(); - static { - addListener("console", CONSOLE_LOGGER); - addListener("master", IN_MEMORY_LOGGER); + private static Map createLoggerMap() { + Map result = new HashMap<>(); + result.put("console", CONSOLE_LOGGER); + result.put("master", IN_MEMORY_LOGGER); + return result; } public static void addListener(String name, Logger logger) { @@ -64,6 +64,10 @@ public class AmidstLogger { } } + public static void warn(Throwable e) { + warn(MessageFormatter.format(e)); + } + public static void error(Object... messages) { synchronized (LOG_LOCK) { if (IS_USING_ALERTS) { @@ -77,7 +81,7 @@ public class AmidstLogger { public static void crash(Throwable e, String message) { synchronized (LOG_LOCK) { - String exceptionText = getExceptionText(e); + String exceptionText = MessageFormatter.format(e); for (Logger listener : LOGGER.values()) { listener.crash(e, exceptionText, message); } @@ -89,22 +93,4 @@ public class AmidstLogger { return IN_MEMORY_LOGGER.getContents(); } } - - private static String getExceptionText(Throwable e) { - if (e != null) { - return getStackTraceAsString(e); - } else { - return ""; - } - } - - public static void printTraceStack(Throwable e) { - warn(getStackTraceAsString(e)); - } - - private static String getStackTraceAsString(Throwable e) { - StringWriter writer = new StringWriter(); - e.printStackTrace(new PrintWriter(writer)); - return writer.toString(); - } } diff --git a/src/main/java/amidst/logging/AmidstMessageBox.java b/src/main/java/amidst/logging/AmidstMessageBox.java new file mode 100644 index 00000000..e4859afc --- /dev/null +++ b/src/main/java/amidst/logging/AmidstMessageBox.java @@ -0,0 +1,104 @@ +package amidst.logging; + +import java.awt.Component; + +import javax.swing.JOptionPane; + +import amidst.documentation.AmidstThread; +import amidst.documentation.CalledOnlyBy; +import amidst.documentation.NotThreadSafe; + +@NotThreadSafe +public enum AmidstMessageBox { + ; + + @CalledOnlyBy(AmidstThread.EDT) + public static void displayError(String title, Throwable e) { + displayMessageBox(title, MessageFormatter.format(e), JOptionPane.ERROR_MESSAGE); + } + + @CalledOnlyBy(AmidstThread.EDT) + public static void displayError(String title, Throwable e, String message) { + displayMessageBox(title, MessageFormatter.format(e, message), JOptionPane.ERROR_MESSAGE); + } + + @CalledOnlyBy(AmidstThread.EDT) + public static void displayError(String title, Throwable e, String message, String part1, String[] parts) { + displayMessageBox(title, MessageFormatter.format(e, message, part1, parts), JOptionPane.ERROR_MESSAGE); + } + + @CalledOnlyBy(AmidstThread.EDT) + public static void displayError(String title, String message) { + displayMessageBox(title, MessageFormatter.format(message), JOptionPane.ERROR_MESSAGE); + } + + @CalledOnlyBy(AmidstThread.EDT) + public static void displayError(String title, String message, String part1, String[] parts) { + displayMessageBox(title, MessageFormatter.format(message, part1, parts), JOptionPane.ERROR_MESSAGE); + } + + @CalledOnlyBy(AmidstThread.EDT) + public static void displayInfo(String title, String message) { + displayMessageBox(title, MessageFormatter.format(message), JOptionPane.INFORMATION_MESSAGE); + } + + @CalledOnlyBy(AmidstThread.EDT) + public static void displayInfo(String title, String message, String part1, String[] parts) { + displayMessageBox(title, MessageFormatter.format(message, part1, parts), JOptionPane.INFORMATION_MESSAGE); + } + + @CalledOnlyBy(AmidstThread.EDT) + public static void displayError(Component parent, String title, Throwable e) { + displayMessageBox(parent, title, MessageFormatter.format(e), JOptionPane.ERROR_MESSAGE); + } + + @CalledOnlyBy(AmidstThread.EDT) + public static void displayError(Component parent, String title, Throwable e, String message) { + displayMessageBox(parent, title, MessageFormatter.format(e, message), JOptionPane.ERROR_MESSAGE); + } + + @CalledOnlyBy(AmidstThread.EDT) + public static void displayError( + Component parent, + String title, + Throwable e, + String message, + String part1, + String[] parts) { + displayMessageBox(parent, title, MessageFormatter.format(e, message, part1, parts), JOptionPane.ERROR_MESSAGE); + } + + @CalledOnlyBy(AmidstThread.EDT) + public static void displayError(Component parent, String title, String message) { + displayMessageBox(parent, title, MessageFormatter.format(message), JOptionPane.ERROR_MESSAGE); + } + + @CalledOnlyBy(AmidstThread.EDT) + public static void displayError(Component parent, String title, String message, String part1, String[] parts) { + displayMessageBox(parent, title, MessageFormatter.format(message, part1, parts), JOptionPane.ERROR_MESSAGE); + } + + @CalledOnlyBy(AmidstThread.EDT) + public static void displayInfo(Component parent, String title, String message) { + displayMessageBox(parent, title, MessageFormatter.format(message), JOptionPane.INFORMATION_MESSAGE); + } + + @CalledOnlyBy(AmidstThread.EDT) + public static void displayInfo(Component parent, String title, String message, String part1, String[] parts) { + displayMessageBox( + parent, + title, + MessageFormatter.format(message, part1, parts), + JOptionPane.INFORMATION_MESSAGE); + } + + @CalledOnlyBy(AmidstThread.EDT) + private static void displayMessageBox(String title, String message, int type) { + JOptionPane.showMessageDialog(null, message, title, type); + } + + @CalledOnlyBy(AmidstThread.EDT) + private static void displayMessageBox(Component parent, String title, String message, int type) { + JOptionPane.showMessageDialog(parent, message, title, type); + } +} diff --git a/src/main/java/amidst/logging/MessageFormatter.java b/src/main/java/amidst/logging/MessageFormatter.java new file mode 100644 index 00000000..cd468e79 --- /dev/null +++ b/src/main/java/amidst/logging/MessageFormatter.java @@ -0,0 +1,56 @@ +package amidst.logging; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Objects; + +import amidst.documentation.Immutable; + +@Immutable +public enum MessageFormatter { + ; + + public static String format(Throwable e, String message) { + return format(message) + "\n\n" + format(e); + } + + public static String format(Throwable e, String message, String part1, String[] parts) { + return format(message, part1, parts) + "\n\n" + format(e); + } + + public static String format(String message) { + return String.valueOf(message); + } + + public static String format(Throwable e) { + if (e != null) { + StringWriter writer = new StringWriter(); + e.printStackTrace(new PrintWriter(writer)); + return writer.toString(); + } else { + return "null"; + } + } + + public static String format(String message, String part1, String... parts) { + Objects.requireNonNull(message, "the message cannot be null"); + + int expectedNumberOfMessageParts = 2 + parts.length; + String[] messageParts = message.split("\\{\\}", expectedNumberOfMessageParts); + if (messageParts.length == 0) { + return ""; + } else if (messageParts.length == 1) { + return messageParts[0]; + } else { + StringBuilder b = new StringBuilder(); + b.append(messageParts[0]); + b.append(format(part1)); + b.append(messageParts[1]); + for (int i = 2; i < messageParts.length; i++) { + b.append(format(parts[i - 2])); + b.append(messageParts[i]); + } + return b.toString(); + } + } +} diff --git a/src/main/java/amidst/mojangapi/file/json/JsonReader.java b/src/main/java/amidst/mojangapi/file/json/JsonReader.java index 56d12c80..146978a8 100644 --- a/src/main/java/amidst/mojangapi/file/json/JsonReader.java +++ b/src/main/java/amidst/mojangapi/file/json/JsonReader.java @@ -49,7 +49,7 @@ public enum JsonReader { remote = readRemoteVersionList(); } catch (IOException | MojangApiParsingException e) { AmidstLogger.warn("Unable to read remote version list."); - AmidstLogger.printTraceStack(e); + AmidstLogger.warn(e); AmidstLogger.warn("Aborting version list load. URL: " + REMOTE_VERSION_LIST); } if (remote != null) { @@ -62,7 +62,7 @@ public enum JsonReader { local = readLocalVersionListFromResource(); } catch (IOException | MojangApiParsingException e) { AmidstLogger.warn("Unable to read local version list."); - AmidstLogger.printTraceStack(e); + AmidstLogger.warn(e); AmidstLogger.warn("Aborting version list load. URL: " + LOCAL_VERSION_LIST); } if (local != null) { diff --git a/src/test/java/amidst/logging/MessageFormatterTest.java b/src/test/java/amidst/logging/MessageFormatterTest.java new file mode 100644 index 00000000..a74ff98a --- /dev/null +++ b/src/test/java/amidst/logging/MessageFormatterTest.java @@ -0,0 +1,83 @@ +package amidst.logging; + +import org.junit.Assert; +import org.junit.Test; + +public class MessageFormatterTest { + @Test + public void testEmptyMessage() { + String message = ""; + String expected = ""; + Assert.assertEquals(expected, MessageFormatter.format(message, "p1")); + } + + @Test + public void testSimplyMessage() { + String message = "{}"; + String expected = "p1"; + Assert.assertEquals(expected, MessageFormatter.format(message, "p1")); + } + + @Test + public void testBeforeMessage() { + String message = "{}m1"; + String expected = "p1m1"; + Assert.assertEquals(expected, MessageFormatter.format(message, "p1")); + } + + @Test + public void testAfterMessage() { + String message = "m1{}"; + String expected = "m1p1"; + Assert.assertEquals(expected, MessageFormatter.format(message, "p1")); + } + + @Test + public void testBetweenMessages() { + String message = "m1{}m2"; + String expected = "m1p1m2"; + Assert.assertEquals(expected, MessageFormatter.format(message, "p1")); + } + + @Test + public void testChain1() { + String message = "m1{}m2{}m3{}m4{}m5{}"; + String expected = "m1p1m2p2m3p3m4p4m5p5"; + Assert.assertEquals(expected, MessageFormatter.format(message, "p1", "p2", "p3", "p4", "p5")); + } + + @Test + public void testChain2() { + String message = "m1{}m2{}m3{}m4{}m5"; + String expected = "m1p1m2p2m3p3m4p4m5"; + Assert.assertEquals(expected, MessageFormatter.format(message, "p1", "p2", "p3", "p4")); + } + + @Test + public void testChain3() { + String message = "{}m1{}m2{}m3{}m4{}m5"; + String expected = "p1m1p2m2p3m3p4m4p5m5"; + Assert.assertEquals(expected, MessageFormatter.format(message, "p1", "p2", "p3", "p4", "p5")); + } + + @Test + public void testChain4() { + String message = "{}m1{}m2{}m3{}m4{}"; + String expected = "p1m1p2m2p3m3p4m4p5"; + Assert.assertEquals(expected, MessageFormatter.format(message, "p1", "p2", "p3", "p4", "p5")); + } + + @Test + public void testTooManyParts() { + String message = "m1{}m2"; + String expected = "m1p1m2"; + Assert.assertEquals(expected, MessageFormatter.format(message, "p1", "p2")); + } + + @Test + public void testTooFewParts() { + String message = "m1{}m2{}"; + String expected = "m1p1m2{}"; + Assert.assertEquals(expected, MessageFormatter.format(message, "p1")); + } +}