001    /**
002     * MainTester.java
003     * jCOLIBRI2 framework. 
004     * @author Juan A. Recio-García.
005     * GAIA - Group for Artificial Intelligence Applications
006     * http://gaia.fdi.ucm.es
007     * 03/07/2007
008     */
009    package jcolibri.test.main;
010    
011    import java.awt.BorderLayout;
012    import java.awt.Dimension;
013    import java.awt.HeadlessException;
014    import java.awt.event.ActionEvent;
015    import java.awt.event.ActionListener;
016    import java.awt.event.WindowAdapter;
017    import java.awt.event.WindowEvent;
018    import java.io.BufferedReader;
019    import java.io.ByteArrayOutputStream;
020    import java.io.FilterOutputStream;
021    import java.io.IOException;
022    import java.io.InputStreamReader;
023    import java.io.OutputStream;
024    import java.io.PrintStream;
025    import java.lang.reflect.Method;
026    import java.net.URL;
027    import java.util.ArrayList;
028    import java.util.Collection;
029    import java.util.List;
030    
031    import javax.swing.BorderFactory;
032    import javax.swing.Box;
033    import javax.swing.BoxLayout;
034    import javax.swing.JButton;
035    import javax.swing.JDialog;
036    import javax.swing.JEditorPane;
037    import javax.swing.JFrame;
038    import javax.swing.JLabel;
039    import javax.swing.JList;
040    import javax.swing.JPanel;
041    import javax.swing.JScrollPane;
042    import javax.swing.JSplitPane;
043    import javax.swing.JTabbedPane;
044    import javax.swing.JTextArea;
045    import javax.swing.JWindow;
046    import javax.swing.ListSelectionModel;
047    import javax.swing.UIManager;
048    import javax.swing.event.HyperlinkEvent;
049    import javax.swing.event.HyperlinkListener;
050    import javax.swing.event.ListSelectionEvent;
051    import javax.swing.event.ListSelectionListener;
052    
053    import jcolibri.util.FileIO;
054    
055    import org.apache.log4j.ConsoleAppender;
056    import org.apache.log4j.Layout;
057    import org.apache.log4j.Logger;
058    import org.apache.log4j.WriterAppender;
059    
060    /**
061     * Main tester application that executes all the examples 
062     * showing also related documentation to each one. 
063     * 
064     * @author Juan A. Recio-Garcia
065     * @version 1.0
066     */
067    public class MainTester extends JFrame
068    {
069        private static final long serialVersionUID = 1L;
070    
071        JList list;
072        List<ExampleInfo> info;
073        JTabbedPane tabPane;
074        JTextArea displayPane;
075        JButton run;
076        JDialog mapDialog;
077        
078        /**
079         * Constructor that creates the tester using a given config file
080         */
081        public MainTester(String configfile)
082        {
083            info = parseExampleInfo(configfile);
084            
085            
086            try
087            {
088                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
089            } catch (Exception e1)
090            {
091            }
092            
093            this.setSize(new Dimension(800,600));
094            this.setTitle("jCOLIBRI2 Tester");
095            Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
096            setBounds((screenSize.width - this.getWidth()) / 2,
097                    (screenSize.height - this.getHeight()) / 2, 
098                    getWidth(),
099                    getHeight());
100            
101            JPanel panelUp = new JPanel();
102            panelUp.setBorder(BorderFactory.createTitledBorder("Available Tests"));
103            JPanel panelDown = new JPanel();
104            panelDown.setBorder(BorderFactory.createTitledBorder("Execution log"));
105            
106            JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT,panelUp, panelDown);
107            split.setDividerLocation(400);
108            this.getContentPane().add(split);
109    
110            JPanel topLeft = new JPanel();
111            topLeft.setLayout(new BorderLayout());
112            
113            Object[] data = new Object[info.size()];
114            int i=0;
115            for(ExampleInfo ei: info)
116                data[i++]=ei.getName();
117            list = new JList(data);
118            list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
119            list.setLayoutOrientation(JList.VERTICAL);
120            JScrollPane listScroller = new JScrollPane(list);
121            
122            topLeft.add(listScroller, BorderLayout.CENTER);
123            
124            run = new JButton("Execute");
125            
126            run.addActionListener(new ActionListener(){
127                public void actionPerformed(ActionEvent e)
128                {
129                    runExample();
130                }  
131            });
132            
133            mapDialog = new JDialog(this,true);
134            mapDialog.getContentPane().add(new HTMLBrowser(FileIO.findFile("jcolibri/test/main/map.html")));
135            mapDialog.setSize(new Dimension(800,600));
136            mapDialog.setTitle("jCOLIBRI2 Examples Map");
137            mapDialog.setBounds((screenSize.width - mapDialog.getWidth()) / 2,
138                    (screenSize.height - mapDialog.getHeight()) / 2, 
139                    mapDialog.getWidth(),
140                    mapDialog.getHeight());
141            JButton map = new JButton("Map");
142            map.addActionListener(new ActionListener(){
143                public void actionPerformed(ActionEvent e)
144                {
145                    mapDialog.setVisible(true);
146                }  
147            });
148            
149            JPanel buttonsPanel = new JPanel();
150            buttonsPanel.setLayout(new BorderLayout(2,1));
151            buttonsPanel.add(run,BorderLayout.CENTER);
152            buttonsPanel.add(map,BorderLayout.EAST);
153            
154            topLeft.add(buttonsPanel, BorderLayout.SOUTH);
155            
156            panelUp.setLayout(new BorderLayout());
157            panelUp.add(topLeft, BorderLayout.WEST);
158            
159            tabPane = new JTabbedPane();
160            panelUp.add(tabPane, BorderLayout.CENTER);
161            
162    
163            list.addListSelectionListener(new ListSelectionListener(){
164    
165                public void valueChanged(ListSelectionEvent e) {
166                        if (e.getValueIsAdjusting() == true)
167                            return;
168                        if (list.getSelectedIndex() == -1) 
169                            return;
170                        int i = list.getSelectedIndex();
171                        setExample(i);
172                }
173            });
174            
175            this.addWindowListener(new WindowAdapter(){
176                    public void windowClosing(WindowEvent e){
177                        System.exit(0);
178                    }
179            });
180            
181            displayPane = new JTextArea();
182            displayPane.setEditable(false);
183            panelDown.setLayout(new BorderLayout());
184            panelDown.add(new JScrollPane(displayPane));
185            
186            PrintStream aPrintStream  =
187                   new PrintStream(
188                     new FilteredStream(
189                       new ByteArrayOutputStream()));
190            System.setOut(aPrintStream);
191            System.setErr(aPrintStream);
192            
193            ConsoleAppender a = (ConsoleAppender) Logger.getRootLogger().getAllAppenders().nextElement();
194            Layout l = a.getLayout();
195            Logger.getRootLogger().addAppender(new WriterAppender(l,aPrintStream));
196            Logger.getRootLogger().removeAppender(a);
197            
198        }
199        
200        /**
201         * Runs a test in a different thread.
202         */
203        public void runExample()
204        {
205            run.setEnabled(false);
206            try
207            {
208                int i = list.getSelectedIndex();
209                if(i==-1)
210                    return;
211                
212                displayPane.setText("");
213                
214                ExampleInfo ei = this.info.get(i);
215                
216                MethodRunner mr = null;
217                Class c = ei.getMainClass();
218                Method[] methods = c.getMethods();
219                for(Method m: methods)
220                    if(m.getName().equals("main"))
221                        mr=new MethodRunner(m);
222                if(mr==null)
223                    return;
224                Thread executionThread = new Thread(mr);
225                executionThread.start();
226                
227            } catch (Exception e)
228            {
229                org.apache.commons.logging.LogFactory.getLog(this.getClass()).error(e); 
230            }
231        }
232        
233        /**
234         * Thread for running a test
235         * @author Juan A. Recio-Garcia
236         * @version 1.0
237         */
238        class MethodRunner implements Runnable
239        {
240            Method method;
241            
242            MethodRunner(Method m)
243            {
244                method = m;
245            }
246            
247            public void run()
248            {
249                Object[] args = new Object[1];
250                args[0] = null;
251                try
252                {
253                    method.invoke(null, args);
254                } catch (Exception e)
255                {
256                    org.apache.commons.logging.LogFactory.getLog(this.getClass()).error(e);
257                    e.printStackTrace();
258                }
259                org.apache.commons.logging.LogFactory.getLog(MainTester.class).info("Test execution finished");
260                run.setEnabled(true);
261            }
262        }
263        
264        /**
265         * Shows an example in the window.
266         */
267        public void setExample(int i)
268        {
269            try
270            {
271                ExampleInfo ei = this.info.get(i);
272                tabPane.removeAll();
273                
274                JEditorPane ep = new JEditorPane();
275                ep.setContentType("text/html");
276                ep.setText("<font face=\"verdana, arial, helvetica\"><b>"+ei.getDescription()+"</b></font>");
277                ep.setEditable(false);
278                tabPane.add("Description", new JScrollPane(ep));
279                
280                ep = new JEditorPane(ei.getSource());
281                ep.setContentType("text/html");
282                ep.setEditable(false);
283                tabPane.add("Source", new JScrollPane(ep));
284                
285                for(URL url: ei.getDoc())
286                {
287                    int b = url.getFile().lastIndexOf('/')+1;
288                    int e = url.getFile().lastIndexOf(".html");
289                    String name = url.getFile().substring(b,e);
290                    if(name.equals("package-summary"))
291                    {
292                        String aux = url.getFile().substring(0,b-1);
293                        int x = aux.lastIndexOf('/')+1;
294                        name = aux.substring(x);
295                    }
296                    tabPane.add("[Doc]"+name, new HTMLBrowser(url));
297                }
298            } catch (IOException e)
299            {
300                org.apache.commons.logging.LogFactory.getLog(this.getClass()).error(e);
301            }
302        }
303        
304        /**
305         * Main method
306         */
307        public static void main(String[] args)
308        {
309            MainTester main = new MainTester("jcolibri/test/main/examples.config");
310            main.setVisible(true);
311            main.new LogoFrame(jcolibri.util.FileIO.findFile("/jcolibri/test/main/jcolibri2.jpg"),2000);
312    
313        }
314    
315        /**
316         * Parses the information in the config file
317         */
318        public List<ExampleInfo> parseExampleInfo(String file)
319        {
320            ArrayList<ExampleInfo> info = new ArrayList<ExampleInfo>();
321    
322            try
323            {
324                BufferedReader br = null;
325                br = new BufferedReader( new InputStreamReader(FileIO.findFile(file).openStream()));
326                if (br == null)
327                    throw new Exception("Error opening file: " + file);
328                String line = "";
329                ExampleInfo ei;
330                while ((line = br.readLine()) != null) {
331                    ei = new ExampleInfo();
332                    ei.setName(line);
333                    ei.setDescription(br.readLine());
334                    ei.setMainClass(Class.forName(br.readLine()));
335                    ei.setSource(FileIO.findFile(br.readLine()));
336                    while(!(line= br.readLine()).equals("<example>"))
337                        ei.addDoc(FileIO.findFile(line));
338                    info.add(ei);
339                }
340                br.close();
341            } catch (Exception e)
342            {
343                org.apache.commons.logging.LogFactory.getLog(this.getClass()).error(e);
344            }
345            return info;
346        }
347    
348        /**
349         * Bean that stores the information in the config file.
350         * @author Juan A. Recio-Garcia
351         * @version 1.0
352         *
353         */
354        class ExampleInfo
355        {
356            String name;
357            String description;
358            Collection<URL> doc;
359            URL source;
360            Class mainClass;
361            
362            public ExampleInfo()
363            {
364                doc = new ArrayList<URL>();
365            }
366            public ExampleInfo(String name, String description, Collection<URL> doc)
367            {
368                super();
369                this.name = name;
370                this.description = description;
371                this.doc = doc;
372            }
373    
374            
375            
376            /**
377             * @return Returns the mainClass.
378             */
379            public Class getMainClass()
380            {
381                return mainClass;
382            }
383            /**
384             * @param mainClass The mainClass to set.
385             */
386            public void setMainClass(Class mainClass)
387            {
388                this.mainClass = mainClass;
389            }
390            /**
391             * @return Returns the source.
392             */
393            public URL getSource()
394            {
395                return source;
396            }
397            /**
398             * @param source The source to set.
399             */
400            public void setSource(URL source)
401            {
402                this.source = source;
403            }
404            /**
405             * @return Returns the description.
406             */
407            public String getDescription()
408            {
409                return description;
410            }
411    
412            /**
413             * @param description The description to set.
414             */
415            public void setDescription(String description)
416            {
417                this.description = description;
418            }
419    
420            /**
421             * @return Returns the doc.
422             */
423            public Collection<URL> getDoc()
424            {
425                return doc;
426            }
427    
428            /**
429             * @param doc The doc to set.
430             */
431            public void setDoc(Collection<URL> doc)
432            {
433                this.doc = doc;
434            }
435            
436            public void addDoc(URL url)
437            {
438                this.doc.add(url);
439            }
440    
441            /**
442             * @return Returns the name.
443             */
444            public String getName()
445            {
446                return name;
447            }
448    
449            /**
450             * @param name The name to set.
451             */
452            public void setName(String name)
453            {
454                this.name = name;
455            }
456            
457            
458        }
459        
460        /**
461         * A HTML browser panel
462         * @author Juan A. Recio-Garcia
463         * @version 1.0
464         *
465         */
466        class HTMLBrowser extends JPanel
467        {
468            private static final long serialVersionUID = 1L;
469    
470            JEditorPane doc;
471            URL originalURL;
472            
473            public HTMLBrowser(URL file)
474            {
475                originalURL = file;
476                JPanel top = new JPanel();
477                top.setLayout(new BoxLayout(top,BoxLayout.X_AXIS));
478                
479                JButton prev = new JButton("Back");
480                prev.addActionListener(new ActionListener(){
481    
482                    public void actionPerformed(ActionEvent e)
483                    {
484                        try
485                        {
486                            doc.setPage(originalURL);
487                        } catch (IOException e1)
488                        {
489                            org.apache.commons.logging.LogFactory.getLog(this.getClass()).error(e1);
490                        }  
491                    }
492                });
493             
494                JLabel urlInfo = new JLabel(file.toString());
495                
496                top.add(prev);
497                top.add(Box.createHorizontalGlue());
498                top.add(urlInfo);
499                
500                doc = new JEditorPane();
501                doc.setContentType("text/html");
502                doc.setEditable(false);
503                doc.addHyperlinkListener(new HyperlinkListener() {
504    
505                    public void hyperlinkUpdate(HyperlinkEvent e)
506                    {
507                        try
508                        {
509                            if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED))
510                                doc.setPage(e.getURL());
511    
512                        } catch (IOException e1)
513                        {
514                            org.apache.commons.logging.LogFactory.getLog(this.getClass()).error(e1);
515                        }
516                    }
517    
518                });
519                try
520                {
521                    doc.setPage(file);
522                } catch (IOException e)
523                {
524                    org.apache.commons.logging.LogFactory.getLog(this.getClass()).error(e);
525                }
526                
527                this.setLayout(new BorderLayout());
528                this.add(top, BorderLayout.NORTH);
529                this.add(new JScrollPane(doc), BorderLayout.CENTER);
530            }
531    
532        }
533    
534        /**
535         * This class redirects System.out to the log text area.
536         * @author Juan A. Recio-Garcia
537         * @version 1.0
538         */
539        class FilteredStream extends FilterOutputStream {
540            public FilteredStream(OutputStream aStream) {
541                super(aStream);
542              }
543    
544            public void write(byte b[]) throws IOException {
545                String aString = new String(b);
546                displayPane.append(aString);
547                displayPane.setCaretPosition( displayPane.getDocument().getLength() );
548            }
549    
550            public void write(byte b[], int off, int len) throws IOException {
551                String aString = new String(b , off , len);
552                displayPane.append(aString);
553                displayPane.setCaretPosition( displayPane.getDocument().getLength() );
554            }
555        }
556        
557        /**
558         * Shows the logo screen
559         * @author Juan A. Recio-Garcia
560         * @version 1.0
561         *
562         */
563        public class LogoFrame extends JWindow implements Runnable {
564            private static final long serialVersionUID = 1L;
565    
566            long time;
567            public LogoFrame(URL image, long time) throws HeadlessException {
568                    try {
569                        
570                            this.time = time;
571                            JLabel jLabel1 = new JLabel();
572                            jLabel1.setIcon(new javax.swing.ImageIcon(image));
573                            jLabel1.setBorder(BorderFactory.createRaisedBevelBorder());
574                            this.getContentPane().add(jLabel1, BorderLayout.CENTER);
575                            this.pack();
576    
577                            java.awt.Dimension screenSize = java.awt.Toolkit
578                                            .getDefaultToolkit().getScreenSize();
579                            setBounds((screenSize.width - this.getWidth()) / 2,
580                                            (screenSize.height - this.getHeight()) / 2, getWidth(),
581                                            getHeight());
582    
583                            this.setVisible(true);
584                            Thread thread = new Thread(this);
585                            thread.start();
586                    } catch (Exception e) {
587                            e.printStackTrace();
588                    }
589            }
590    
591            public void run()
592            {
593                try
594                {
595                    Thread.sleep(2000);
596                } catch (InterruptedException e)
597                {
598                    org.apache.commons.logging.LogFactory.getLog(this.getClass()).error(e);
599                    
600                }
601                this.dispose();
602            }
603        }
604    }