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