View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.log4j.lf5.viewer;
18  
19  import org.apache.log4j.lf5.LogLevel;
20  import org.apache.log4j.lf5.LogRecord;
21  import org.apache.log4j.lf5.LogRecordFilter;
22  import org.apache.log4j.lf5.util.DateFormatManager;
23  import org.apache.log4j.lf5.util.LogFileParser;
24  import org.apache.log4j.lf5.util.StreamUtils;
25  import org.apache.log4j.lf5.viewer.categoryexplorer.CategoryExplorerTree;
26  import org.apache.log4j.lf5.viewer.categoryexplorer.CategoryPath;
27  import org.apache.log4j.lf5.viewer.configure.ConfigurationManager;
28  import org.apache.log4j.lf5.viewer.configure.MRUFileManager;
29  
30  import javax.swing.*;
31  import java.awt.*;
32  import java.awt.event.ActionEvent;
33  import java.awt.event.ActionListener;
34  import java.awt.event.WindowAdapter;
35  import java.awt.event.WindowEvent;
36  import java.io.File;
37  import java.io.IOException;
38  import java.io.InputStream;
39  import java.net.MalformedURLException;
40  import java.net.URL;
41  import java.util.*;
42  import java.util.List;
43  
44  /***
45   * LogBrokerMonitor
46   *.
47   * @author Michael J. Sikorsky
48   * @author Robert Shaw
49   * @author Brad Marlborough
50   * @author Richard Wan
51   * @author Brent Sprecher
52   * @author Richard Hurst
53   */
54  
55  // Contributed by ThoughtWorks Inc.
56  
57  public class LogBrokerMonitor {
58    //--------------------------------------------------------------------------
59    //   Constants:
60    //--------------------------------------------------------------------------
61  
62    public static final String DETAILED_VIEW = "Detailed";
63  //    public static final String STANDARD_VIEW = "Standard";
64  //    public static final String COMPACT_VIEW = "Compact";
65    //--------------------------------------------------------------------------
66    //   Protected Variables:
67    //--------------------------------------------------------------------------
68    protected JFrame _logMonitorFrame;
69    protected int _logMonitorFrameWidth = 550;
70    protected int _logMonitorFrameHeight = 500;
71    protected LogTable _table;
72    protected CategoryExplorerTree _categoryExplorerTree;
73    protected String _searchText;
74    protected String _NDCTextFilter = "";
75    protected LogLevel _leastSevereDisplayedLogLevel = LogLevel.DEBUG;
76  
77    protected JScrollPane _logTableScrollPane;
78    protected JLabel _statusLabel;
79    protected Object _lock = new Object();
80    protected JComboBox _fontSizeCombo;
81  
82    protected int _fontSize = 10;
83    protected String _fontName = "Dialog";
84    protected String _currentView = DETAILED_VIEW;
85  
86    protected boolean _loadSystemFonts = false;
87    protected boolean _trackTableScrollPane = true;
88    protected Dimension _lastTableViewportSize;
89    protected boolean _callSystemExitOnClose = false;
90    protected List _displayedLogBrokerProperties = new Vector();
91  
92    protected Map _logLevelMenuItems = new HashMap();
93    protected Map _logTableColumnMenuItems = new HashMap();
94  
95    protected List _levels = null;
96    protected List _columns = null;
97    protected boolean _isDisposed = false;
98  
99    protected ConfigurationManager _configurationManager = null;
100   protected MRUFileManager _mruFileManager = null;
101   protected File _fileLocation = null;
102 
103   //--------------------------------------------------------------------------
104   //   Private Variables:
105   //--------------------------------------------------------------------------
106 
107   //--------------------------------------------------------------------------
108   //   Constructors:
109   //--------------------------------------------------------------------------
110 
111   /***
112    * Construct a LogBrokerMonitor.
113    */
114   public LogBrokerMonitor(List logLevels) {
115 
116     _levels = logLevels;
117     _columns = LogTableColumn.getLogTableColumns();
118     // This allows us to use the LogBroker in command line tools and
119     // have the option for it to shutdown.
120 
121     String callSystemExitOnClose =
122         System.getProperty("monitor.exit");
123     if (callSystemExitOnClose == null) {
124       callSystemExitOnClose = "false";
125     }
126     callSystemExitOnClose = callSystemExitOnClose.trim().toLowerCase();
127 
128     if (callSystemExitOnClose.equals("true")) {
129       _callSystemExitOnClose = true;
130     }
131 
132     initComponents();
133 
134 
135     _logMonitorFrame.addWindowListener(
136         new LogBrokerMonitorWindowAdaptor(this));
137 
138   }
139 
140   //--------------------------------------------------------------------------
141   //   Public Methods:
142   //--------------------------------------------------------------------------
143 
144   /***
145    * Show the frame for the LogBrokerMonitor. Dispatched to the
146    * swing thread.
147    */
148   public void show(final int delay) {
149     if (_logMonitorFrame.isVisible()) {
150       return;
151     }
152     // This request is very low priority, let other threads execute first.
153     SwingUtilities.invokeLater(new Runnable() {
154       public void run() {
155         Thread.yield();
156         pause(delay);
157         _logMonitorFrame.setVisible(true);
158       }
159     });
160   }
161 
162   public void show() {
163     show(0);
164   }
165 
166   /***
167    * Dispose of the frame for the LogBrokerMonitor.
168    */
169   public void dispose() {
170     _logMonitorFrame.dispose();
171     _isDisposed = true;
172 
173     if (_callSystemExitOnClose == true) {
174       System.exit(0);
175     }
176   }
177 
178   /***
179    * Hide the frame for the LogBrokerMonitor.
180    */
181   public void hide() {
182     _logMonitorFrame.setVisible(false);
183   }
184 
185   /***
186    * Get the DateFormatManager for formatting dates.
187    */
188   public DateFormatManager getDateFormatManager() {
189     return _table.getDateFormatManager();
190   }
191 
192   /***
193    * Set the date format manager for formatting dates.
194    */
195   public void setDateFormatManager(DateFormatManager dfm) {
196     _table.setDateFormatManager(dfm);
197   }
198 
199   /***
200    * Get the value of whether or not System.exit() will be called
201    * when the LogBrokerMonitor is closed.
202    */
203   public boolean getCallSystemExitOnClose() {
204     return _callSystemExitOnClose;
205   }
206 
207   /***
208    * Set the value of whether or not System.exit() will be called
209    * when the LogBrokerMonitor is closed.
210    */
211   public void setCallSystemExitOnClose(boolean callSystemExitOnClose) {
212     _callSystemExitOnClose = callSystemExitOnClose;
213   }
214 
215   /***
216    * Add a log record message to be displayed in the LogTable.
217    * This method is thread-safe as it posts requests to the SwingThread
218    * rather than processing directly.
219    */
220   public void addMessage(final LogRecord lr) {
221     if (_isDisposed == true) {
222       // If the frame has been disposed of, do not log any more
223       // messages.
224       return;
225     }
226 
227     SwingUtilities.invokeLater(new Runnable() {
228       public void run() {
229         _categoryExplorerTree.getExplorerModel().addLogRecord(lr);
230         _table.getFilteredLogTableModel().addLogRecord(lr); // update table
231         updateStatusLabel(); // show updated counts
232       }
233     });
234   }
235 
236   public void setMaxNumberOfLogRecords(int maxNumberOfLogRecords) {
237     _table.getFilteredLogTableModel().setMaxNumberOfLogRecords(maxNumberOfLogRecords);
238   }
239 
240   public JFrame getBaseFrame() {
241     return _logMonitorFrame;
242   }
243 
244   public void setTitle(String title) {
245     _logMonitorFrame.setTitle(title + " - LogFactor5");
246   }
247 
248   public void setFrameSize(int width, int height) {
249     Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
250     if (0 < width && width < screen.width) {
251       _logMonitorFrameWidth = width;
252     }
253     if (0 < height && height < screen.height) {
254       _logMonitorFrameHeight = height;
255     }
256     updateFrameSize();
257   }
258 
259   public void setFontSize(int fontSize) {
260     changeFontSizeCombo(_fontSizeCombo, fontSize);
261     // setFontSizeSilently(actualFontSize); - changeFontSizeCombo fires event
262     // refreshDetailTextArea();
263   }
264 
265   public void addDisplayedProperty(Object messageLine) {
266     _displayedLogBrokerProperties.add(messageLine);
267   }
268 
269   public Map getLogLevelMenuItems() {
270     return _logLevelMenuItems;
271   }
272 
273   public Map getLogTableColumnMenuItems() {
274     return _logTableColumnMenuItems;
275   }
276 
277   public JCheckBoxMenuItem getTableColumnMenuItem(LogTableColumn column) {
278     return getLogTableColumnMenuItem(column);
279   }
280 
281   public CategoryExplorerTree getCategoryExplorerTree() {
282     return _categoryExplorerTree;
283   }
284 
285   // Added in version 1.2 - gets the value of the NDC text filter
286   // This value is set back to null each time the Monitor is initialized.
287   public String getNDCTextFilter() {
288     return _NDCTextFilter;
289   }
290 
291   // Added in version 1.2 - sets the NDC Filter based on
292   // a String passed in by the user.  This value is persisted
293   // in the XML Configuration file.
294   public void setNDCLogRecordFilter(String textFilter) {
295     _table.getFilteredLogTableModel().
296         setLogRecordFilter(createNDCLogRecordFilter(textFilter));
297   }
298   //--------------------------------------------------------------------------
299   //   Protected Methods:
300   //--------------------------------------------------------------------------
301 
302   protected void setSearchText(String text) {
303     _searchText = text;
304   }
305 
306   // Added in version 1.2 - Sets the text filter for the NDC
307   protected void setNDCTextFilter(String text) {
308     // if no value is set, set it to a blank string
309     // otherwise use the value provided
310     if (text == null) {
311       _NDCTextFilter = "";
312     } else {
313       _NDCTextFilter = text;
314     }
315   }
316 
317   // Added in version 1.2 - Uses a different filter that sorts
318   // based on an NDC string passed in by the user.  If the string
319   // is null or is an empty string, we do nothing.
320   protected void sortByNDC() {
321     String text = _NDCTextFilter;
322     if (text == null || text.length() == 0) {
323       return;
324     }
325 
326     // Use new NDC filter
327     _table.getFilteredLogTableModel().
328         setLogRecordFilter(createNDCLogRecordFilter(text));
329   }
330 
331   protected void findSearchText() {
332     String text = _searchText;
333     if (text == null || text.length() == 0) {
334       return;
335     }
336     int startRow = getFirstSelectedRow();
337     int foundRow = findRecord(
338         startRow,
339         text,
340         _table.getFilteredLogTableModel().getFilteredRecords()
341     );
342     selectRow(foundRow);
343   }
344 
345   protected int getFirstSelectedRow() {
346     return _table.getSelectionModel().getMinSelectionIndex();
347   }
348 
349   protected void selectRow(int foundRow) {
350     if (foundRow == -1) {
351       String message = _searchText + " not found.";
352       JOptionPane.showMessageDialog(
353           _logMonitorFrame,
354           message,
355           "Text not found",
356           JOptionPane.INFORMATION_MESSAGE
357       );
358       return;
359     }
360     LF5SwingUtils.selectRow(foundRow, _table, _logTableScrollPane);
361   }
362 
363   protected int findRecord(
364       int startRow,
365       String searchText,
366       List records
367       ) {
368     if (startRow < 0) {
369       startRow = 0; // start at first element if no rows are selected
370     } else {
371       startRow++; // start after the first selected row
372     }
373     int len = records.size();
374 
375     for (int i = startRow; i < len; i++) {
376       if (matches((LogRecord) records.get(i), searchText)) {
377         return i; // found a record
378       }
379     }
380     // wrap around to beginning if when we reach the end with no match
381     len = startRow;
382     for (int i = 0; i < len; i++) {
383       if (matches((LogRecord) records.get(i), searchText)) {
384         return i; // found a record
385       }
386     }
387     // nothing found
388     return -1;
389   }
390 
391   /***
392    * Check to see if the any records contain the search string.
393    * Searching now supports NDC messages and date.
394    */
395   protected boolean matches(LogRecord record, String text) {
396     String message = record.getMessage();
397     String NDC = record.getNDC();
398 
399     if (message == null && NDC == null || text == null) {
400       return false;
401     }
402     if (message.toLowerCase().indexOf(text.toLowerCase()) == -1 &&
403         NDC.toLowerCase().indexOf(text.toLowerCase()) == -1) {
404       return false;
405     }
406 
407     return true;
408   }
409 
410   /***
411    * When the fontsize of a JTextArea is changed, the word-wrapped lines
412    * may become garbled.  This method clears and resets the text of the
413    * text area.
414    */
415   protected void refresh(JTextArea textArea) {
416     String text = textArea.getText();
417     textArea.setText("");
418     textArea.setText(text);
419   }
420 
421   protected void refreshDetailTextArea() {
422     refresh(_table._detailTextArea);
423   }
424 
425   protected void clearDetailTextArea() {
426     _table._detailTextArea.setText("");
427   }
428 
429   /***
430    * Changes the font selection in the combo box and returns the
431    * size actually selected.
432    * @return -1 if unable to select an appropriate font
433    */
434   protected int changeFontSizeCombo(JComboBox box, int requestedSize) {
435     int len = box.getItemCount();
436     int currentValue;
437     Object currentObject;
438     Object selectedObject = box.getItemAt(0);
439     int selectedValue = Integer.parseInt(String.valueOf(selectedObject));
440     for (int i = 0; i < len; i++) {
441       currentObject = box.getItemAt(i);
442       currentValue = Integer.parseInt(String.valueOf(currentObject));
443       if (selectedValue < currentValue && currentValue <= requestedSize) {
444         selectedValue = currentValue;
445         selectedObject = currentObject;
446       }
447     }
448     box.setSelectedItem(selectedObject);
449     return selectedValue;
450   }
451 
452   /***
453    * Does not update gui or cause any events to be fired.
454    */
455   protected void setFontSizeSilently(int fontSize) {
456     _fontSize = fontSize;
457     setFontSize(_table._detailTextArea, fontSize);
458     selectRow(0);
459     setFontSize(_table, fontSize);
460   }
461 
462   protected void setFontSize(Component component, int fontSize) {
463     Font oldFont = component.getFont();
464     Font newFont =
465         new Font(oldFont.getFontName(), oldFont.getStyle(), fontSize);
466     component.setFont(newFont);
467   }
468 
469   protected void updateFrameSize() {
470     _logMonitorFrame.setSize(_logMonitorFrameWidth, _logMonitorFrameHeight);
471     centerFrame(_logMonitorFrame);
472   }
473 
474   protected void pause(int millis) {
475     try {
476       Thread.sleep(millis);
477     } catch (InterruptedException e) {
478 
479     }
480   }
481 
482   protected void initComponents() {
483     //
484     // Configure the Frame.
485     //
486     _logMonitorFrame = new JFrame("LogFactor5");
487 
488     _logMonitorFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
489 
490     String resource =
491         "/org/apache/log4j/lf5/viewer/images/lf5_small_icon.gif";
492     URL lf5IconURL = getClass().getResource(resource);
493 
494     if (lf5IconURL != null) {
495       _logMonitorFrame.setIconImage(new ImageIcon(lf5IconURL).getImage());
496     }
497     updateFrameSize();
498 
499     //
500     // Configure the LogTable.
501     //
502     JTextArea detailTA = createDetailTextArea();
503     JScrollPane detailTAScrollPane = new JScrollPane(detailTA);
504     _table = new LogTable(detailTA);
505     setView(_currentView, _table);
506     _table.setFont(new Font(_fontName, Font.PLAIN, _fontSize));
507     _logTableScrollPane = new JScrollPane(_table);
508 
509     if (_trackTableScrollPane) {
510       _logTableScrollPane.getVerticalScrollBar().addAdjustmentListener(
511           new TrackingAdjustmentListener()
512       );
513     }
514 
515 
516     // Configure the SplitPane between the LogTable & DetailTextArea
517     //
518 
519     JSplitPane tableViewerSplitPane = new JSplitPane();
520     tableViewerSplitPane.setOneTouchExpandable(true);
521     tableViewerSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
522     tableViewerSplitPane.setLeftComponent(_logTableScrollPane);
523     tableViewerSplitPane.setRightComponent(detailTAScrollPane);
524     // Make sure to do this last..
525     //tableViewerSplitPane.setDividerLocation(1.0); Doesn't work
526     //the same under 1.2.x & 1.3
527     // "350" is a magic number that provides the correct default
528     // behaviour under 1.2.x & 1.3.  For example, bumping this
529     // number to 400, causes the pane to be completely open in 1.2.x
530     // and closed in 1.3
531     tableViewerSplitPane.setDividerLocation(350);
532 
533     //
534     // Configure the CategoryExplorer
535     //
536 
537     _categoryExplorerTree = new CategoryExplorerTree();
538 
539     _table.getFilteredLogTableModel().setLogRecordFilter(createLogRecordFilter());
540 
541     JScrollPane categoryExplorerTreeScrollPane =
542         new JScrollPane(_categoryExplorerTree);
543     categoryExplorerTreeScrollPane.setPreferredSize(new Dimension(130, 400));
544 
545     // Load most recently used file list
546     _mruFileManager = new MRUFileManager();
547 
548     //
549     // Configure the SplitPane between the CategoryExplorer & (LogTable/Detail)
550     //
551 
552     JSplitPane splitPane = new JSplitPane();
553     splitPane.setOneTouchExpandable(true);
554     splitPane.setRightComponent(tableViewerSplitPane);
555     splitPane.setLeftComponent(categoryExplorerTreeScrollPane);
556     // Do this last.
557     splitPane.setDividerLocation(130);
558     //
559     // Add the MenuBar, StatusArea, CategoryExplorer|LogTable to the
560     // LogMonitorFrame.
561     //
562     _logMonitorFrame.getRootPane().setJMenuBar(createMenuBar());
563     _logMonitorFrame.getContentPane().add(splitPane, BorderLayout.CENTER);
564     _logMonitorFrame.getContentPane().add(createToolBar(),
565         BorderLayout.NORTH);
566     _logMonitorFrame.getContentPane().add(createStatusArea(),
567         BorderLayout.SOUTH);
568 
569     makeLogTableListenToCategoryExplorer();
570     addTableModelProperties();
571 
572     //
573     // Configure ConfigurationManager
574     //
575     _configurationManager = new ConfigurationManager(this, _table);
576 
577   }
578 
579   protected LogRecordFilter createLogRecordFilter() {
580     LogRecordFilter result = new LogRecordFilter() {
581       public boolean passes(LogRecord record) {
582         CategoryPath path = new CategoryPath(record.getCategory());
583         return
584             getMenuItem(record.getLevel()).isSelected() &&
585             _categoryExplorerTree.getExplorerModel().isCategoryPathActive(path);
586       }
587     };
588     return result;
589   }
590 
591   // Added in version 1.2 - Creates a new filter that sorts records based on
592   // an NDC string passed in by the user.
593   protected LogRecordFilter createNDCLogRecordFilter(String text) {
594     _NDCTextFilter = text;
595     LogRecordFilter result = new LogRecordFilter() {
596       public boolean passes(LogRecord record) {
597         String NDC = record.getNDC();
598         CategoryPath path = new CategoryPath(record.getCategory());
599         if (NDC == null || _NDCTextFilter == null) {
600           return false;
601         } else if (NDC.toLowerCase().indexOf(_NDCTextFilter.toLowerCase()) == -1) {
602           return false;
603         } else {
604           return getMenuItem(record.getLevel()).isSelected() &&
605               _categoryExplorerTree.getExplorerModel().isCategoryPathActive(path);
606         }
607       }
608     };
609 
610     return result;
611   }
612 
613 
614   protected void updateStatusLabel() {
615     _statusLabel.setText(getRecordsDisplayedMessage());
616   }
617 
618   protected String getRecordsDisplayedMessage() {
619     FilteredLogTableModel model = _table.getFilteredLogTableModel();
620     return getStatusText(model.getRowCount(), model.getTotalRowCount());
621   }
622 
623   protected void addTableModelProperties() {
624     final FilteredLogTableModel model = _table.getFilteredLogTableModel();
625 
626     addDisplayedProperty(new Object() {
627       public String toString() {
628         return getRecordsDisplayedMessage();
629       }
630     });
631     addDisplayedProperty(new Object() {
632       public String toString() {
633         return "Maximum number of displayed LogRecords: "
634             + model._maxNumberOfLogRecords;
635       }
636     });
637   }
638 
639   protected String getStatusText(int displayedRows, int totalRows) {
640     StringBuffer result = new StringBuffer();
641     result.append("Displaying: ");
642     result.append(displayedRows);
643     result.append(" records out of a total of: ");
644     result.append(totalRows);
645     result.append(" records.");
646     return result.toString();
647   }
648 
649   protected void makeLogTableListenToCategoryExplorer() {
650     ActionListener listener = new ActionListener() {
651       public void actionPerformed(ActionEvent e) {
652         _table.getFilteredLogTableModel().refresh();
653         updateStatusLabel();
654       }
655     };
656     _categoryExplorerTree.getExplorerModel().addActionListener(listener);
657   }
658 
659   protected JPanel createStatusArea() {
660     JPanel statusArea = new JPanel();
661     JLabel status =
662         new JLabel("No log records to display.");
663     _statusLabel = status;
664     status.setHorizontalAlignment(JLabel.LEFT);
665 
666     statusArea.setBorder(BorderFactory.createEtchedBorder());
667     statusArea.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
668     statusArea.add(status);
669 
670     return (statusArea);
671   }
672 
673   protected JTextArea createDetailTextArea() {
674     JTextArea detailTA = new JTextArea();
675     detailTA.setFont(new Font("Monospaced", Font.PLAIN, 14));
676     detailTA.setTabSize(3);
677     detailTA.setLineWrap(true);
678     detailTA.setWrapStyleWord(false);
679     return (detailTA);
680   }
681 
682   protected JMenuBar createMenuBar() {
683     JMenuBar menuBar = new JMenuBar();
684     menuBar.add(createFileMenu());
685     menuBar.add(createEditMenu());
686     menuBar.add(createLogLevelMenu());
687     menuBar.add(createViewMenu());
688     menuBar.add(createConfigureMenu());
689     menuBar.add(createHelpMenu());
690 
691     return (menuBar);
692   }
693 
694   protected JMenu createLogLevelMenu() {
695     JMenu result = new JMenu("Log Level");
696     result.setMnemonic('l');
697     Iterator levels = getLogLevels();
698     while (levels.hasNext()) {
699       result.add(getMenuItem((LogLevel) levels.next()));
700     }
701 
702     result.addSeparator();
703     result.add(createAllLogLevelsMenuItem());
704     result.add(createNoLogLevelsMenuItem());
705     result.addSeparator();
706     result.add(createLogLevelColorMenu());
707     result.add(createResetLogLevelColorMenuItem());
708 
709     return result;
710   }
711 
712   protected JMenuItem createAllLogLevelsMenuItem() {
713     JMenuItem result = new JMenuItem("Show all LogLevels");
714     result.setMnemonic('s');
715     result.addActionListener(new ActionListener() {
716       public void actionPerformed(ActionEvent e) {
717         selectAllLogLevels(true);
718         _table.getFilteredLogTableModel().refresh();
719         updateStatusLabel();
720       }
721     });
722     return result;
723   }
724 
725   protected JMenuItem createNoLogLevelsMenuItem() {
726     JMenuItem result = new JMenuItem("Hide all LogLevels");
727     result.setMnemonic('h');
728     result.addActionListener(new ActionListener() {
729       public void actionPerformed(ActionEvent e) {
730         selectAllLogLevels(false);
731         _table.getFilteredLogTableModel().refresh();
732         updateStatusLabel();
733       }
734     });
735     return result;
736   }
737 
738   protected JMenu createLogLevelColorMenu() {
739     JMenu colorMenu = new JMenu("Configure LogLevel Colors");
740     colorMenu.setMnemonic('c');
741     Iterator levels = getLogLevels();
742     while (levels.hasNext()) {
743       colorMenu.add(createSubMenuItem((LogLevel) levels.next()));
744     }
745 
746     return colorMenu;
747   }
748 
749   protected JMenuItem createResetLogLevelColorMenuItem() {
750     JMenuItem result = new JMenuItem("Reset LogLevel Colors");
751     result.setMnemonic('r');
752     result.addActionListener(new ActionListener() {
753       public void actionPerformed(ActionEvent e) {
754         // reset the level colors in the map
755         LogLevel.resetLogLevelColorMap();
756 
757         // refresh the table
758         _table.getFilteredLogTableModel().refresh();
759       }
760     });
761     return result;
762   }
763 
764   protected void selectAllLogLevels(boolean selected) {
765     Iterator levels = getLogLevels();
766     while (levels.hasNext()) {
767       getMenuItem((LogLevel) levels.next()).setSelected(selected);
768     }
769   }
770 
771   protected JCheckBoxMenuItem getMenuItem(LogLevel level) {
772     JCheckBoxMenuItem result = (JCheckBoxMenuItem) (_logLevelMenuItems.get(level));
773     if (result == null) {
774       result = createMenuItem(level);
775       _logLevelMenuItems.put(level, result);
776     }
777     return result;
778   }
779 
780   protected JMenuItem createSubMenuItem(LogLevel level) {
781     final JMenuItem result = new JMenuItem(level.toString());
782     final LogLevel logLevel = level;
783     result.setMnemonic(level.toString().charAt(0));
784     result.addActionListener(new ActionListener() {
785       public void actionPerformed(ActionEvent e) {
786         showLogLevelColorChangeDialog(result, logLevel);
787       }
788     });
789 
790     return result;
791 
792   }
793 
794   protected void showLogLevelColorChangeDialog(JMenuItem result, LogLevel level) {
795     JMenuItem menuItem = result;
796     Color newColor = JColorChooser.showDialog(
797         _logMonitorFrame,
798         "Choose LogLevel Color",
799         result.getForeground());
800 
801     if (newColor != null) {
802       // set the color for the record
803       level.setLogLevelColorMap(level, newColor);
804       _table.getFilteredLogTableModel().refresh();
805     }
806 
807   }
808 
809   protected JCheckBoxMenuItem createMenuItem(LogLevel level) {
810     JCheckBoxMenuItem result = new JCheckBoxMenuItem(level.toString());
811     result.setSelected(true);
812     result.setMnemonic(level.toString().charAt(0));
813     result.addActionListener(new ActionListener() {
814       public void actionPerformed(ActionEvent e) {
815         _table.getFilteredLogTableModel().refresh();
816         updateStatusLabel();
817       }
818     });
819     return result;
820   }
821 
822   // view menu
823   protected JMenu createViewMenu() {
824     JMenu result = new JMenu("View");
825     result.setMnemonic('v');
826     Iterator columns = getLogTableColumns();
827     while (columns.hasNext()) {
828       result.add(getLogTableColumnMenuItem((LogTableColumn) columns.next()));
829     }
830 
831     result.addSeparator();
832     result.add(createAllLogTableColumnsMenuItem());
833     result.add(createNoLogTableColumnsMenuItem());
834     return result;
835   }
836 
837   protected JCheckBoxMenuItem getLogTableColumnMenuItem(LogTableColumn column) {
838     JCheckBoxMenuItem result = (JCheckBoxMenuItem) (_logTableColumnMenuItems.get(column));
839     if (result == null) {
840       result = createLogTableColumnMenuItem(column);
841       _logTableColumnMenuItems.put(column, result);
842     }
843     return result;
844   }
845 
846   protected JCheckBoxMenuItem createLogTableColumnMenuItem(LogTableColumn column) {
847     JCheckBoxMenuItem result = new JCheckBoxMenuItem(column.toString());
848 
849     result.setSelected(true);
850     result.setMnemonic(column.toString().charAt(0));
851     result.addActionListener(new ActionListener() {
852       public void actionPerformed(ActionEvent e) {
853         // update list of columns and reset the view
854         List selectedColumns = updateView();
855         _table.setView(selectedColumns);
856       }
857     });
858     return result;
859   }
860 
861   protected List updateView() {
862     ArrayList updatedList = new ArrayList();
863     Iterator columnIterator = _columns.iterator();
864     while (columnIterator.hasNext()) {
865       LogTableColumn column = (LogTableColumn) columnIterator.next();
866       JCheckBoxMenuItem result = getLogTableColumnMenuItem(column);
867       // check and see if the checkbox is checked
868       if (result.isSelected()) {
869         updatedList.add(column);
870       }
871     }
872 
873     return updatedList;
874   }
875 
876   protected JMenuItem createAllLogTableColumnsMenuItem() {
877     JMenuItem result = new JMenuItem("Show all Columns");
878     result.setMnemonic('s');
879     result.addActionListener(new ActionListener() {
880       public void actionPerformed(ActionEvent e) {
881         selectAllLogTableColumns(true);
882         // update list of columns and reset the view
883         List selectedColumns = updateView();
884         _table.setView(selectedColumns);
885       }
886     });
887     return result;
888   }
889 
890   protected JMenuItem createNoLogTableColumnsMenuItem() {
891     JMenuItem result = new JMenuItem("Hide all Columns");
892     result.setMnemonic('h');
893     result.addActionListener(new ActionListener() {
894       public void actionPerformed(ActionEvent e) {
895         selectAllLogTableColumns(false);
896         // update list of columns and reset the view
897         List selectedColumns = updateView();
898         _table.setView(selectedColumns);
899       }
900     });
901     return result;
902   }
903 
904   protected void selectAllLogTableColumns(boolean selected) {
905     Iterator columns = getLogTableColumns();
906     while (columns.hasNext()) {
907       getLogTableColumnMenuItem((LogTableColumn) columns.next()).setSelected(selected);
908     }
909   }
910 
911   protected JMenu createFileMenu() {
912     JMenu fileMenu = new JMenu("File");
913     fileMenu.setMnemonic('f');
914     JMenuItem exitMI;
915     fileMenu.add(createOpenMI());
916     fileMenu.add(createOpenURLMI());
917     fileMenu.addSeparator();
918     fileMenu.add(createCloseMI());
919     createMRUFileListMI(fileMenu);
920     fileMenu.addSeparator();
921     fileMenu.add(createExitMI());
922     return fileMenu;
923   }
924 
925   /***
926    * Menu item added to allow log files to be opened with
927    * the LF5 GUI.
928    */
929   protected JMenuItem createOpenMI() {
930     JMenuItem result = new JMenuItem("Open...");
931     result.setMnemonic('o');
932     result.addActionListener(new ActionListener() {
933       public void actionPerformed(ActionEvent e) {
934         requestOpen();
935       }
936     });
937     return result;
938   }
939 
940   /***
941    * Menu item added to allow log files loaded from a URL
942    * to be opened by the LF5 GUI.
943    */
944   protected JMenuItem createOpenURLMI() {
945     JMenuItem result = new JMenuItem("Open URL...");
946     result.setMnemonic('u');
947     result.addActionListener(new ActionListener() {
948       public void actionPerformed(ActionEvent e) {
949         requestOpenURL();
950       }
951     });
952     return result;
953   }
954 
955   protected JMenuItem createCloseMI() {
956     JMenuItem result = new JMenuItem("Close");
957     result.setMnemonic('c');
958     result.setAccelerator(KeyStroke.getKeyStroke("control Q"));
959     result.addActionListener(new ActionListener() {
960       public void actionPerformed(ActionEvent e) {
961         requestClose();
962       }
963     });
964     return result;
965   }
966 
967   /***
968    * Creates a Most Recently Used file list to be
969    * displayed in the File menu
970    */
971   protected void createMRUFileListMI(JMenu menu) {
972 
973     String[] files = _mruFileManager.getMRUFileList();
974 
975     if (files != null) {
976       menu.addSeparator();
977       for (int i = 0; i < files.length; i++) {
978         JMenuItem result = new JMenuItem((i + 1) + " " + files[i]);
979         result.setMnemonic(i + 1);
980         result.addActionListener(new ActionListener() {
981           public void actionPerformed(ActionEvent e) {
982             requestOpenMRU(e);
983           }
984         });
985         menu.add(result);
986       }
987     }
988   }
989 
990   protected JMenuItem createExitMI() {
991     JMenuItem result = new JMenuItem("Exit");
992     result.setMnemonic('x');
993     result.addActionListener(new ActionListener() {
994       public void actionPerformed(ActionEvent e) {
995         requestExit();
996       }
997     });
998     return result;
999   }
1000 
1001   protected JMenu createConfigureMenu() {
1002     JMenu configureMenu = new JMenu("Configure");
1003     configureMenu.setMnemonic('c');
1004     configureMenu.add(createConfigureSave());
1005     configureMenu.add(createConfigureReset());
1006     configureMenu.add(createConfigureMaxRecords());
1007 
1008     return configureMenu;
1009   }
1010 
1011   protected JMenuItem createConfigureSave() {
1012     JMenuItem result = new JMenuItem("Save");
1013     result.setMnemonic('s');
1014     result.addActionListener(new ActionListener() {
1015       public void actionPerformed(ActionEvent e) {
1016         saveConfiguration();
1017       }
1018     });
1019 
1020     return result;
1021   }
1022 
1023   protected JMenuItem createConfigureReset() {
1024     JMenuItem result = new JMenuItem("Reset");
1025     result.setMnemonic('r');
1026     result.addActionListener(new ActionListener() {
1027       public void actionPerformed(ActionEvent e) {
1028         resetConfiguration();
1029       }
1030     });
1031 
1032     return result;
1033   }
1034 
1035   protected JMenuItem createConfigureMaxRecords() {
1036     JMenuItem result = new JMenuItem("Set Max Number of Records");
1037     result.setMnemonic('m');
1038     result.addActionListener(new ActionListener() {
1039       public void actionPerformed(ActionEvent e) {
1040         setMaxRecordConfiguration();
1041       }
1042     });
1043 
1044     return result;
1045   }
1046 
1047 
1048   protected void saveConfiguration() {
1049     _configurationManager.save();
1050   }
1051 
1052   protected void resetConfiguration() {
1053     _configurationManager.reset();
1054   }
1055 
1056   protected void setMaxRecordConfiguration() {
1057     LogFactor5InputDialog inputDialog = new LogFactor5InputDialog(
1058         getBaseFrame(), "Set Max Number of Records", "", 10);
1059 
1060     String temp = inputDialog.getText();
1061 
1062     if (temp != null) {
1063       try {
1064         setMaxNumberOfLogRecords(Integer.parseInt(temp));
1065       } catch (NumberFormatException e) {
1066         LogFactor5ErrorDialog error = new LogFactor5ErrorDialog(
1067             getBaseFrame(),
1068             "'" + temp + "' is an invalid parameter.\nPlease try again.");
1069         setMaxRecordConfiguration();
1070       }
1071     }
1072   }
1073 
1074 
1075   protected JMenu createHelpMenu() {
1076     JMenu helpMenu = new JMenu("Help");
1077     helpMenu.setMnemonic('h');
1078     helpMenu.add(createHelpProperties());
1079     return helpMenu;
1080   }
1081 
1082   protected JMenuItem createHelpProperties() {
1083     final String title = "LogFactor5 Properties";
1084     final JMenuItem result = new JMenuItem(title);
1085     result.setMnemonic('l');
1086     result.addActionListener(new ActionListener() {
1087       public void actionPerformed(ActionEvent e) {
1088         showPropertiesDialog(title);
1089       }
1090     });
1091     return result;
1092   }
1093 
1094   protected void showPropertiesDialog(String title) {
1095     JOptionPane.showMessageDialog(
1096         _logMonitorFrame,
1097         _displayedLogBrokerProperties.toArray(),
1098         title,
1099         JOptionPane.PLAIN_MESSAGE
1100     );
1101   }
1102 
1103   protected JMenu createEditMenu() {
1104     JMenu editMenu = new JMenu("Edit");
1105     editMenu.setMnemonic('e');
1106     editMenu.add(createEditFindMI());
1107     editMenu.add(createEditFindNextMI());
1108     editMenu.addSeparator();
1109     editMenu.add(createEditSortNDCMI());
1110     editMenu.add(createEditRestoreAllNDCMI());
1111     return editMenu;
1112   }
1113 
1114   protected JMenuItem createEditFindNextMI() {
1115     JMenuItem editFindNextMI = new JMenuItem("Find Next");
1116     editFindNextMI.setMnemonic('n');
1117     editFindNextMI.setAccelerator(KeyStroke.getKeyStroke("F3"));
1118     editFindNextMI.addActionListener(new ActionListener() {
1119       public void actionPerformed(ActionEvent e) {
1120         findSearchText();
1121       }
1122     });
1123     return editFindNextMI;
1124   }
1125 
1126   protected JMenuItem createEditFindMI() {
1127     JMenuItem editFindMI = new JMenuItem("Find");
1128     editFindMI.setMnemonic('f');
1129     editFindMI.setAccelerator(KeyStroke.getKeyStroke("control F"));
1130 
1131     editFindMI.addActionListener(
1132         new ActionListener() {
1133           public void actionPerformed(ActionEvent e) {
1134             String inputValue =
1135                 JOptionPane.showInputDialog(
1136                     _logMonitorFrame,
1137                     "Find text: ",
1138                     "Search Record Messages",
1139                     JOptionPane.QUESTION_MESSAGE
1140                 );
1141             setSearchText(inputValue);
1142             findSearchText();
1143           }
1144         }
1145 
1146     );
1147     return editFindMI;
1148   }
1149 
1150   // Added version 1.2 - Allows users to Sort Log Records by an
1151   // NDC text filter. A new LogRecordFilter was created to
1152   // sort the records.
1153   protected JMenuItem createEditSortNDCMI() {
1154     JMenuItem editSortNDCMI = new JMenuItem("Sort by NDC");
1155     editSortNDCMI.setMnemonic('s');
1156     editSortNDCMI.addActionListener(
1157         new ActionListener() {
1158           public void actionPerformed(ActionEvent e) {
1159             String inputValue =
1160                 JOptionPane.showInputDialog(
1161                     _logMonitorFrame,
1162                     "Sort by this NDC: ",
1163                     "Sort Log Records by NDC",
1164                     JOptionPane.QUESTION_MESSAGE
1165                 );
1166             setNDCTextFilter(inputValue);
1167             sortByNDC();
1168             _table.getFilteredLogTableModel().refresh();
1169             updateStatusLabel();
1170           }
1171         }
1172 
1173     );
1174     return editSortNDCMI;
1175   }
1176 
1177   // Added in version 1.2 - Resets the LogRecordFilter back to default
1178   // filter.
1179   protected JMenuItem createEditRestoreAllNDCMI() {
1180     JMenuItem editRestoreAllNDCMI = new JMenuItem("Restore all NDCs");
1181     editRestoreAllNDCMI.setMnemonic('r');
1182     editRestoreAllNDCMI.addActionListener(
1183         new ActionListener() {
1184           public void actionPerformed(ActionEvent e) {
1185             _table.getFilteredLogTableModel().setLogRecordFilter(createLogRecordFilter());
1186             // reset the text filter
1187             setNDCTextFilter("");
1188             _table.getFilteredLogTableModel().refresh();
1189             updateStatusLabel();
1190           }
1191         }
1192     );
1193     return editRestoreAllNDCMI;
1194   }
1195 
1196   protected JToolBar createToolBar() {
1197     JToolBar tb = new JToolBar();
1198     tb.putClientProperty("JToolBar.isRollover", Boolean.TRUE);
1199     JComboBox fontCombo = new JComboBox();
1200     JComboBox fontSizeCombo = new JComboBox();
1201     _fontSizeCombo = fontSizeCombo;
1202 
1203     ClassLoader cl = this.getClass().getClassLoader();
1204     if(cl == null) {
1205         cl = ClassLoader.getSystemClassLoader();
1206     }
1207     URL newIconURL = cl.getResource("org/apache/log4j/lf5/viewer/" +
1208         "images/channelexplorer_new.gif");
1209 
1210     ImageIcon newIcon = null;
1211 
1212     if (newIconURL != null) {
1213       newIcon = new ImageIcon(newIconURL);
1214     }
1215 
1216     JButton newButton = new JButton("Clear Log Table");
1217 
1218     if (newIcon != null) {
1219       newButton.setIcon(newIcon);
1220     }
1221 
1222     newButton.setToolTipText("Clear Log Table.");
1223     //newButton.setBorder(BorderFactory.createEtchedBorder());
1224 
1225     newButton.addActionListener(
1226         new ActionListener() {
1227           public void actionPerformed(ActionEvent e) {
1228             _table.clearLogRecords();
1229             _categoryExplorerTree.getExplorerModel().resetAllNodeCounts();
1230             updateStatusLabel();
1231             clearDetailTextArea();
1232             LogRecord.resetSequenceNumber();
1233           }
1234         }
1235     );
1236 
1237     Toolkit tk = Toolkit.getDefaultToolkit();
1238     // This will actually grab all the fonts
1239 
1240     String[] fonts;
1241 
1242     if (_loadSystemFonts) {
1243       fonts = GraphicsEnvironment.
1244           getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
1245     } else {
1246       fonts = tk.getFontList();
1247     }
1248 
1249     for (int j = 0; j < fonts.length; j++) {
1250       fontCombo.addItem(fonts[j]);
1251     }
1252 
1253     fontCombo.setSelectedItem(_fontName);
1254 
1255     fontCombo.addActionListener(
1256 
1257         new ActionListener() {
1258           public void actionPerformed(ActionEvent e) {
1259             JComboBox box = (JComboBox) e.getSource();
1260             String font = (String) box.getSelectedItem();
1261             _table.setFont(new Font(font, Font.PLAIN, _fontSize));
1262             _fontName = font;
1263           }
1264         }
1265     );
1266 
1267     fontSizeCombo.addItem("8");
1268     fontSizeCombo.addItem("9");
1269     fontSizeCombo.addItem("10");
1270     fontSizeCombo.addItem("12");
1271     fontSizeCombo.addItem("14");
1272     fontSizeCombo.addItem("16");
1273     fontSizeCombo.addItem("18");
1274     fontSizeCombo.addItem("24");
1275 
1276     fontSizeCombo.setSelectedItem(String.valueOf(_fontSize));
1277     fontSizeCombo.addActionListener(
1278         new ActionListener() {
1279           public void actionPerformed(ActionEvent e) {
1280             JComboBox box = (JComboBox) e.getSource();
1281             String size = (String) box.getSelectedItem();
1282             int s = Integer.valueOf(size).intValue();
1283 
1284             setFontSizeSilently(s);
1285             refreshDetailTextArea();
1286             _fontSize = s;
1287           }
1288         }
1289     );
1290 
1291     tb.add(new JLabel(" Font: "));
1292     tb.add(fontCombo);
1293     tb.add(fontSizeCombo);
1294     tb.addSeparator();
1295     tb.addSeparator();
1296     tb.add(newButton);
1297 
1298     newButton.setAlignmentY(0.5f);
1299     newButton.setAlignmentX(0.5f);
1300 
1301     fontCombo.setMaximumSize(fontCombo.getPreferredSize());
1302     fontSizeCombo.setMaximumSize(
1303         fontSizeCombo.getPreferredSize());
1304 
1305     return (tb);
1306   }
1307 
1308 //    protected void setView(String viewString, LogTable table) {
1309 //        if (STANDARD_VIEW.equals(viewString)) {
1310 //            table.setStandardView();
1311 //        } else if (COMPACT_VIEW.equals(viewString)) {
1312 //            table.setCompactView();
1313 //        } else if (DETAILED_VIEW.equals(viewString)) {
1314 //            table.setDetailedView();
1315 //        } else {
1316 //            String message = viewString + "does not match a supported view.";
1317 //            throw new IllegalArgumentException(message);
1318 //        }
1319 //        _currentView = viewString;
1320 //    }
1321 
1322   protected void setView(String viewString, LogTable table) {
1323     if (DETAILED_VIEW.equals(viewString)) {
1324       table.setDetailedView();
1325     } else {
1326       String message = viewString + "does not match a supported view.";
1327       throw new IllegalArgumentException(message);
1328     }
1329     _currentView = viewString;
1330   }
1331 
1332   protected JComboBox createLogLevelCombo() {
1333     JComboBox result = new JComboBox();
1334     Iterator levels = getLogLevels();
1335     while (levels.hasNext()) {
1336       result.addItem(levels.next());
1337     }
1338     result.setSelectedItem(_leastSevereDisplayedLogLevel);
1339 
1340     result.addActionListener(new ActionListener() {
1341       public void actionPerformed(ActionEvent e) {
1342         JComboBox box = (JComboBox) e.getSource();
1343         LogLevel level = (LogLevel) box.getSelectedItem();
1344         setLeastSevereDisplayedLogLevel(level);
1345       }
1346     });
1347     result.setMaximumSize(result.getPreferredSize());
1348     return result;
1349   }
1350 
1351   protected void setLeastSevereDisplayedLogLevel(LogLevel level) {
1352     if (level == null || _leastSevereDisplayedLogLevel == level) {
1353       return; // nothing to do
1354     }
1355     _leastSevereDisplayedLogLevel = level;
1356     _table.getFilteredLogTableModel().refresh();
1357     updateStatusLabel();
1358   }
1359 
1360   /***
1361    * Ensures that the Table's ScrollPane Viewport will "track" with updates
1362    * to the Table.  When the vertical scroll bar is at its bottom anchor
1363    * and tracking is enabled then viewport will stay at the bottom most
1364    * point of the component.  The purpose of this feature is to allow
1365    * a developer to watch the table as messages arrive and not have to
1366    * scroll after each new message arrives.  When the vertical scroll bar
1367    * is at any other location, then no tracking will happen.
1368    * @deprecated tracking is now done automatically.
1369    */
1370   protected void trackTableScrollPane() {
1371     // do nothing
1372   }
1373 
1374   protected void centerFrame(JFrame frame) {
1375     Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1376     Dimension comp = frame.getSize();
1377 
1378     frame.setLocation(((screen.width - comp.width) / 2),
1379         ((screen.height - comp.height) / 2));
1380 
1381   }
1382 
1383   /***
1384    * Uses a JFileChooser to select a file to opened with the
1385    * LF5 GUI.
1386    */
1387   protected void requestOpen() {
1388     JFileChooser chooser;
1389 
1390     if (_fileLocation == null) {
1391       chooser = new JFileChooser();
1392     } else {
1393       chooser = new JFileChooser(_fileLocation);
1394     }
1395 
1396     int returnVal = chooser.showOpenDialog(_logMonitorFrame);
1397     if (returnVal == JFileChooser.APPROVE_OPTION) {
1398       File f = chooser.getSelectedFile();
1399       if (loadLogFile(f)) {
1400         _fileLocation = chooser.getSelectedFile();
1401         _mruFileManager.set(f);
1402         updateMRUList();
1403       }
1404     }
1405   }
1406 
1407   /***
1408    * Uses a Dialog box to accept a URL to a file to be opened
1409    * with the LF5 GUI.
1410    */
1411   protected void requestOpenURL() {
1412     LogFactor5InputDialog inputDialog = new LogFactor5InputDialog(
1413         getBaseFrame(), "Open URL", "URL:");
1414     String temp = inputDialog.getText();
1415 
1416     if (temp != null) {
1417       if (temp.indexOf("://") == -1) {
1418         temp = "http://" + temp;
1419       }
1420 
1421       try {
1422         URL url = new URL(temp);
1423         if (loadLogFile(url)) {
1424           _mruFileManager.set(url);
1425           updateMRUList();
1426         }
1427       } catch (MalformedURLException e) {
1428         LogFactor5ErrorDialog error = new LogFactor5ErrorDialog(
1429             getBaseFrame(), "Error reading URL.");
1430       }
1431     }
1432   }
1433 
1434   /***
1435    * Removes old file list and creates a new file list
1436    * with the updated MRU list.
1437    */
1438   protected void updateMRUList() {
1439     JMenu menu = _logMonitorFrame.getJMenuBar().getMenu(0);
1440     menu.removeAll();
1441     menu.add(createOpenMI());
1442     menu.add(createOpenURLMI());
1443     menu.addSeparator();
1444     menu.add(createCloseMI());
1445     createMRUFileListMI(menu);
1446     menu.addSeparator();
1447     menu.add(createExitMI());
1448   }
1449 
1450   protected void requestClose() {
1451     setCallSystemExitOnClose(false);
1452     closeAfterConfirm();
1453   }
1454 
1455   /***
1456    * Opens a file in the MRU list.
1457    */
1458   protected void requestOpenMRU(ActionEvent e) {
1459     String file = e.getActionCommand();
1460     StringTokenizer st = new StringTokenizer(file);
1461     String num = st.nextToken().trim();
1462     file = st.nextToken("\n");
1463 
1464     try {
1465       int index = Integer.parseInt(num) - 1;
1466 
1467       InputStream in = _mruFileManager.getInputStream(index);
1468       LogFileParser lfp = new LogFileParser(in);
1469       lfp.parse(this);
1470 
1471       _mruFileManager.moveToTop(index);
1472       updateMRUList();
1473 
1474     } catch (Exception me) {
1475       LogFactor5ErrorDialog error = new LogFactor5ErrorDialog(
1476           getBaseFrame(), "Unable to load file " + file);
1477     }
1478 
1479   }
1480 
1481   protected void requestExit() {
1482     _mruFileManager.save();
1483     setCallSystemExitOnClose(true);
1484     closeAfterConfirm();
1485   }
1486 
1487   protected void closeAfterConfirm() {
1488     StringBuffer message = new StringBuffer();
1489 
1490     if (_callSystemExitOnClose == false) {
1491       message.append("Are you sure you want to close the logging ");
1492       message.append("console?\n");
1493       message.append("(Note: This will not shut down the Virtual Machine,\n");
1494       message.append("or the Swing event thread.)");
1495     } else {
1496       message.append("Are you sure you want to exit?\n");
1497       message.append("This will shut down the Virtual Machine.\n");
1498     }
1499 
1500     String title =
1501         "Are you sure you want to dispose of the Logging Console?";
1502 
1503     if (_callSystemExitOnClose == true) {
1504       title = "Are you sure you want to exit?";
1505     }
1506     int value = JOptionPane.showConfirmDialog(
1507         _logMonitorFrame,
1508         message.toString(),
1509         title,
1510         JOptionPane.OK_CANCEL_OPTION,
1511         JOptionPane.QUESTION_MESSAGE,
1512         null
1513     );
1514 
1515     if (value == JOptionPane.OK_OPTION) {
1516       dispose();
1517     }
1518   }
1519 
1520   protected Iterator getLogLevels() {
1521     return _levels.iterator();
1522   }
1523 
1524   protected Iterator getLogTableColumns() {
1525     return _columns.iterator();
1526   }
1527 
1528   /***
1529    * Loads and parses a log file.
1530    */
1531   protected boolean loadLogFile(File file) {
1532     boolean ok = false;
1533     try {
1534       LogFileParser lfp = new LogFileParser(file);
1535       lfp.parse(this);
1536       ok = true;
1537     } catch (IOException e) {
1538       LogFactor5ErrorDialog error = new LogFactor5ErrorDialog(
1539           getBaseFrame(), "Error reading " + file.getName());
1540     }
1541 
1542     return ok;
1543   }
1544 
1545   /***
1546    * Loads a parses a log file running on a server.
1547    */
1548   protected boolean loadLogFile(URL url) {
1549     boolean ok = false;
1550     try {
1551       LogFileParser lfp = new LogFileParser(url.openStream());
1552       lfp.parse(this);
1553       ok = true;
1554     } catch (IOException e) {
1555       LogFactor5ErrorDialog error = new LogFactor5ErrorDialog(
1556           getBaseFrame(), "Error reading URL:" + url.getFile());
1557     }
1558     return ok;
1559   }
1560   //--------------------------------------------------------------------------
1561   //   Private Methods:
1562   //--------------------------------------------------------------------------
1563 
1564   //--------------------------------------------------------------------------
1565   //   Nested Top-Level Classes or Interfaces:
1566   //--------------------------------------------------------------------------
1567 
1568   class LogBrokerMonitorWindowAdaptor extends WindowAdapter {
1569     protected LogBrokerMonitor _monitor;
1570 
1571     public LogBrokerMonitorWindowAdaptor(LogBrokerMonitor monitor) {
1572       _monitor = monitor;
1573     }
1574 
1575     public void windowClosing(WindowEvent ev) {
1576       _monitor.requestClose();
1577     }
1578   }
1579 }
1580 
1581