1 package net.sf.logdistiller.gui;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 import java.awt.Font;
18 import java.awt.LayoutManager;
19 import java.awt.event.ActionEvent;
20 import java.awt.event.KeyEvent;
21 import java.io.*;
22 import java.lang.reflect.*;
23 import java.text.MessageFormat;
24 import java.text.ParseException;
25 import java.util.*;
26 import javax.swing.*;
27 import javax.xml.parsers.ParserConfigurationException;
28
29 import org.xml.sax.ErrorHandler;
30 import org.xml.sax.SAXException;
31 import org.xml.sax.SAXParseException;
32
33 import com.jgoodies.forms.builder.DefaultFormBuilder;
34 import com.jgoodies.forms.factories.ButtonBarFactory;
35 import com.jgoodies.forms.factories.DefaultComponentFactory;
36 import com.jgoodies.forms.layout.FormLayout;
37 import com.sun.syndication.io.XmlReader;
38
39 import org.apache.commons.io.IOUtils;
40
41 import net.sf.logdistiller.LogDistillation;
42 import net.sf.logdistiller.LogDistiller;
43 import net.sf.logdistiller.LogEvent;
44 import net.sf.logdistiller.LogType;
45 import net.sf.logdistiller.LogTypes;
46 import net.sf.logdistiller.reports.TextReport;
47 import net.sf.logdistiller.util.FormatUtil;
48 import net.sf.logdistiller.util.PropertiesReplacer;
49 import net.sf.logdistiller.xml.DOMConfigurator;
50 import net.sf.logdistiller.xml.LogDistillerEntityResolver;
51
52
53
54
55 public class MainPanel
56 implements Runnable
57 {
58 private static final String TITLE = "LogDistiller " + LogDistiller.getVersion() + " interactive console";
59
60 private static final String ABOUT = TITLE + "\n\nCopyright (C) 2004-2009 Hervé Boutemy. All rights reserved.";
61
62 private final JFrame frame;
63
64 public MainPanel( JFrame frame )
65 {
66 this.frame = frame;
67 frame.setTitle( TITLE );
68 }
69
70 private Thread reloadThread;
71
72 protected JPanel panel = new JPanel();
73
74 private JTextField tfRules = new JTextField( "open or create a rules configuration file..." );
75
76 private JTextField tfSourceFile = new JTextField();
77
78 private JTextField tfSourceStats = new JTextField();
79
80 private JTextField tfOutputDir = new JTextField();
81
82 private JButton btRun = new JButton( "run" );
83
84 private JButton btBatch = new JButton( "batch" );
85
86 private JButton btSourceFile = new JButton( "..." );
87
88 private JButton btOutputDir = new JButton( "..." );
89
90 private JTextArea taResult = new JTextArea();
91
92 private LongProgressBar progress = new LongProgressBar();
93
94 private void initComponents()
95 {
96 tfSourceFile.setEditable( false );
97 btSourceFile.addActionListener( SwingAdapter.getActionListener( this, "btSourceFileActionPerformed" ) );
98 tfSourceStats.setEditable( false );
99 tfOutputDir.setEditable( false );
100 btOutputDir.addActionListener( SwingAdapter.getActionListener( this, "btOutputDirActionPerformed" ) );
101 tfRules.setEditable( false );
102 taResult.setEditable( false );
103 btRun.addActionListener( SwingAdapter.getActionListener( this, "btRunActionPerformed" ) );
104 btRun.setEnabled( false );
105 btBatch.addActionListener( SwingAdapter.getActionListener( this, "btBatchActionPerformed" ) );
106 btBatch.setEnabled( false );
107
108 taResult.setFont( new Font( "Monospaced", Font.PLAIN, taResult.getFont().getSize() ) );
109
110 progress.setStringPainted( true );
111 progress.setFont( new Font( "Monospaced", Font.PLAIN, progress.getFont().getSize() ) );
112 }
113
114 private void addLabel( String label, String id )
115 {
116 panel.add( new JLabel( label ), id );
117 }
118
119 private void addSeparator( String label, String id )
120 {
121 panel.add( DefaultComponentFactory.getInstance().createSeparator( label ), id );
122 }
123
124 public final static SimpleLayoutConstraintsManager SIMPLE_LAYOUT_CONSTRAINTS_MANAGER =
125 SimpleLayoutConstraintsManager.getLayoutConstraintsManager( MainPanel.class.getResourceAsStream( "gui.xml" ) );
126
127 public LayoutManager createLayout( String layoutId )
128 {
129 return MainPanel.SIMPLE_LAYOUT_CONSTRAINTS_MANAGER.getLayout( layoutId );
130 }
131
132 public JComponent buildPanel()
133 {
134 initComponents();
135 buildMenuBar();
136
137 panel.setBorder( com.jgoodies.forms.factories.Borders.DIALOG_BORDER );
138 panel.setLayout( createLayout( "mainPanel" ) );
139
140
141
142
143
144
145
146
147
148 panel.add( tfRules, "tfRules" );
149
150 addSeparator( "logs", "sep2" );
151 addLabel( "log file:", "lblSourceFile" );
152 panel.add( tfSourceFile, "tfSourceFile" );
153 panel.add( btSourceFile, "btSourceFile" );
154 panel.add( tfSourceStats, "tfSourceStats" );
155
156 addLabel( "output directory:", "lblOutputDir" );
157 panel.add( tfOutputDir, "tfOutputDir" );
158 panel.add( btOutputDir, "btOutputDir" );
159
160 JPanel bbar = ButtonBarFactory.buildRightAlignedBar( new JButton[] { btRun, btBatch } );
161 FormLayout layout = new FormLayout( "default:grow, 3dlu, pref" );
162 DefaultFormBuilder builder = new DefaultFormBuilder( layout );
163 builder.append( progress, bbar );
164 panel.add( builder.getPanel(), "pRun" );
165
166 addSeparator( "result", "sep3" );
167 panel.add( new JScrollPane( taResult ), "taResult" );
168
169 reloadThread = new Thread( this );
170 reloadThread.setDaemon( true );
171 reloadThread.setPriority( Thread.MIN_PRIORITY );
172 reloadThread.start();
173 return panel;
174 }
175
176 private void buildMenuBar()
177 {
178 JMenuBar menuBar = new JMenuBar();
179
180 JMenu fileMenu = new JMenu( "File" );
181 fileMenu.setMnemonic( KeyEvent.VK_F );
182
183
184 JMenuItem fileOpenMenuItem = new JMenuItem( "Open rules file...", KeyEvent.VK_O );
185 fileOpenMenuItem.addActionListener( SwingAdapter.getActionListener( this, "btOpenActionPerformed" ) );
186 fileMenu.add( fileOpenMenuItem );
187
188
189 JMenuItem fileNewMenuItem = new JMenuItem( "New rules file...", KeyEvent.VK_N );
190 fileNewMenuItem.addActionListener( SwingAdapter.getActionListener( this, "btNewActionPerformed" ) );
191 fileMenu.add( fileNewMenuItem );
192
193
194 JMenuItem exitMenuItem = new JMenuItem( "Exit", KeyEvent.VK_X );
195 exitMenuItem.addActionListener( SwingAdapter.getActionListener( this, "exit" ) );
196 fileMenu.add( exitMenuItem );
197
198
199 JMenu helpMenu = new JMenu( "Help" );
200 helpMenu.setMnemonic( KeyEvent.VK_H );
201
202
203 JMenuItem aboutMenuItem = new JMenuItem( "About...", KeyEvent.VK_A );
204 aboutMenuItem.addActionListener( SwingAdapter.getActionListener( this, "about" ) );
205 helpMenu.add( aboutMenuItem );
206
207 menuBar.add( fileMenu );
208 menuBar.add( helpMenu );
209 frame.setJMenuBar( menuBar );
210 }
211
212 public void about( ActionEvent ae )
213 {
214 JOptionPane.showMessageDialog( frame, ABOUT, "About", JOptionPane.INFORMATION_MESSAGE );
215 }
216
217 public void exit( ActionEvent ae )
218 {
219 System.exit( 0 );
220 }
221
222 private File currentDir = new File( "." );
223
224 private File configurationFile = null;
225
226 private long configurationFileLastModified;
227
228 public void btOpenActionPerformed( ActionEvent ae )
229 {
230 reloadConfigurationFileEnabled = false;
231 JFileChooser fc = new JFileChooser( currentDir );
232 int ret = fc.showOpenDialog( frame );
233 if ( ret == JFileChooser.APPROVE_OPTION )
234 {
235 selectConfigurationFile( fc.getSelectedFile() );
236 }
237 reloadConfigurationFileEnabled = true;
238 }
239
240 private LogDistiller ld = null;
241
242 public void selectConfigurationFile( File newConfiguration )
243 {
244 initProgress();
245 configurationFile = newConfiguration;
246 configurationFileLastModified = configurationFile.lastModified();
247 currentDir = configurationFile.getParentFile();
248 frame.setTitle( TITLE + ": " + configurationFile.getName() );
249
250 tfRules.setText( "reading " + configurationFile.getName() );
251 try
252 {
253 taResult.setText( IOUtils.toString( new XmlReader( configurationFile ) ) );
254 DOMConfigurator domConfigurator = new DOMConfigurator( new HashMap<String, String>() );
255 ld = domConfigurator.read( configurationFile, new GuiSAXErrorHandler() );
256 compatibilityUpdate( ld );
257
258 LogDistiller.LogType logtype = ld.getLogType();
259 String logeventType = ( logtype != null ) ? logtype.getId() : null;
260
261
262 if ( logeventType != null )
263 {
264 if ( LogTypes.getLogType( logeventType ) == null )
265 {
266 taResult.setText( "Unknown '" + logeventType + "' logtype.\n" + "Valid values: "
267 + LogTypes.listAllLogTypeIds() );
268 logeventType += " (unknown)";
269 }
270 }
271 else
272 {
273 logeventType = "undefined";
274 taResult.setText( "Undefined logtype.\n" + "Valid values: " + LogTypes.listAllLogTypeIds() );
275 }
276 try
277 {
278 LogDistillation distillation = new LogDistillation( ld );
279 logtypeDescription = distillation.getLogTypeDescription();
280 }
281 catch ( Exception e )
282 {
283 displayException( e );
284 }
285
286
287 selectOutputDir( new File( ld.getOutput().getDirectory() ) );
288
289
290 Object[] args =
291 new Object[] { ld.getId(), ld.getDescription(), new Integer( ld.getGroups().length ),
292 new Integer( ld.getCategories().length ), logeventType };
293 MessageFormat mf =
294 new MessageFormat( "{0} - {1}: {2,choice,0#no group|1#one group|1<{2,number,integer} groups}"
295 + " {3,choice,0#with no category|1#in one category|1<in {3,number,integer} categories}"
296 + ", logtype: {4}." );
297 tfRules.setText( mf.format( args ) );
298 }
299 catch ( RuntimeException re )
300 {
301 ld = null;
302 displayException( re );
303 }
304 catch ( IOException ioe )
305 {
306 ld = null;
307 displayException( ioe );
308 }
309 catch ( ParserConfigurationException pce )
310 {
311 ld = null;
312 displayException( pce );
313 }
314 catch ( SAXException se )
315 {
316 ld = null;
317 displayException( se );
318 }
319 updateBtRunState();
320 }
321
322
323
324
325
326
327
328 private void compatibilityUpdate( LogDistiller ld )
329 {
330 if ( ld.getLogType() != null )
331 {
332
333 return;
334 }
335 String logeventType = (String) ld.getOutput().getParams().get( "logevent.type" );
336 if ( logeventType != null )
337 {
338 String warning =
339 "parameter 'logevent.type' is deprecated, please use element 'logtype' from "
340 + LogDistillerEntityResolver.LATEST_DTD + " in your rules file";
341 ld.addWarning( warning );
342 ld.buildCompatibilityLogType( logeventType );
343 }
344 }
345
346 private final Runnable runnableReloadConfigurationFile = SwingAdapter.getRunnable( this, "reloadConfigurationFile" );
347
348 private boolean reloadConfigurationFileEnabled = true;
349
350 public void reloadConfigurationFile()
351 {
352 selectConfigurationFile( configurationFile );
353 initProgress();
354 }
355
356 public class GuiSAXErrorHandler
357 implements ErrorHandler
358 {
359 public void error( SAXParseException spe )
360 {
361 taResult.append( "Parsing error on line " + spe.getLineNumber() + " and column " + spe.getColumnNumber()
362 + ": " + spe.getMessage() + "\n" );
363 Exception e = spe.getException();
364 if ( e != null )
365 {
366 displayException( e );
367 }
368 }
369
370 public void fatalError( SAXParseException spe )
371 {
372 error( spe );
373 }
374
375 public void warning( SAXParseException spe )
376 {
377 taResult.append( "Parsing warning on line " + spe.getLineNumber() + " and column " + spe.getColumnNumber()
378 + ": " + spe.getMessage() + "\n" );
379 Exception e = spe.getException();
380 if ( e != null )
381 {
382 displayException( e );
383 }
384 }
385 }
386
387 private void displayException( Throwable t )
388 {
389 StringWriter sw = new StringWriter();
390 PrintWriter out = new PrintWriter( sw );
391 t.printStackTrace( out );
392 out.close();
393 taResult.append( sw.toString() );
394 }
395
396 private LogType.Description logtypeDescription = null;
397
398 public void btNewActionPerformed( ActionEvent ae )
399 {
400 NewDialog dlg = new NewDialog( currentDir );
401 File newConfiguration = dlg.showNewConfigurationDialog( frame );
402 taResult.setText( "" );
403 if ( newConfiguration != null )
404 {
405 selectConfigurationFile( newConfiguration );
406 }
407 }
408
409 private File sourceFile = null;
410
411 private long sourceFileLastModified;
412
413 public void btSourceFileActionPerformed( ActionEvent ae )
414 {
415 JFileChooser fc = new JFileChooser( ( sourceFile == null ) ? currentDir : sourceFile.getParentFile() );
416 int ret = fc.showOpenDialog( frame );
417 if ( ret == JFileChooser.APPROVE_OPTION )
418 {
419 selectSourceFile( fc.getSelectedFile() );
420 }
421 }
422
423 public void selectSourceFile( File newSourceFile )
424 {
425 sourceFile = newSourceFile;
426 tfSourceFile.setText( sourceFile.getName() );
427 initProgress();
428 if ( !sourceFile.canRead() )
429 {
430 sourceFileLastModified = -1;
431 taResult.setText( "file not found: " + sourceFile.getAbsolutePath() );
432 return;
433 }
434 sourceFileLastModified = sourceFile.lastModified();
435 tfSourceStats.setText( "file size: " + FormatUtil.formatSize( sourceFile.length() ) );
436 progress.setMinimum( 0 );
437 progress.setLongMaximum( sourceFile.length() );
438 updateBtRunState();
439 }
440
441 private final Runnable runnableReloadSourceFile = SwingAdapter.getRunnable( this, "reloadSourceFile" );
442
443 public void reloadSourceFile()
444 {
445 setResultText( "" );
446 selectSourceFile( sourceFile );
447 }
448
449 private File outputDir = null;
450
451 public void btOutputDirActionPerformed( ActionEvent ae )
452 {
453 JFileChooser fc = new JFileChooser( ( outputDir == null ) ? currentDir : outputDir.getParentFile() );
454 fc.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY );
455 int ret = fc.showOpenDialog( frame );
456 if ( ret == JFileChooser.APPROVE_OPTION )
457 {
458 selectOutputDir( fc.getSelectedFile() );
459 }
460 }
461
462 private void selectOutputDir( File output )
463 {
464 outputDir = output;
465 tfOutputDir.setText( outputDir.getAbsolutePath() );
466 initProgress();
467 updateBtRunState();
468 }
469
470 private void updateBtRunState()
471 {
472 boolean enabled =
473 ( ld != null ) && ( logtypeDescription != null ) && ( sourceFile != null ) && ( outputDir != null );
474 btRun.setEnabled( enabled );
475 btBatch.setEnabled( enabled );
476 }
477
478 private String resultText = "";
479
480 public void setResultText()
481 {
482 taResult.setText( resultText );
483 }
484
485 private final Runnable runnableSetResultText = SwingAdapter.getRunnable( this, "setResultText" );
486
487
488
489
490
491
492 private void setResultText( String text )
493 {
494 this.resultText = text;
495 if ( SwingUtilities.isEventDispatchThread() )
496 {
497 taResult.setText( resultText );
498 }
499 else
500 {
501 SwingUtilities.invokeLater( runnableSetResultText );
502 }
503 }
504
505 private long progressValue = 0;
506
507 private int progressCount = 0;
508
509 private String progressText = null;
510
511 private final Runnable runnableUpdateProgress = SwingAdapter.getRunnable( this, "updateProgress" );
512
513 public void updateProgress()
514 {
515 if ( progressText == null )
516 {
517 progress.setValue( progress.getMaximum() );
518 progress.setString( "processed " + progressValue + " logevents" );
519 }
520 else
521 {
522 progress.setLongValue( progressValue );
523 progress.setString( progressCount + " - " + progressText );
524 }
525 }
526
527 private void initProgress()
528 {
529 progress.setString( "0%" );
530 progress.setValue( 0 );
531 }
532
533 private final Runnable runnableRunLogDistillation = SwingAdapter.getRunnable( this, "runLogDistillation" );
534
535 public void runLogDistillation()
536 {
537 try
538 {
539 LogEvent.Factory factory =
540 logtypeDescription.newFactory( new InputStreamReader( new FileInputStream( sourceFile ) ),
541 sourceFile.toURL().toString() );
542 ld.getOutput().setDirectory( outputDir.getAbsolutePath() );
543 ld.getOutput().setContent( "interactive run" );
544 LogDistillation distillation = new LogDistillation( ld );
545 distillation.begin();
546 LogEvent le;
547 long lastProgress = System.currentTimeMillis();
548 while ( ( le = factory.nextEvent() ) != null )
549 {
550 distillation.processLogEvent( le );
551 long time = System.currentTimeMillis();
552 if ( ( time - lastProgress ) > 100 )
553 {
554 progressValue = distillation.getEventBytes();
555 progressCount = distillation.getEventCount();
556 progressText = le.getTimestamp();
557 SwingUtilities.invokeLater( runnableUpdateProgress );
558 lastProgress = time;
559 }
560 }
561 distillation.end();
562 progressValue = distillation.getEventCount();
563 progressText = null;
564 SwingUtilities.invokeLater( runnableUpdateProgress );
565
566 StringWriter sw = new StringWriter();
567 new TextReport().report( distillation, sw );
568 setResultText( sw.toString() );
569 }
570 catch ( RuntimeException re )
571 {
572 ld = null;
573 displayException( re );
574 }
575 catch ( IOException ioe )
576 {
577 ld = null;
578 displayException( ioe );
579 }
580 catch ( ParseException pe )
581 {
582 ld = null;
583 displayException( pe );
584 }
585 setAllButtonsEnabled( true );
586 reloadConfigurationFileEnabled = true;
587 }
588
589 public void btRunActionPerformed( ActionEvent ae )
590 {
591 reloadConfigurationFileEnabled = false;
592 setAllButtonsEnabled( false );
593 taResult.setText( "" );
594 new Thread( runnableRunLogDistillation ).start();
595 }
596
597 public void btBatchActionPerformed( ActionEvent ae )
598 {
599 taResult.setText( "" );
600 initProgress();
601 try
602 {
603 String text = IOUtils.toString( MainPanel.class.getResourceAsStream( "reference-build.xml" ), "UTF-8" );
604 Map<String, String> properties = new HashMap<String, String>();
605 properties.put( "id", ld.getId() );
606 properties.put( "configurationFile", configurationFile.getPath() );
607 properties.put( "sourceDir", sourceFile.getAbsoluteFile().getParentFile().getPath() );
608 properties.put( "sourceFile", sourceFile.getName() + "*" );
609 properties.put( "destDir", outputDir.getPath() );
610 PropertiesReplacer repl = new PropertiesReplacer( properties, "#(", ")" );
611 taResult.setText( repl.replaceProperties( text ) );
612 }
613 catch ( Exception e )
614 {
615 displayException( e );
616 }
617 }
618
619 public void setAllButtonsEnabled( boolean enable )
620 {
621 btBatch.setEnabled( enable );
622 btOutputDir.setEnabled( enable );
623 btRun.setEnabled( enable );
624 btSourceFile.setEnabled( enable );
625 if ( enable )
626 {
627 updateBtRunState();
628 }
629 }
630
631
632
633
634 public void run()
635 {
636 while ( true )
637 {
638 try
639 {
640 Thread.sleep( 1000 );
641 }
642 catch ( InterruptedException ie )
643 {
644 ie.printStackTrace();
645 }
646 if ( reloadConfigurationFileEnabled && ( configurationFile != null )
647 && ( configurationFileLastModified != configurationFile.lastModified() ) )
648 {
649 try
650 {
651 SwingUtilities.invokeAndWait( runnableReloadConfigurationFile );
652 }
653 catch ( InvocationTargetException ite )
654 {
655 displayException( ite );
656 }
657 catch ( InterruptedException ie )
658 {
659 displayException( ie );
660 }
661 }
662 if ( ( sourceFile != null ) && ( sourceFileLastModified != sourceFile.lastModified() ) )
663 {
664 try
665 {
666 SwingUtilities.invokeAndWait( runnableReloadSourceFile );
667 }
668 catch ( InvocationTargetException ite )
669 {
670 displayException( ite );
671 }
672 catch ( InterruptedException ie )
673 {
674 displayException( ie );
675 }
676 }
677 }
678 }
679 }