All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.bordertech.wcomponents.lde.StandaloneLauncher Maven / Gradle / Ivy

package com.github.bordertech.wcomponents.lde;

import com.github.bordertech.wcomponents.util.Config;
import com.github.bordertech.wcomponents.util.ConfigurationProperties;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.MapConfiguration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * This launcher is intended to be run in a stand-alone environment, i.e. directly From a jar file rather than through
 * an IDE. It provides basic controls to interact with the LDE.
 *
 * @author Yiannis Paschalidis
 * @since 1.0.0
 */
public final class StandaloneLauncher {

	/**
	 * The singleton instance of the StandaloneLauncher UI.
	 */
	private static final StandaloneLauncher INSTANCE = new StandaloneLauncher();

	/**
	 * The WComponent LDE launcher.
	 */
	private final MyLauncher launcher = new MyLauncher();

	/**
	 * This text area is used to display the log output.
	 */
	private final JTextArea log = new JTextArea();

	/**
	 * Creates a StandaloneLauncher.
	 */
	private StandaloneLauncher() {
		final JFrame frame = new JFrame("WComponent stand-alone LDE");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		JPanel content = new JPanel();
		content.setLayout(new BorderLayout());
		frame.setContentPane(content);

		content.add(new JLabel("Log:"), BorderLayout.NORTH);

		log.setColumns(120);
		log.setRows(30);
		log.setFont(new Font("Monospaced", Font.PLAIN, 12));
		content.add(new JScrollPane(log, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
				JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED), BorderLayout.CENTER);

		JPanel buttonPanel = new JPanel();
		buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0));
		content.add(buttonPanel, BorderLayout.SOUTH);

		JButton button = new JButton("Clear log");
		buttonPanel.add(button);
		button.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent event) {
				log.setText("");
			}
		});

		button = new JButton("Launch browser");
		buttonPanel.add(button);
		button.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent event) {
				// Use of reflections here is required as we still need to compile under java 1.5.
				//Desktop.getDesktop().open(index);
				try {
					Class clazz = Class.forName("java.awt.Desktop");
					Object instance = clazz.getMethod("getDesktop").invoke(null);
					clazz.getMethod("browse", URI.class).invoke(instance, new URI(
							getInstance().launcher.getUrl()));
				} catch (ClassNotFoundException e) {
					//Desktop isn't available in Java 1.5, so we'll just use a
					// windows specific cmdline for now
					String cmd = "rundll32 url.dll,FileProtocolHandler "
							+ getInstance().launcher.getUrl();

					try {
						Runtime.getRuntime().exec(cmd);
					} catch (Exception e2) {
						LogFactory.getLog(getClass()).error("Failed to launch browser", e);
					}
				} catch (Exception e) {
					LogFactory.getLog(getClass()).error("Failed to launch browser", e);
				}
			}
		});

		button = new JButton("Exit");
		buttonPanel.add(button);
		button.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent event) {
				// Trigger closing of the frame rather than forcefully terminating the VM.
				// This allows clean-up routines registered in window listeners to run.
				WindowEvent closeEvent = new WindowEvent(frame, WindowEvent.WINDOW_CLOSING);
				Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(closeEvent);
			}
		});

		frame.pack();
		frame.setVisible(true);
	}

	/**
	 * @return the Singleton instance of the StandaloneLauncher.
	 */
	public static StandaloneLauncher getInstance() {
		return INSTANCE;
	}

	/**
	 * Logs a message to the console (text area).
	 *
	 * @param message the message to log.
	 */
	public void log(final String message) {
		if (!SwingUtilities.isEventDispatchThread()) {
			SwingUtilities.invokeLater(new Runnable() {
				@Override
				public void run() {
					log(message);
				}
			});
		} else {
			log.append(message);
		}
	}

	/**
	 * The entry point when the launcher is run as a java application.
	 *
	 * @param args command-line arguments, ignored.
	 * @throws Exception on error
	 */
	public static void main(final String[] args) throws Exception {
		// Set the logger to use the text area logger
		System.setProperty("org.apache.commons.logging.Log",
				"com.github.bordertech.wcomponents.lde.StandaloneLauncher$TextAreaLogger");

		// Set the port number to a random port
		Configuration internalWComponentConfig = Config.getInstance();
		CompositeConfiguration config = new CompositeConfiguration(new MapConfiguration(
				new HashMap()));
		config.addConfiguration(internalWComponentConfig); // Internal WComponent config next
		config.setProperty(ConfigurationProperties.LDE_SERVER_PORT, 0);
		Config.setConfiguration(config);

		getInstance().launcher.run();
		getInstance().log("LDE now running on " + getInstance().launcher.getUrl() + '\n');
	}

	/**
	 * Extension of PlainLauncher to make getUrl() public.
	 */
	public static final class MyLauncher extends PlainLauncher {

		/**
		 * {@inheritDoc}
		 */
		@Override
		public String getUrl() {
			return super.getUrl();
		}
	}

	/**
	 * A commons-logging Log implementation which logs to the StandaloneLauncher log.
	 */
	public static final class TextAreaLogger implements Log {

		/**
		 * The TRACE log-level should be used to output even more fine-grained information than DEBUG.
		 */
		public static final int TRACE = 0;
		/**
		 * The DEBUG log-level should be used for fine-grained information useful for debugging an application.
		 */
		public static final int DEBUG = 1;
		/**
		 * The INFO log-level is used to output application processing at a course level.
		 */
		public static final int INFO = 2;
		/**
		 * The WARN log-level is used to log information about potentially damaging situations.
		 */
		public static final int WARN = 3;
		/**
		 * The ERROR log-level is used to log application errors where the application can recover.
		 */
		public static final int ERROR = 4;
		/**
		 * The FATAL log-level is used to log application errors where the application can not recover.
		 */
		public static final int FATAL = 5;

		/**
		 * The current log level.
		 */
		private int logLevel = DEBUG;

		/**
		 * Creates a TextAreaLogger.
		 *
		 * @param name the logger name.
		 */
		public TextAreaLogger(final String name) {
			// Warning, commons logging requires this (currently unused) constructor.
		}

		/**
		 * Sets the log level.
		 *
		 * @param level the new log level to set.
		 */
		public void setLogLevel(final int level) {
			logLevel = level;
		}

		/**
		 * Logs a message.
		 *
		 * @param message the message to log.
		 * @param throwable the throwable which caused the message to be logged (if applicable).
		 * @param level the logging level to log the message at.
		 */
		private void log(final Object message, final Throwable throwable, final int level) {
			if (level < logLevel) {
				return;
			}

			if (message != null) {
				String prefix = new SimpleDateFormat("dd/MM/yy HH:mm:ss").format(new Date()) + ": ";
				StandaloneLauncher.getInstance().log(prefix + message.toString() + '\n');
			}

			if (throwable != null) {
				StringWriter writer = new StringWriter();
				PrintWriter printWriter = new PrintWriter(writer);
				throwable.printStackTrace(printWriter);
				printWriter.close();

				StandaloneLauncher.getInstance().log(writer.toString());
			}
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void debug(final Object message, final Throwable cause) {
			log(message, cause, DEBUG);
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void debug(final Object message) {
			log(message, null, DEBUG);
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void error(final Object message, final Throwable cause) {
			log(message, cause, ERROR);
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void error(final Object message) {
			log(message, null, ERROR);
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void fatal(final Object message, final Throwable cause) {
			log(message, cause, FATAL);
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void fatal(final Object message) {
			log(message, null, FATAL);
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void info(final Object message, final Throwable cause) {
			log(message, cause, INFO);
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void info(final Object message) {
			log(message, null, INFO);
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void warn(final Object message, final Throwable cause) {
			log(message, cause, WARN);
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void warn(final Object message) {
			log(message, null, WARN);
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public boolean isDebugEnabled() {
			return logLevel <= DEBUG;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public boolean isErrorEnabled() {
			return logLevel <= ERROR;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public boolean isFatalEnabled() {
			return logLevel <= FATAL;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public boolean isInfoEnabled() {
			return logLevel <= INFO;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public boolean isWarnEnabled() {
			return logLevel <= WARN;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public boolean isTraceEnabled() {
			return logLevel <= TRACE;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void trace(final Object message, final Throwable cause) {
			log(message, cause, TRACE);
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void trace(final Object message) {
			log(message, null, TRACE);
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy