001: /*
002: * $Id: ConsoleGUI.java,v 1.9 2007/09/18 08:45:08 agoubard Exp $
003: *
004: * Copyright 2003-2007 Orange Nederland Breedband B.V.
005: * See the COPYRIGHT file for redistribution and use restrictions.
006: */
007: package org.xins.common.servlet.container;
008:
009: import java.awt.BorderLayout;
010: import java.awt.Color;
011: import java.awt.Dimension;
012: import java.awt.Toolkit;
013: import java.awt.event.ActionEvent;
014: import java.awt.event.InputEvent;
015: import java.awt.event.KeyEvent;
016: import java.io.BufferedReader;
017: import java.io.IOException;
018: import java.io.InputStreamReader;
019: import java.io.PipedInputStream;
020: import java.io.PipedOutputStream;
021: import java.io.PrintStream;
022: import java.net.URI;
023: import java.net.URL;
024: import java.util.regex.Pattern;
025: import javax.swing.*;
026: import javax.swing.text.BadLocationException;
027: import javax.swing.text.Style;
028: import javax.swing.text.StyleConstants;
029:
030: /**
031: * Graphical user interface for the Servlet container.
032: * This class may move to another package.
033: *
034: * @version $Revision: 1.9 $ $Date: 2007/09/18 08:45:08 $
035: * @author <a href="mailto:anthony.goubard@japplis.com">Anthony Goubard</a>
036: *
037: * @since XINS 2.1
038: */
039: public class ConsoleGUI {
040:
041: private JPanel consolePanel;
042:
043: private JTextPane console;
044:
045: private JMenuBar consoleMenuBar;
046:
047: private Style[] logStyles;
048:
049: private int logLevel = 0;
050:
051: private Pattern patternFilter = null;
052:
053: private String logFilter = null;
054:
055: /**
056: * Constructs a new <code>ConsoleGUI</code>.
057: *
058: * @param mainFrame
059: * the main frame or <code>null</code> if no frame is available.
060: *
061: * @param cmdArgs
062: * the command line arguments, cannot be <code>null</code>.
063: */
064: public ConsoleGUI(JFrame mainFrame, CommandLineArguments cmdArgs) {
065: initUI(mainFrame, cmdArgs);
066: initData();
067: }
068:
069: /**
070: * Creates the user interface.
071: * This method also creates the actions available in the menu.
072: *
073: * @param mainFrame
074: * the main frame or <code>null</code> if no frame is available.
075: *
076: * @param cmdArgs
077: * the command line arguments, cannot be <code>null</code>.
078: */
079: protected void initUI(final JFrame mainFrame,
080: final CommandLineArguments cmdArgs) {
081: consolePanel = new JPanel();
082: console = new JTextPane();
083: console.setPreferredSize(new Dimension(700, 400));
084: consolePanel.setLayout(new BorderLayout(5, 5));
085: consolePanel.add(new JScrollPane(console), BorderLayout.CENTER);
086:
087: consoleMenuBar = new JMenuBar();
088:
089: // Add the actions
090: JMenu consoleMenu = new JMenu("Console");
091: consoleMenu.setMnemonic('c');
092: Action showSpec = new AbstractAction("Specifications") {
093: public void actionPerformed(ActionEvent ae) {
094: try {
095: ClassLoader loader = ServletClassLoader
096: .getServletClassLoader(
097: cmdArgs.getWarFile(), cmdArgs
098: .getLoaderMode());
099:
100: loader.loadClass("org.xins.common.spec.SpecGUI")
101: .newInstance();
102: } catch (Exception ex) {
103: ex.printStackTrace();
104: }
105: }
106: };
107: showSpec.putValue(Action.MNEMONIC_KEY, new Integer(
108: KeyEvent.VK_S));
109: consoleMenu.add(showSpec);
110: Action clearAction = new AbstractAction("Clear") {
111: public void actionPerformed(ActionEvent ae) {
112: console.setText("");
113: }
114: };
115: consoleMenu.add(clearAction);
116: consoleMenu.addSeparator();
117: Action exitAction = new AbstractAction("Exit") {
118: public void actionPerformed(ActionEvent ae) {
119: System.exit(0);
120: }
121: };
122: exitAction.putValue(Action.ACCELERATOR_KEY, KeyStroke
123: .getKeyStroke(KeyEvent.VK_F4, InputEvent.ALT_MASK));
124: consoleMenu.add(exitAction);
125:
126: JMenu logLevelMenu = new JMenu("Log level");
127: logLevelMenu.setMnemonic('l');
128: JCheckBoxMenuItem debugMenu = new JCheckBoxMenuItem(
129: new ChangeLogLevel(0, "Debug"));
130: debugMenu.setSelected(true);
131: JCheckBoxMenuItem infoMenu = new JCheckBoxMenuItem(
132: new ChangeLogLevel(1, "Info"));
133: JCheckBoxMenuItem noticeMenu = new JCheckBoxMenuItem(
134: new ChangeLogLevel(2, "Notice"));
135: JCheckBoxMenuItem warningMenu = new JCheckBoxMenuItem(
136: new ChangeLogLevel(3, "Warning"));
137: JCheckBoxMenuItem errorMenu = new JCheckBoxMenuItem(
138: new ChangeLogLevel(4, "Error"));
139: JCheckBoxMenuItem fatalMenu = new JCheckBoxMenuItem(
140: new ChangeLogLevel(5, "Fatal"));
141: ButtonGroup logLevelGroup = new ButtonGroup();
142: logLevelGroup.add(debugMenu);
143: logLevelGroup.add(infoMenu);
144: logLevelGroup.add(noticeMenu);
145: logLevelGroup.add(warningMenu);
146: logLevelGroup.add(errorMenu);
147: logLevelGroup.add(fatalMenu);
148: logLevelMenu.add(debugMenu);
149: logLevelMenu.add(infoMenu);
150: logLevelMenu.add(noticeMenu);
151: logLevelMenu.add(warningMenu);
152: logLevelMenu.add(errorMenu);
153: logLevelMenu.add(fatalMenu);
154: Action regexpFilterAction = new AbstractAction("Filter") {
155: public void actionPerformed(ActionEvent ae) {
156: String pattern = (String) JOptionPane.showInputDialog(
157: mainFrame,
158: "Please regular expression to match",
159: "Log Filter", JOptionPane.QUESTION_MESSAGE,
160: null, null, logFilter);
161: if ("".equals(pattern)) {
162: logFilter = null;
163: patternFilter = null;
164: } else if (pattern != null) {
165: logFilter = pattern;
166: patternFilter = Pattern.compile(logFilter);
167: }
168: }
169: };
170: logLevelMenu.add(regexpFilterAction);
171:
172: JMenu helpMenu = new JMenu("Help");
173: helpMenu.setMnemonic('h');
174: String javaVersion = System.getProperty("java.version");
175: if (javaVersion.startsWith("1.6")
176: || javaVersion.startsWith("1.7")) {
177: helpMenu.add(new BrowseAction("XINS Web site",
178: "http://www.xins.org/"));
179: helpMenu.add(new BrowseAction("User Guide",
180: "http://www.xins.org/docs/"));
181: helpMenu.addSeparator();
182: }
183: Action aboutAction = new AbstractAction("About") {
184: public void actionPerformed(ActionEvent ae) {
185: Object[] aboutMessage = { "XINS",
186: "http://www.xins.org/" };
187:
188: JOptionPane optionPane = new JOptionPane();
189: optionPane.setMessage(aboutMessage);
190: optionPane
191: .setMessageType(JOptionPane.INFORMATION_MESSAGE);
192: JDialog dialog = optionPane.createDialog(mainFrame,
193: "About");
194: dialog.setVisible(true);
195: }
196: };
197: helpMenu.add(aboutAction);
198: consoleMenuBar.add(consoleMenu);
199: consoleMenuBar.add(logLevelMenu);
200: consoleMenuBar.add(helpMenu);
201:
202: if (mainFrame != null) {
203: mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
204: URL iconLocation = ConsoleGUI.class
205: .getResource("/org/xins/common/servlet/container/xins.gif");
206: if (iconLocation != null) {
207: mainFrame.setIconImage(new ImageIcon(iconLocation)
208: .getImage());
209: }
210: String title = "XINS Servlet Console "
211: + cmdArgs.getWarFile().getName();
212: if (cmdArgs.getPort() != HTTPServletStarter.DEFAULT_PORT_NUMBER) {
213: title += " [port:" + cmdArgs.getPort() + "]";
214: }
215: mainFrame.setTitle(title);
216: mainFrame.setJMenuBar(getMenuBar());
217: mainFrame.getContentPane().add(getMainPanel());
218: mainFrame.pack();
219:
220: // Center the JFrame
221: Dimension screenDim = Toolkit.getDefaultToolkit()
222: .getScreenSize();
223: Dimension appDim = mainFrame.getSize();
224: mainFrame.setLocation((screenDim.width - appDim.width) / 2,
225: (screenDim.height - appDim.height) / 2);
226: }
227: }
228:
229: protected void initData() {
230:
231: // Initialize the styles
232: Style debug = console.addStyle("Debug", null);
233: StyleConstants.setForeground(debug, Color.DARK_GRAY);
234: Style info = console.addStyle("Info", null);
235: StyleConstants.setForeground(info, Color.BLACK);
236: Style notice = console.addStyle("Notice", null);
237: StyleConstants.setForeground(notice, Color.BLUE.darker());
238: Style warning = console.addStyle("Warning", null);
239: StyleConstants.setForeground(warning, Color.ORANGE.darker());
240: Style error = console.addStyle("Error", null);
241: StyleConstants.setForeground(error, Color.RED.darker());
242: Style fatal = console.addStyle("Fatal", null);
243: StyleConstants.setForeground(fatal, Color.RED);
244: StyleConstants.setBackground(fatal, Color.LIGHT_GRAY);
245: logStyles = new Style[] { debug, info, notice, warning, error,
246: fatal };
247:
248: try {
249: // Set up System.out
250: PipedInputStream piOut = new PipedInputStream();
251: PipedOutputStream poOut = new PipedOutputStream(piOut);
252: System.setOut(new PrintStream(poOut, true));
253:
254: // Set up System.err
255: /*PipedInputStream piErr = new PipedInputStream();
256: PipedOutputStream poErr = new PipedOutputStream(piErr);
257: System.setErr(new PrintStream(poErr, true));*/
258: // Create reader threads
259: new ReaderThread(piOut).start();
260: //new ReaderThread(piErr).start();
261: } catch (IOException ioe) {
262: }
263: }
264:
265: public JPanel getMainPanel() {
266: return consolePanel;
267: }
268:
269: public JMenuBar getMenuBar() {
270: return consoleMenuBar;
271: }
272:
273: protected int getLogLevel(String text) {
274: String textToSearch = text;
275: if (text.length() > 50) {
276: textToSearch = text.substring(0, 50);
277: }
278: if (textToSearch.indexOf("DEBUG") != -1) {
279: return 0;
280: } else if (textToSearch.indexOf("INFO") != -1) {
281: return 1;
282: } else if (textToSearch.indexOf("NOTICE") != -1) {
283: return 2;
284: } else if (textToSearch.indexOf("WARN") != -1) {
285: return 3;
286: } else if (textToSearch.indexOf("ERROR") != -1) {
287: return 4;
288: } else if (textToSearch.indexOf("FATAL") != -1) {
289: return 5;
290: } else {
291: return -1;
292: }
293: }
294:
295: class ReaderThread extends Thread {
296: BufferedReader br;
297:
298: ReaderThread(PipedInputStream pi) {
299: br = new BufferedReader(new InputStreamReader(pi));
300: }
301:
302: public void run() {
303: while (true) {
304: try {
305: final String text = br.readLine();
306: SwingUtilities.invokeLater(new Runnable() {
307: public void run() {
308: try {
309: int consoleLength = console
310: .getDocument().getLength();
311: int messageLogLevel = getLogLevel(text);
312: if (messageLogLevel < logLevel
313: && messageLogLevel != -1) {
314: return;
315: }
316: if (logFilter != null) {
317: boolean match = patternFilter
318: .matcher(text).find();
319: if (!match) {
320: return;
321: }
322: }
323: if (messageLogLevel == -1) {
324: console.getDocument().insertString(
325: consoleLength, text + "\n",
326: null);
327: } else {
328: Style style = logStyles[messageLogLevel];
329: console.getDocument().insertString(
330: consoleLength, text + "\n",
331: style);
332: }
333:
334: // Make sure the last line is always visible
335: consoleLength = console.getDocument()
336: .getLength();
337: console.setCaretPosition(consoleLength);
338:
339: // Keep the text area down to a certain character size
340: int idealSize = 100000;
341: int maxExcess = 50000;
342: int excess = consoleLength - idealSize;
343: if (excess >= maxExcess) {
344: console.getDocument().remove(0,
345: excess);
346: }
347: } catch (BadLocationException e) {
348: }
349: }
350: });
351: } catch (IOException e) {
352: // XXX a Write end dead is throw everytime (I don't know why)
353: try {
354: sleep(500);
355: } catch (InterruptedException ie) {
356: }
357: }
358: }
359: }
360: }
361:
362: class ChangeLogLevel extends AbstractAction {
363:
364: private int _newLogLevel;
365:
366: ChangeLogLevel(int newLogLevel, String level) {
367: super (level);
368: _newLogLevel = newLogLevel;
369: }
370:
371: public void actionPerformed(ActionEvent ae) {
372: logLevel = _newLogLevel;
373: }
374: }
375:
376: class BrowseAction extends AbstractAction {
377:
378: private String _url;
379:
380: BrowseAction(String title, String url) {
381: super (title);
382: _url = url;
383: }
384:
385: public void actionPerformed(ActionEvent ae) {
386: try {
387: URI uri = new URI(_url);
388: Class destkopClass = Class.forName("java.awt.Desktop");
389: Object desktop = destkopClass.getMethod("getDesktop",
390: null).invoke(null, null);
391: Class[] argClasses = { URI.class };
392: URI[] args = { uri };
393: destkopClass.getMethod("browse", argClasses).invoke(
394: desktop, args);
395: } catch (Throwable ex) {
396: // Ignore
397: }
398: }
399: }
400: }
|