/*
* eXist Open Source Native XML Database
* Copyright (C) 2012-2015 The eXist-db Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
package org.exist.launcher;
import org.apache.commons.configuration2.MapConfiguration;
import org.apache.commons.lang3.SystemUtils;
import org.exist.EXistException;
import org.exist.jetty.JettyStart;
import org.exist.repo.ExistRepository;
import org.exist.security.PermissionDeniedException;
import org.exist.start.Main;
import org.exist.storage.BrokerPool;
import org.exist.storage.DBBroker;
import org.exist.util.ConfigurationHelper;
import org.exist.util.FileUtils;
import org.exist.util.SystemExitCodes;
import org.exist.xquery.XPathException;
import org.exist.xquery.XQuery;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.SequenceIterator;
import org.rzo.yajsw.wrapper.WrappedService;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.Timer;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
/**
* A launcher for the eXist-db server integrated with the desktop.
* Shows a splash screen during startup and registers a tray icon
* in the system bar.
*
* @author Wolfgang Meier
*/
public class Launcher extends Observable implements Observer {
private MenuItem stopItem;
private MenuItem startItem;
private MenuItem dashboardItem;
private MenuItem eXideItem;
private MenuItem monexItem;
private MenuItem installServiceItem;
private MenuItem uninstallServiceItem;
private MenuItem showServices;
private MenuItem quitItem;
public final static String PACKAGE_DASHBOARD = "http://exist-db.org/apps/dashboard";
public final static String PACKAGE_EXIDE = "http://exist-db.org/apps/eXide";
public final static String PACKAGE_MONEX = "http://exist-db.org/apps/monex";
public static void main(final String[] args) {
final String os = System.getProperty("os.name", "");
// Switch to native look and feel except for Linux (ugly)
if (!"Linux".equals(os)) {
final String nativeLF = UIManager.getSystemLookAndFeelClassName();
try {
UIManager.setLookAndFeel(nativeLF);
} catch (final Exception e) {
// can be safely ignored
}
}
/* Turn off metal's use of bold fonts */
//UIManager.put("swing.boldMetal", Boolean.FALSE);
//Schedule a job for the event-dispatching thread:
SwingUtilities.invokeLater(() -> new Launcher(args));
}
private SystemTray tray = null;
private TrayIcon trayIcon = null;
private Optional<WrappedService> runningAsService;
private SplashScreen splash;
private Optional<JettyStart> jetty = Optional.empty();
private final Path jettyConfig;
private Properties wrapperProperties;
private boolean inServiceInstall = false;
private UtilityPanel utilityPanel;
private ConfigurationDialog configDialog;
private boolean canUseServices = false;
public Launcher(final String[] args) {
if (SystemTray.isSupported()) {
tray = SystemTray.getSystemTray();
}
captureConsole();
this.jettyConfig = getJettyConfig();
final Optional<Path> eXistHome = ConfigurationHelper.getExistHome();
final Path wrapperConfig;
if (eXistHome.isPresent()) {
wrapperConfig = eXistHome.get().resolve("tools/yajsw/conf/wrapper.conf");
} else {
wrapperConfig = Paths.get("tools/yajsw/conf/wrapper.conf");
}
wrapperProperties = new Properties();
wrapperProperties.setProperty("wrapper.working.dir", eXistHome.orElse(Paths.get(".")).toString());
wrapperProperties.setProperty("wrapper.config", wrapperConfig.toString());
System.setProperty("wrapper.config", wrapperConfig.toString());
installedAsService();
boolean initSystemTray = true;
if (isSystemTraySupported()) {
initSystemTray = initSystemTray();
}
configDialog = new ConfigurationDialog(this::shutdown);
splash = new SplashScreen(this);
splash.addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(WindowEvent windowEvent) {
setServiceState();
if (runningAsService.isPresent()) {
splash.setStatus("eXist-db is already installed as service! Attaching to it ...");
final Timer timer = new Timer(3000, (event) -> splash.setVisible(false));
timer.setRepeats(false);
timer.start();
} else {
if (ConfigurationUtility.isFirstStart()) {
splash.setVisible(false);
configDialog.open(true);
configDialog.requestFocus();
} else {
startJetty();
}
}
}
});
final boolean systemTrayReady = tray != null && initSystemTray && tray.getTrayIcons().length > 0;
SwingUtilities.invokeLater(() -> utilityPanel = new UtilityPanel(Launcher.this, systemTrayReady));
}
protected void startJetty() {
new Thread() {
@Override
public void run() {
try {
if (!jetty.isPresent()) {
jetty = Optional.of(new JettyStart());
jetty.get().run(new String[]{jettyConfig.toAbsolutePath().toString()}, splash);
}
} catch (final Exception e) {
showMessageAndExit("Error Occurred", "An error occurred during eXist-db startup. Please check console output and logs.", true);
System.exit(SystemExitCodes.CATCH_ALL_GENERAL_ERROR_EXIT_CODE);
}
}
}.start();
}
public boolean isSystemTraySupported() {
return tray != null;
}
private boolean initSystemTray() {
final Dimension iconDim = tray.getTrayIconSize();
BufferedImage image = null;
try {
image = ImageIO.read(getClass().getResource("icon32.png"));
} catch (final IOException e) {
showMessageAndExit("Launcher failed", "Failed to read system tray icon.", false);
}
trayIcon = new TrayIcon(image.getScaledInstance(iconDim.width, iconDim.height, Image.SCALE_SMOOTH), "eXist-db Launcher");
final JDialog hiddenFrame = new JDialog();
hiddenFrame.setUndecorated(true);
hiddenFrame.setIconImage(image);
final PopupMenu popup = createMenu();
trayIcon.setPopupMenu(popup);
trayIcon.addActionListener(actionEvent -> {
trayIcon.displayMessage(null, "Right click for menu", TrayIcon.MessageType.INFO);
setServiceState();
}
);
// add listener for left click on system tray icon. doesn't work well on linux though.
if (!SystemUtils.IS_OS_LINUX) {
trayIcon.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent mouseEvent) {
if (mouseEvent.getButton() == MouseEvent.BUTTON1) {
setServiceState();
hiddenFrame.add(popup);
popup.show(hiddenFrame, mouseEvent.getXOnScreen(), mouseEvent.getYOnScreen());
}
}
});
}
try {
hiddenFrame.setResizable(false);
hiddenFrame.pack();
hiddenFrame.setVisible(true);
tray.add(trayIcon);
} catch (final AWTException e) {
return false;
}
return true;
}
private PopupMenu createMenu() {
final PopupMenu popup = new PopupMenu();
startItem = new MenuItem("Start server");
popup.add(startItem);
startItem.addActionListener(actionEvent -> {
if (jetty.isPresent()) {
jetty.ifPresent(server -> {
if (server.isStarted()) {
showTrayMessage("Server already started", TrayIcon.MessageType.WARNING);
} else {
server.run(new String[]{jettyConfig.toAbsolutePath().toString()}, null);
if (server.isStarted()) {
showTrayMessage("eXist-db server running on port " + server.getPrimaryPort(), TrayIcon
.MessageType.INFO);
}
}
setServiceState();
});
} else if (runningAsService.isPresent()){
showTrayMessage("Starting the eXistdb service. Please wait...", TrayIcon.MessageType.INFO);
if (runningAsService.get().start()) {
showTrayMessage("eXistdb service started", TrayIcon.MessageType.INFO);
} else {
showTrayMessage("Starting eXistdb service failed", TrayIcon.MessageType.ERROR);
}
setServiceState();
}
});
stopItem = new MenuItem("Stop server");
popup.add(stopItem);
stopItem.addActionListener(actionEvent -> {
if (jetty.isPresent()) {
jetty.get().shutdown();
setServiceState();
showTrayMessage("eXist-db stopped", TrayIcon.MessageType.INFO);
} else if (runningAsService.isPresent()) {
if (runningAsService.get().stop()) {
showTrayMessage("eXistdb service stopped", TrayIcon.MessageType.INFO);
} else {
showTrayMessage("Stopping eXistdb service failed", TrayIcon.MessageType.ERROR);
}
setServiceState();
}
});
popup.addSeparator();
final MenuItem configItem = new MenuItem("System Configuration");
popup.add(configItem);
configItem.addActionListener(e -> EventQueue.invokeLater(() -> {
configDialog.open(false);
configDialog.toFront();
configDialog.repaint();
configDialog.requestFocus();
}));
if (SystemUtils.IS_OS_WINDOWS) {
canUseServices = true;
} else {
isRoot((root) -> canUseServices = root);
}
final String requiresRootMsg;
if (canUseServices) {
requiresRootMsg = "";
} else {
requiresRootMsg = " (requires root)";
}
installServiceItem = new MenuItem("Install as service" + requiresRootMsg);
popup.add(installServiceItem);
installServiceItem.setEnabled(canUseServices);
installServiceItem.addActionListener(e -> SwingUtilities.invokeLater(this::installAsService));
uninstallServiceItem = new MenuItem("Uninstall service" + requiresRootMsg);
popup.add(uninstallServiceItem);
uninstallServiceItem.setEnabled(canUseServices);
uninstallServiceItem.addActionListener(e -> SwingUtilities.invokeLater(this::uninstallService));
if (SystemUtils.IS_OS_WINDOWS) {
showServices = new MenuItem("Show services console");
popup.add(showServices);
showServices.addActionListener(e -> SwingUtilities.invokeLater(this::showServicesConsole));
}
popup.addSeparator();
final MenuItem toolbar = new MenuItem("Show tool window");
popup.add(toolbar);
toolbar.addActionListener(actionEvent -> EventQueue.invokeLater(() -> {
utilityPanel.toFront();
utilityPanel.setVisible(true);
}));
MenuItem item;
if (Desktop.isDesktopSupported()) {
popup.addSeparator();
final Desktop desktop = Desktop.getDesktop();
if (desktop.isSupported(Desktop.Action.BROWSE)) {
dashboardItem = new MenuItem("Open Dashboard");
popup.add(dashboardItem);
dashboardItem.addActionListener(actionEvent -> dashboard(desktop));
eXideItem = new MenuItem("Open eXide");
popup.add(eXideItem);
eXideItem.addActionListener(actionEvent -> eXide(desktop));
item = new MenuItem("Open Java Admin Client");
popup.add(item);
item.addActionListener(actionEvent -> client());
monexItem = new MenuItem("Open Monitoring and Profiling");
popup.add(monexItem);
monexItem.addActionListener(actionEvent -> monex(desktop));
}
if (desktop.isSupported(Desktop.Action.OPEN)) {
popup.addSeparator();
item = new MenuItem("Open exist.log");
popup.add(item);
item.addActionListener(new LogActionListener());
}
popup.addSeparator();
quitItem = new MenuItem("Quit (and stop server)");
popup.add(quitItem);
quitItem.addActionListener(actionEvent -> shutdown(false));
setServiceState();
}
return popup;
}
protected void installAsService() {
jetty.ifPresent(server -> {
if (server.isStarted()) {
showTrayMessage("Stopping eXistdb...", TrayIcon.MessageType.INFO);
server.shutdown();
}
});
jetty = Optional.empty();
showTrayMessage("Installing service and starting eXistdb ...", TrayIcon.MessageType.INFO);
final WrappedService service = new WrappedService();
service.setLocalConfiguration(new MapConfiguration(wrapperProperties));
service.init();
final boolean installed = service.install();
if (installed) {
if (SystemUtils.IS_OS_WINDOWS) {
service.start();
}
runningAsService = Optional.of(service);
setServiceState();
showTrayMessage("Service installed and started", TrayIcon.MessageType.INFO);
} else {
JOptionPane.showMessageDialog(null, "Failed to install service. ", "Install Service Failed", JOptionPane
.ERROR_MESSAGE);
runningAsService = Optional.empty();
}
inServiceInstall = false;
}
protected void uninstallService() {
if (runningAsService.isPresent()) {
final boolean uninstalled = runningAsService.get().uninstall();
if (uninstalled) {
showTrayMessage("Service removed and db stopped", TrayIcon.MessageType.INFO);
runningAsService = Optional.empty();
} else {
JOptionPane.showMessageDialog(null, "Removing the service failed.", "Removing Service Failed", JOptionPane.ERROR_MESSAGE);
}
setServiceState();
}
}
private void setServiceState() {
if (runningAsService.isPresent()) {
final WrappedService service = runningAsService.get();
final boolean serverRunning = service.isRunning() || service.isStarting();
if (canUseServices) {
final boolean serviceInstalled = service.isInstalled();
if (installServiceItem != null && uninstallServiceItem != null) {
installServiceItem.setEnabled(!serviceInstalled);
uninstallServiceItem.setEnabled(serviceInstalled);
}
}
quitItem.setLabel("Quit");
stopItem.setEnabled(serverRunning);
startItem.setEnabled(!serverRunning);
if (dashboardItem != null) {
dashboardItem.setEnabled(serverRunning);
monexItem.setEnabled(serverRunning);
eXideItem.setEnabled(serverRunning);
}
} else {
final boolean serverRunning = jetty.isPresent() && jetty.get().isStarted();
if (canUseServices) {
if (installServiceItem != null && uninstallServiceItem != null) {
installServiceItem.setEnabled(true);
uninstallServiceItem.setEnabled(false);
}
}
quitItem.setLabel("Quit (and stop server)");
stopItem.setEnabled(serverRunning);
startItem.setEnabled(!serverRunning);
if (dashboardItem != null) {
dashboardItem.setEnabled(serverRunning);
monexItem.setEnabled(serverRunning);
eXideItem.setEnabled(serverRunning);
}
}
}
private void isRoot(Consumer<Boolean> consumer) {
final List<String> args = new ArrayList<>(2);
args.add("id");
args.add("-u");
run(args, (code, output) -> {
consumer.accept("0".equals(output.trim()));
});
}
private void showServicesConsole() {
final List<String> args = new ArrayList<>(2);
args.add("cmd");
args.add("/c");
args.add("services.msc");
run(args, null);
}
protected static void run(List<String> args, BiConsumer<Integer, String> consumer) {
final ProcessBuilder pb = new ProcessBuilder(args);
final Optional<Path> home = ConfigurationHelper.getExistHome();
if (home.isPresent()) {
pb.directory(home.get().toFile());
}
pb.redirectErrorStream(true);
try {
final Process process = pb.start();
if (consumer != null) {
final StringBuilder output = new StringBuilder();
try (final BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(),
"UTF-8"))) {
String line;
while ((line = reader.readLine()) != null) {
output.append('\n').append(line);
}
}
final int exitValue = process.waitFor();
consumer.accept(exitValue, output.toString());
}
} catch (IOException | InterruptedException e) {
JOptionPane.showMessageDialog(null, e.getMessage(), "Error Running Process", JOptionPane.ERROR_MESSAGE);
}
}
protected void shutdown(final boolean restart) {
utilityPanel.setStatus("Shutting down ...");
SwingUtilities.invokeLater(() -> {
if (restart && runningAsService.isPresent()) {
final WrappedService service = runningAsService.get();
if (service.isRunning() || service.isStarting()) {
if (service.stop()) {
while (service.isRunning()) {
try {
wait(500);
} catch (InterruptedException e) {
break;
}
}
if (!service.isRunning() && service.start()) {
trayIcon.displayMessage(null, "Database restarted", TrayIcon.MessageType.INFO);
} else {
trayIcon.displayMessage(null, "Failed to restart. Please start service manually.", TrayIcon.MessageType.INFO);
}
}
}
} else {
if (tray != null) {
tray.remove(trayIcon);
}
if (jetty.isPresent()) {
jetty.get().shutdown();
if (restart) {
final LauncherWrapper wrapper = new LauncherWrapper(Launcher.class.getName());
wrapper.launch();
}
}
System.exit(SystemExitCodes.OK_EXIT_CODE);
}
});
}
protected void dashboard(Desktop desktop) {
utilityPanel.setStatus("Opening dashboard in browser ...");
final int port = jetty.isPresent() ? jetty.get().getPrimaryPort() : 8080;
try {
final URI url = new URI("http://localhost:" + port + "/exist/apps/dashboard/");
desktop.browse(url);
} catch (final URISyntaxException e) {
if (isSystemTraySupported())
{trayIcon.displayMessage(null, "Failed to open URL", TrayIcon.MessageType.ERROR);}
utilityPanel.setStatus("Unable to launch browser");
} catch (final IOException e) {
if (isSystemTraySupported())
{trayIcon.displayMessage(null, "Failed to open URL", TrayIcon.MessageType.ERROR);}
utilityPanel.setStatus("Unable to launch browser");
}
}
protected void eXide(Desktop desktop) {
utilityPanel.setStatus("Opening dashboard in browser ...");
final int port = jetty.isPresent() ? jetty.get().getPrimaryPort() : 8080;
try {
final URI url = new URI("http://localhost:" + port + "/exist/apps/eXide/");
desktop.browse(url);
} catch (final URISyntaxException e) {
if (isSystemTraySupported())
{trayIcon.displayMessage(null, "Failed to open URL", TrayIcon.MessageType.ERROR);}
utilityPanel.setStatus("Unable to launch browser");
} catch (final IOException e) {
if (isSystemTraySupported())
{trayIcon.displayMessage(null, "Failed to open URL", TrayIcon.MessageType.ERROR);}
utilityPanel.setStatus("Unable to launch browser");
}
}
protected void monex(Desktop desktop) {
utilityPanel.setStatus("Opening Monitoring and Profiling in browser ...");
final int port = jetty.isPresent() ? jetty.get().getPrimaryPort() : 8080;
try {
final URI url = new URI("http://localhost:" + port + "/exist/apps/monex/");
desktop.browse(url);
} catch (final URISyntaxException e) {
if (isSystemTraySupported())
{trayIcon.displayMessage(null, "Failed to open URL", TrayIcon.MessageType.ERROR);}
utilityPanel.setStatus("Unable to launch browser");
} catch (final IOException e) {
if (isSystemTraySupported())
{trayIcon.displayMessage(null, "Failed to open URL", TrayIcon.MessageType.ERROR);}
utilityPanel.setStatus("Unable to launch browser");
}
}
protected void client() {
final LauncherWrapper wrapper = new LauncherWrapper("client");
wrapper.launch();
}
protected void signalStarted() {
if (isSystemTraySupported()) {
final int port = jetty.isPresent() ? jetty.get().getPrimaryPort() : 8080;
trayIcon.setToolTip("eXist-db server running on port " + port);
startItem.setEnabled(false);
stopItem.setEnabled(true);
checkInstalledApps();
registerObserver();
}
if (!inServiceInstall && !runningAsService.isPresent() && SystemUtils.IS_OS_WINDOWS) {
inServiceInstall = true;
SwingUtilities.invokeLater(() -> {
if (JOptionPane.showConfirmDialog(splash, "It is recommended to run eXist as a service on " +
"Windows.\nNot doing so may lead to data loss if you shut down the computer before " +
"eXist.\n\nWould you like to install the service?", "Install as Service?",
JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
installAsService();
}
});
}
}
protected void signalShutdown() {
if (isSystemTraySupported()) {
trayIcon.setToolTip("eXist-db server stopped");
if (!inServiceInstall) {
startItem.setEnabled(true);
stopItem.setEnabled(false);
}
}
}
private void checkInstalledApps() {
try {
final BrokerPool pool = BrokerPool.getInstance();
try (final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
final XQuery xquery = pool.getXQueryService();
final Sequence pkgs = xquery.execute(broker, "repo:list()", null);
for (final SequenceIterator i = pkgs.iterate(); i.hasNext(); ) {
final ExistRepository.Notification notification = new ExistRepository.Notification(ExistRepository.Action.INSTALL, i.nextItem().getStringValue());
Optional<ExistRepository> expathRepo = pool.getExpathRepo();
if (expathRepo.isPresent()) {
update(expathRepo.get(), notification);
utilityPanel.update(expathRepo.get(), notification);
}
expathRepo.orElseThrow(() -> new XPathException("expath repository is not available."));
}
}
} catch (final EXistException e) {
System.err.println("Failed to check installed packages: " + e.getMessage());
e.printStackTrace();
} catch (final XPathException e) {
System.err.println("Failed to check installed packages: " + e.getMessage());
e.printStackTrace();
} catch (final PermissionDeniedException e) {
System.err.println("Failed to check installed packages: " + e.getMessage());
e.printStackTrace();
}
}
private void registerObserver() {
try {
final BrokerPool pool = BrokerPool.getInstance();
Optional<ExistRepository> repo = pool.getExpathRepo();
if (repo.isPresent()) {
repo.get().addObserver(this);
repo.get().addObserver(utilityPanel);
} else {
System.err.println("expath repository is not available.");
}
} catch (final EXistException e) {
System.err.println("Failed to register as observer for package manager events");
e.printStackTrace();
}
}
@Override
public void update(Observable observable, Object o) {
final ExistRepository.Notification notification = (ExistRepository.Notification) o;
if (notification.getPackageURI().equals(PACKAGE_DASHBOARD) && dashboardItem != null) {
dashboardItem.setEnabled(notification.getAction() == ExistRepository.Action.INSTALL);
} else if (notification.getPackageURI().equals(PACKAGE_EXIDE) && eXideItem != null) {
eXideItem.setEnabled(notification.getAction() == ExistRepository.Action.INSTALL);
} else if (notification.getPackageURI().equals(PACKAGE_MONEX) && monexItem != null) {
monexItem.setEnabled(notification.getAction() == ExistRepository.Action.INSTALL);
}
}
private Path getJettyConfig() {
final String jettyProperty = Optional.ofNullable(System.getProperty("jetty.home"))
.orElseGet(() -> {
final Optional<Path> home = ConfigurationHelper.getExistHome();
final Path jettyHome = FileUtils.resolve(home, "tools").resolve("jetty");
final String jettyPath = jettyHome.toAbsolutePath().toString();
System.setProperty("jetty.home", jettyPath);
return jettyPath;
});
return Paths.get(jettyProperty)
.normalize()
.resolve("etc")
.resolve(Main.STANDARD_ENABLED_JETTY_CONFIGS);
}
protected void showMessageAndExit(String title, String message, boolean logs) {
final JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
final JLabel label = new JLabel(message);
label.setHorizontalAlignment(SwingConstants.CENTER);
panel.add(label, BorderLayout.CENTER);
if (logs) {
final JButton displayLogs = new JButton("View Log");
displayLogs.addActionListener(new LogActionListener());
label.setHorizontalAlignment(SwingConstants.CENTER);
panel.add(displayLogs, BorderLayout.SOUTH);
}
utilityPanel.showMessages();
utilityPanel.toFront();
utilityPanel.setVisible(true);
JOptionPane.showMessageDialog(splash, panel, title, JOptionPane.WARNING_MESSAGE);
//System.exit(SystemExitCodes.CATCH_ALL_GENERAL_ERROR_EXIT_CODE);
}
protected void showTrayMessage(String message, TrayIcon.MessageType type) {
if (isSystemTraySupported()) {
trayIcon.displayMessage(message, message, type);
}
}
private void installedAsService() {
final WrappedService service = new WrappedService();
service.setLocalConfiguration(new MapConfiguration(wrapperProperties));
service.init();
if (service.isInstalled()) {
runningAsService = Optional.of(service);
} else {
runningAsService = Optional.empty();
}
}
/**
* Ensure that stdout and stderr messages are also printed
* to the logs.
*/
private void captureConsole() {
System.setOut(createLoggingProxy(System.out));
System.setErr(createLoggingProxy(System.err));
}
public PrintStream createLoggingProxy(final PrintStream realStream) {
final OutputStream out = new OutputStream() {
@Override
public void write(int i) throws IOException {
realStream.write(i);
String s = String.valueOf((char) i);
Launcher.this.setChanged();
Launcher.this.notifyObservers(s);
}
@Override
public void write(byte[] bytes) throws IOException {
realStream.write(bytes);
String s = new String(bytes);
Launcher.this.setChanged();
Launcher.this.notifyObservers(s);
}
@Override
public void write(byte[] bytes, int offset, int len) throws IOException {
realStream.write(bytes, offset, len);
String s = new String(bytes, offset, len);
Launcher.this.setChanged();
Launcher.this.notifyObservers(s);
}
};
return new PrintStream(out);
}
private class LogActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent actionEvent) {
if (!Desktop.isDesktopSupported())
{return;}
final Desktop desktop = Desktop.getDesktop();
final Optional<Path> home = ConfigurationHelper.getExistHome();
final Path logFile = FileUtils.resolve(home, "webapp/WEB-INF/logs/exist.log");
if (!Files.isReadable(logFile)) {
trayIcon.displayMessage(null, "Log file not found", TrayIcon.MessageType.ERROR);
} else {
try {
desktop.open(logFile.toFile());
} catch (final IOException e) {
trayIcon.displayMessage(null, "Failed to open log file", TrayIcon.MessageType.ERROR);
}
}
}
}
}