From 3721842c8b2ecc09d5d8ae52831786e5df8e0c3f Mon Sep 17 00:00:00 2001 From: huangyuhui Date: Sat, 4 Nov 2017 22:30:38 +0800 Subject: [PATCH] Removed funtionalities of Log4jHandler --- HMCL/build.gradle | 4 +- .../java/org/jackhuang/hmcl/ui/MainFrame.java | 20 ++--- .../org/jackhuang/hmcl/util/Log4jHandler.java | 89 +++---------------- .../org/jackhuang/hmcl/util/StrUtils.java | 4 +- .../jackhuang/hmcl/util/sys/ExitWaiter.java | 79 ++++++++++++++++ .../hmcl/util/sys/ProcessMonitor.java | 53 +---------- 6 files changed, 106 insertions(+), 143 deletions(-) create mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ExitWaiter.java diff --git a/HMCL/build.gradle b/HMCL/build.gradle index 8fa6df987d..be25e3cfe4 100755 --- a/HMCL/build.gradle +++ b/HMCL/build.gradle @@ -38,11 +38,11 @@ def buildnumber = System.getenv("TRAVIS_BUILD_NUMBER") if (buildnumber == null) buildnumber = System.getenv("BUILD_NUMBER") if (buildnumber == null) -buildnumber = "42" +buildnumber = "51" def versionroot = System.getenv("VERSION_ROOT") if (versionroot == null) -versionroot = "2.7.8" +versionroot = "2.7.9" String mavenGroupId = 'HMCL' String mavenVersion = versionroot + '.' + buildnumber diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainFrame.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainFrame.java index bc44bd2ce7..03bca057af 100755 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainFrame.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/MainFrame.java @@ -69,7 +69,6 @@ import org.jackhuang.hmcl.api.ui.Theme; import org.jackhuang.hmcl.api.ui.TopTabPage; - /** * * @author huangyuhui @@ -256,7 +255,7 @@ private void initComponents() { realPanel.setBounds(1, 0, 800, 511); add(realPanel); - + reloadColor(Settings.getInstance().getTheme()); } @@ -396,11 +395,10 @@ private void initBorderColor() { public void reloadColor(Theme t) { if (isShowedMessage) return; - for (Map.Entry entry : t.settings.entrySet()) { + for (Map.Entry entry : t.settings.entrySet()) if (entry.getValue().startsWith("#")) UIManager.put(entry.getKey(), GraphicsUtils.getWebColor(entry.getValue())); - } - + initBorderColor(); if (border != null) border.setColor(borderColor); @@ -423,14 +421,14 @@ private void paintImpl(Graphics g) { @Override public void paint(Graphics g) { - if (!enableShadow) + int off = enableShadow ? 16 : 0; + int width = this.getWidth(); + int height = this.getHeight(); + int contentWidth = width - off - off; + int contentHeight = height - off - off; + if (!enableShadow || contentWidth <= 0 || contentHeight <= 0) paintImpl(g); else { - int off = enableShadow ? 16 : 0; - int width = this.getWidth(); - int height = this.getHeight(); - int contentWidth = width - off - off; - int contentHeight = height - off - off; BufferedImage contentImage = new BufferedImage(contentWidth, contentHeight, Transparency.OPAQUE); Graphics2D contentG2d = contentImage.createGraphics(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/Log4jHandler.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/Log4jHandler.java index 3498f7dd48..b8e532d0fe 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/Log4jHandler.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/Log4jHandler.java @@ -17,9 +17,6 @@ */ package org.jackhuang.hmcl.util; -import java.io.IOException; -import java.io.InterruptedIOException; -import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.text.SimpleDateFormat; import java.util.Date; @@ -27,20 +24,15 @@ import java.util.List; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; -import javax.xml.parsers.ParserConfigurationException; import org.jackhuang.hmcl.api.HMCLApi; -import org.jackhuang.hmcl.api.HMCLog; import org.jackhuang.hmcl.api.event.process.JavaProcessStoppedEvent; import org.jackhuang.hmcl.api.func.Consumer; import org.jackhuang.hmcl.ui.LogWindow; import org.jackhuang.hmcl.util.log.Level; import org.jackhuang.hmcl.util.sys.ProcessMonitor; import org.xml.sax.Attributes; -import org.xml.sax.InputSource; import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; -import org.xml.sax.helpers.XMLReaderFactory; /** * @@ -48,70 +40,28 @@ */ public class Log4jHandler extends Thread implements Consumer { - XMLReader reader; ProcessMonitor monitor; - PipedInputStream inputStream; - PipedOutputStream outputStream; List> forbiddenTokens = new LinkedList<>(); AtomicBoolean interrupted = new AtomicBoolean(false); - ExecutorService executorService = Executors.newSingleThreadExecutor(); boolean enabled = true; - public Log4jHandler(ProcessMonitor monitor, PipedOutputStream outputStream, boolean enabled) throws ParserConfigurationException, IOException, SAXException { - reader = XMLReaderFactory.createXMLReader(); - inputStream = new PipedInputStream(outputStream); - this.outputStream = outputStream; + public Log4jHandler(ProcessMonitor monitor, PipedOutputStream outputStream, boolean enabled) { this.monitor = monitor; this.enabled = enabled; - + HMCLApi.EVENT_BUS.channel(JavaProcessStoppedEvent.class).register((Consumer) this); } - + public void addForbiddenToken(String token, String replacement) { forbiddenTokens.add(new Pair<>(token, replacement)); } @Override public void run() { - try { - setName("log4j-handler"); - if (enabled) - newLogLine(""); - reader.setContentHandler(new Log4jHandlerImpl()); - reader.parse(new InputSource(inputStream)); - } catch (InterruptedIOException e) { - interrupted.set(true); - } catch (SAXException | IOException e) { - throw new Error(e); - } finally { - executorService.shutdown(); - } } @Override public void accept(JavaProcessStoppedEvent t) { - if (!interrupted.get()) - return; - if (t.getSource() == monitor) { - try { - executorService.submit(() -> { - if (!interrupted.get()) { - if (enabled) { - Future f = newLogLine(""); - if (f != null) - f.get(); - } - outputStream.close(); - join(); - } - return null; - }).get(); - } catch (Exception e) { - HMCLog.err("Please contact author", e); - } finally { - executorService.shutdown(); - } - } } /** @@ -126,32 +76,12 @@ public void accept(JavaProcessStoppedEvent t) { * @param content The content to be written to the log */ public Future newLogLine(String content) { - try { - return executorService.submit(() -> { - if (enabled) - try { - String log = content; - if (!log.trim().startsWith("<")) { // without logging configuration. - log = "", "") + "]]>"; - } - outputStream.write(log - .replace("log4j:Event", "log4j_Event") - .replace("log4j:Message", "log4j_Message") - .replace("log4j:Throwable", "log4j_Throwable") - .getBytes()); - outputStream.flush(); - } catch (IOException ignore) { // won't happen - throw new Error(ignore); - } - else - printlnImpl(content, Level.guessLevel(content)); - }); - } catch (RejectedExecutionException e) { - return null; - } + printlnImpl(content, Level.guessLevel(content)); + return null; } class Log4jHandlerImpl extends DefaultHandler { + private final SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss"); String date = "", thread = "", logger = ""; @@ -168,7 +98,7 @@ public void startElement(String uri, String localName, String qName, Attributes date = df.format(d); try { l = Level.valueOf(attributes.getValue("level")); - } catch(IllegalArgumentException e) { + } catch (IllegalArgumentException e) { l = Level.INFO; } thread = attributes.getValue("thread"); @@ -197,7 +127,8 @@ public void endElement(String uri, String localName, String qName) throws SAXExc @Override public void characters(char[] ch, int start, int length) throws SAXException { String line = new String(ch, start, length); - if (line.trim().isEmpty()) return; + if (line.trim().isEmpty()) + return; if (readingMessage) message.append(line).append(C.LINE_SEPARATOR); else @@ -208,7 +139,7 @@ public void println(String message, Level l) { printlnImpl(message, l); } } - + private void printlnImpl(String message, Level l) { for (Pair entry : forbiddenTokens) message = message.replace(entry.key, entry.value); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/StrUtils.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/StrUtils.java index 9aa4c8152f..3eb467a4ec 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/StrUtils.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/StrUtils.java @@ -87,10 +87,10 @@ public static boolean equalsOne(String base, String... a) { return false; } - public static boolean containsOne(List base, List match, Predicate pred) { + public static boolean containsOne(Collection base, String... match) { for (String a : base) for (String b : match) - if (pred.apply(a) && a.toLowerCase().contains(b.toLowerCase())) + if (a.toLowerCase().contains(b.toLowerCase())) return true; return false; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ExitWaiter.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ExitWaiter.java new file mode 100644 index 0000000000..5c2c03329f --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ExitWaiter.java @@ -0,0 +1,79 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2013 huangyuhui + * + * 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 {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.util.sys; + +import java.util.Collection; +import org.jackhuang.hmcl.api.HMCLApi; +import org.jackhuang.hmcl.api.IProcess; +import org.jackhuang.hmcl.api.event.process.JVMLaunchFailedEvent; +import org.jackhuang.hmcl.api.event.process.JavaProcessExitedAbnormallyEvent; +import org.jackhuang.hmcl.api.event.process.JavaProcessStoppedEvent; +import org.jackhuang.hmcl.util.CollectionUtils; +import org.jackhuang.hmcl.util.StrUtils; +import org.jackhuang.hmcl.util.log.Level; + +/** + * + * @author huang + */ +public class ExitWaiter extends Thread { + + private final ProcessMonitor monitor; + private final IProcess process; + private final Runnable callback; + + /** + * Constructor + * @param monitor + * @param callback nullable, will be called when process exited. + */ + public ExitWaiter(ProcessMonitor monitor, Runnable callback) { + this.monitor = monitor; + this.process = monitor.getProcess(); + this.callback = callback; + + setName("exit-waitor"); + } + + @Override + public void run() { + try { + int exitCode = process.getRawProcess().waitFor(); + monitor.errorThread.join(); + monitor.inputThread.join(); + + Collection errorLines = CollectionUtils.filter(process.getStdOutLines(), str -> Level.isError(Level.guessLevel(str))); + + // LaunchWrapper will terminate the application with exit code 0, though this is error state. + if (exitCode != 0 || StrUtils.containsOne(errorLines, "Unable to launch")) + HMCLApi.EVENT_BUS.fireChannel(new JavaProcessExitedAbnormallyEvent(monitor, process)); + else if (exitCode != 0 && StrUtils.containsOne(errorLines, + "Could not create the Java Virtual Machine.", + "Error occurred during initialization of VM", + "A fatal exception has occurred. Program will exit.", + "Unable to launch")) + HMCLApi.EVENT_BUS.fireChannel(new JVMLaunchFailedEvent(monitor, process)); + else + HMCLApi.EVENT_BUS.fireChannel(new JavaProcessStoppedEvent(this, process)); + + if (callback != null) + callback.run(); + } catch (InterruptedException ex) { + } + } +} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessMonitor.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessMonitor.java index 42de0e74a4..771f548244 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessMonitor.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessMonitor.java @@ -17,19 +17,11 @@ */ package org.jackhuang.hmcl.util.sys; -import java.util.Arrays; import java.util.HashSet; import java.util.concurrent.CountDownLatch; import org.jackhuang.hmcl.api.HMCLApi; -import org.jackhuang.hmcl.api.event.process.JVMLaunchFailedEvent; -import org.jackhuang.hmcl.api.event.process.JavaProcessExitedAbnormallyEvent; import org.jackhuang.hmcl.api.event.process.JavaProcessStartingEvent; -import org.jackhuang.hmcl.api.event.process.JavaProcessStoppedEvent; -import org.jackhuang.hmcl.util.StrUtils; -import org.jackhuang.hmcl.api.HMCLog; -import org.jackhuang.hmcl.util.log.Level; import org.jackhuang.hmcl.api.IProcess; -import org.jackhuang.hmcl.api.event.SimpleEvent; import org.jackhuang.hmcl.api.func.Consumer; /** @@ -43,6 +35,7 @@ public class ProcessMonitor { private final CountDownLatch latch = new CountDownLatch(2); ProcessThread inputThread; ProcessThread errorThread; + ExitWaiter waitorThread; WaitForThread waitForThread; private final IProcess p; @@ -50,9 +43,7 @@ public ProcessMonitor(IProcess p) { this.p = p; inputThread = new ProcessThread(this, false); errorThread = new ProcessThread(this, true); - inputThread.stopEvent.register(this::threadStopped); - inputThread.stopEvent.register(event -> processThreadStopped((ProcessThread) event.getSource())); - errorThread.stopEvent.register(this::threadStopped); + waitorThread = new ExitWaiter(this, this::processThreadStopped); } public IProcess getProcess() { @@ -75,51 +66,14 @@ public void registerPrintlnEvent(Consumer c) { } public void start() { - hasFired = false; MONITORS.add(this); HMCLApi.EVENT_BUS.fireChannel(new JavaProcessStartingEvent(this, p)); inputThread.start(); errorThread.start(); } - private void threadStopped(SimpleEvent event) { - latch.countDown(); - ProcessThread t = (ProcessThread) event.getSource(); - int exitCode = Integer.MAX_VALUE; - try { - exitCode = p.getExitCode(); - } catch(IllegalThreadStateException e) { - HMCLog.err("Failed to get exit code ", e); - } - if (p.getExitCode() != 0 || StrUtils.containsOne(t.getLines(), - Arrays.asList("Unable to launch"), // LaunchWrapper will terminate the application returning exit code 0, but this is an error state. - x -> Level.isError(Level.guessLevel(x)))) - synchronized (this) { - if (!hasFired) { - hasFired = true; - HMCLApi.EVENT_BUS.fireChannel(new JavaProcessExitedAbnormallyEvent(ProcessMonitor.this, p)); - } - } - if (p.getExitCode() != 0 && StrUtils.containsOne(t.getLines(), - Arrays.asList("Could not create the Java Virtual Machine.", - "Error occurred during initialization of VM", - "A fatal exception has occurred. Program will exit.", - "Unable to launch"), - x -> Level.isError(Level.guessLevel(x)))) - synchronized (this) { - if (!hasFired) { - hasFired = true; - HMCLApi.EVENT_BUS.fireChannel(new JVMLaunchFailedEvent(ProcessMonitor.this, p)); - } - } - } - - boolean hasFired = false; - - private void processThreadStopped(ProcessThread t1) { + private void processThreadStopped() { MONITORS.remove(this); - errorThread.interrupt(); - HMCLApi.EVENT_BUS.fireChannel(new JavaProcessStoppedEvent(this, p)); } public static void stopAll() { @@ -127,6 +81,7 @@ public static void stopAll() { monitor.getProcess().getRawProcess().destroy(); monitor.inputThread.interrupt(); monitor.errorThread.interrupt(); + monitor.waitorThread.interrupt(); } }