KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > sape > carbon > services > devtools > junit > launcher > TestLauncher


1 /*
2  * The contents of this file are subject to the Sapient Public License
3  * Version 1.0 (the "License"); you may not use this file except in compliance
4  * with the License. You may obtain a copy of the License at
5  * http://carbon.sf.net/License.html.
6  *
7  * Software distributed under the License is distributed on an "AS IS" basis,
8  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
9  * the specific language governing rights and limitations under the License.
10  *
11  * The Original Code is The Carbon Component Framework.
12  *
13  * The Initial Developer of the Original Code is Sapient Corporation
14  *
15  * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
16  */

17 package org.sape.carbon.services.devtools.junit.launcher;
18
19 import java.util.ArrayList JavaDoc;
20 import java.util.List JavaDoc;
21 import java.util.HashSet JavaDoc;
22 import java.util.Set JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.Properties JavaDoc;
27 import java.util.Enumeration JavaDoc;
28 import java.util.TreeSet JavaDoc;
29
30 import javax.swing.JFrame JavaDoc;
31 import java.awt.BorderLayout JavaDoc;
32 import java.awt.Container JavaDoc;
33 import javax.swing.JScrollPane JavaDoc;
34 import javax.swing.JPanel JavaDoc;
35 import java.awt.GridBagLayout JavaDoc;
36 import java.awt.GridBagConstraints JavaDoc;
37 import javax.swing.JLabel JavaDoc;
38 import javax.swing.JCheckBox JavaDoc;
39 import java.awt.Insets JavaDoc;
40 import javax.swing.JButton JavaDoc;
41 import java.awt.FlowLayout JavaDoc;
42 import java.awt.event.WindowAdapter JavaDoc;
43 import java.awt.event.WindowEvent JavaDoc;
44 import java.awt.Dimension JavaDoc;
45 import java.awt.Toolkit JavaDoc;
46 import javax.swing.ImageIcon JavaDoc;
47
48 import java.awt.event.ActionListener JavaDoc;
49 import java.awt.event.ActionEvent JavaDoc;
50 import org.sape.carbon.core.util.reflection.ClassFinder;
51 import junit.framework.TestCase;
52 import junit.swingui.TestRunner;
53
54 import java.io.IOException JavaDoc;
55
56 /**
57  * Swing Application that will display all Carbon tests to the user
58  * and allow the user to turn off selected tests or groups of
59  * tests that meet a criteria.
60  * <p>
61  * Test grouping is handled through a properties file located
62  * in the same directory called "launcher.properties".
63  * </p>
64  *
65  * Copyright 2003 Sapient
66  * @since carbon 2.1
67  * @author Jordan Reed, August 2003
68  * @version $Revision: 1.1 $($Author: jdreed $ / $Date: 2003/08/13 02:36:11 $)
69  */

70 public class TestLauncher implements ActionListener JavaDoc, Runnable JavaDoc {
71     /**
72      * Static Set of Strings holding the names of the TestClasses
73      * the user wishes to execute. After the main window is
74      * complete this object can be queried by the jUnit framework
75      * from inside the same JVM.
76      */

77     public static Set JavaDoc selectedClasses = new HashSet JavaDoc();
78
79     /**
80      * Used for simple thread concurrency. The main window
81      * will call notify() on this when the user has finished
82      * processing.
83      */

84     private static final Object JavaDoc WINDOW_NOTIFIER = new Object JavaDoc();
85     
86     /** Cached empty inset to avoid recreation. */
87     private static final Insets JavaDoc emptyInset = new Insets JavaDoc(0, 0, 0, 0);
88     
89     /** Cached inset to avoid recreation. */
90     private static final Insets JavaDoc widthInset = new Insets JavaDoc(0, 5, 0, 5);
91     
92     /** Base location of this package to load the various resources from. */
93     private static final String JavaDoc PACKAGE_LOCATION = "/org/sape/carbon/services/devtools/junit/launcher/";
94     
95     /** Location of the 'launcher.properties' file that holds configuration data. */
96     private static final String JavaDoc PROPERTY_FILE_LOCATION = PACKAGE_LOCATION + "launcher.properties";
97     
98     /** Location of the jUnit logo for the pretty button. */
99     private static final String JavaDoc JUNIT_LOGO_LOCATION = PACKAGE_LOCATION + "junitlogo.gif";
100     
101     /** Location of the remove icon for the pretty button. */
102     private static final String JavaDoc REMOVE_ICON_LOCATION = PACKAGE_LOCATION + "remove.gif";
103     
104     
105     /** Location of the Carbon logo for the frame icon. */
106     private static final String JavaDoc CARBON_LOGO_LOCATION = PACKAGE_LOCATION + "carbonlogo.gif";
107     
108     /** Prefix for excluded tests in the properties file. */
109     private static final String JavaDoc EXCLUDE_PREFIX = "EXCLUDE.";
110     
111     /** Prefix for depend strings in the properties file. */
112     private static final String JavaDoc DEPEND_PREFIX = "DEPEND.";
113
114     /** Action command when the user is finished selecting tests. */
115     private static final String JavaDoc ACTION_DONE = "ACTION_DONE";
116     
117     /** Action command indicating the user wishes to check all tests. */
118     private static final String JavaDoc ACTION_CHECK_ALL = "ACTION_CHECK_ALL";
119     
120     /**
121      * Action command indicating the user has select to remove one
122      * of the dependencies.
123      */

124     private static final String JavaDoc ACTION_REMOVE_DEPEND = "ACTION_REMOVE_DEPEND";
125
126     /** Holds the awt toolkit for the system. */
127     protected Toolkit JavaDoc toolkit = Toolkit.getDefaultToolkit();
128     
129     /** The main frame shown to the user. */
130     protected JFrame JavaDoc applicationFrame;
131     
132     /** The selectAllCheckbox. This is stored so it can be constantly kept checked. */
133     protected JCheckBox JavaDoc selectAllCheckbox;
134     
135     /**
136      * Map of JCheckBox objects to the String of the Test Class Name they
137      * represent.
138      */

139     protected Map JavaDoc checkBoxToClassNameMap;
140     
141     /**
142      * Map of Test Class Names to JCheckBoxs that represent them. */

143     protected Map JavaDoc classNameToCheckBoxMap;
144     
145     /** Set of all test classes found in the system. */
146     protected Set JavaDoc inputClassNames;
147     
148     /** Set of prefixes for classes that should be excluded from testing. */
149     protected Set JavaDoc excludedClassNames;
150     
151     /**
152      * Map of Strings containing the name of dependencies to a
153      * List of Strings containing the name of the class prefixes
154      * that have that dependency.
155      */

156     protected Map JavaDoc dependMap;
157     
158     /**
159      * Map of JButtons to the String name of dependencies.
160      * This is used to determine which dependcy button the
161      * user has clicked on.
162      */

163     protected Map JavaDoc dependButtonMap;
164     
165     /**
166      * Executes the main program.
167      *
168      * @param args ignored
169      */

170     public static void main(String JavaDoc args[]) {
171         TestLauncher testSelector = new TestLauncher();
172         testSelector.runAsThread();
173         
174         // Null out to let the gc get the swing components
175
testSelector = null;
176         
177         if(!selectedClasses.isEmpty()) {
178             TestRunner.main(new String JavaDoc[] {"-noloading", LauncherSelectedTest.class.getName()});
179         }
180     }
181
182     /**
183      * Default constructor initializes all the internal structures.
184      */

185     public TestLauncher() {
186         checkBoxToClassNameMap = new HashMap JavaDoc();
187         classNameToCheckBoxMap = new HashMap JavaDoc();
188         dependButtonMap = new HashMap JavaDoc();
189         excludedClassNames = new HashSet JavaDoc();
190         dependMap = new HashMap JavaDoc();
191         loadPropertiesFile();
192         addAllTests();
193     }
194     
195     /**
196      * Loads and parses the properties file from the classpath.
197      * <p>
198      * After execution the excludedClassNames and dependMap
199      * objects will be initialzed.
200      * </p>
201      */

202     protected void loadPropertiesFile() {
203         Properties JavaDoc properties = new Properties JavaDoc();
204
205         try {
206             properties.load(
207                 getClass().getResourceAsStream(PROPERTY_FILE_LOCATION));
208         } catch (IOException JavaDoc e) {}
209
210         Enumeration JavaDoc propertyNames = properties.propertyNames();
211         while(propertyNames.hasMoreElements()) {
212             String JavaDoc propertyName = (String JavaDoc) propertyNames.nextElement();
213             String JavaDoc propertyValue = properties.getProperty(propertyName);
214             
215             if(propertyName.startsWith(EXCLUDE_PREFIX)) {
216                 addExcludedClass(propertyValue);
217             }
218             else if(propertyName.startsWith(DEPEND_PREFIX)) {
219                 String JavaDoc className = propertyName.substring(DEPEND_PREFIX.length());
220                 addDepend(propertyValue, className);
221             }
222         }
223     }
224     
225     /**
226      * Adds a single class name to the list of classes to
227      * exclude from showing the user.
228      *
229      * @param excludedClassName class name to exclude
230      */

231     protected void addExcludedClass(String JavaDoc excludedClassName) {
232         excludedClassNames.add(excludedClassName);
233     }
234     
235     /**
236      * Adds a class name to the list of classes that match
237      * a dependency.
238      *
239      * @param dependName the name of the dependency to add the class to
240      * @param className the name of the class to add
241      */

242     protected void addDepend(String JavaDoc dependName, String JavaDoc className) {
243         if(!dependMap.containsKey(dependName)) {
244             dependMap.put(dependName, new ArrayList JavaDoc());
245         }
246         
247         ((List JavaDoc)dependMap.get(dependName)).add(className);
248     }
249     
250     /**
251      * Adds all the tests under the "org.sape.carbon" package into
252      * the list of tests and then removes the performance classes
253      * and excluded classes.
254      */

255     protected void addAllTests() {
256         ClassFinder classFinder = new ClassFinder(TestCase.class, "org.sape.carbon");
257         Set JavaDoc testClasses = classFinder.getClasses();
258
259         ClassFinder perfClassFinder = new ClassFinder(TestCase.class,"PerformanceTest");
260         Set JavaDoc performanceClasses = perfClassFinder.getClasses();
261         testClasses.removeAll(performanceClasses);
262         testClasses.removeAll(excludedClassNames);
263
264         setInputClassNames(testClasses);
265     }
266     
267     /**
268      * Sets the name of the classes to display to the user.
269      * This makes a defensive copy of the Set passed in.
270      *
271      * @param inputClassNames A set of Strings representing the
272      * classes to show to the user
273      */

274     public void setInputClassNames(Set JavaDoc inputClassNames) {
275         // Make a copy and sort it for prettiness
276
this.inputClassNames = new TreeSet JavaDoc(inputClassNames);
277     }
278
279     /**
280      * Allows this class to be run as a thread.
281      */

282     public void run() {
283         getUserInput();
284     }
285
286     /**
287      * Runs the input in it's own thread and will return
288      * once the user has finished selecting and closed
289      * the window.
290      */

291     public void runAsThread() {
292         Thread JavaDoc testSelectorThread = new Thread JavaDoc(this);
293         testSelectorThread.start();
294         synchronized(WINDOW_NOTIFIER) {
295             try {
296                 WINDOW_NOTIFIER.wait();
297             }
298             catch (InterruptedException JavaDoc e) {}
299         }
300     }
301
302     /**
303      * This is the main method to build the frame and show it
304      * to the user. The method will exit the moment the
305      * frame is up and displayed. If you wish to have your
306      * thread pause until the user selects input call
307      * the runAsThread method instead.
308      */

309     public void getUserInput() {
310         // Build the application frame
311
applicationFrame = new JFrame JavaDoc("Carbon Test Launcher");
312         applicationFrame.setIconImage(
313             toolkit.getImage(getClass().getResource(CARBON_LOGO_LOCATION)));
314                 
315         applicationFrame.addWindowListener(new WindowCloser());
316         Container JavaDoc contentPane = applicationFrame.getContentPane();
317         contentPane.setLayout(new BorderLayout JavaDoc());
318         JScrollPane JavaDoc scrollPane = new JScrollPane JavaDoc(createTestHarnessPanel());
319
320         contentPane.add(scrollPane);
321         contentPane.add(createButtonPanel(), BorderLayout.NORTH);
322
323         // Give the frame a reasonable size
324
adjustFrameSize();
325         
326         applicationFrame.setVisible(true);
327     }
328
329     /**
330      * If there are too many test classes the Frame will
331      * run off the bottom of the screen. This will
332      * adjust the window size to be more reasonable
333      * if needed.
334      */

335     protected void adjustFrameSize() {
336         applicationFrame.pack();
337         Dimension JavaDoc screenSize = toolkit.getScreenSize();
338         Dimension JavaDoc frameSize = applicationFrame.getSize();
339         double newHeight = frameSize.getHeight();
340         double newWidth = frameSize.getWidth();
341         
342         if(newHeight > screenSize.getHeight() * 0.8) {
343             newHeight = screenSize.getHeight() * 0.8;
344             // Make it a little wider for the vertical scroll bar
345
newWidth = newWidth + 20;
346         }
347         if(newWidth > screenSize.getWidth() * 0.8) {
348             newWidth = screenSize.getWidth() * 0.8;
349         }
350         frameSize.setSize(newWidth, newHeight);
351         applicationFrame.setSize(frameSize);
352     }
353
354     /**
355      * Creates the panel of buttons across the top of
356      * the display that the user can use to execute jUnit
357      * or turn-off dependency groups.
358      *
359      * @return the button panel
360      */

361     protected JPanel JavaDoc createButtonPanel() {
362         JPanel JavaDoc buttonPanel = new JPanel JavaDoc();
363         buttonPanel.setLayout(new FlowLayout JavaDoc(FlowLayout.LEFT));
364         
365         JButton JavaDoc doneButton =
366             new JButton JavaDoc("Run jUnit!", new ImageIcon JavaDoc(getClass().getResource(JUNIT_LOGO_LOCATION)));
367         doneButton.setActionCommand(ACTION_DONE);
368         doneButton.addActionListener(this);
369         buttonPanel.add(doneButton);
370
371         Iterator JavaDoc dependIterator = dependMap.keySet().iterator();
372         while(dependIterator.hasNext()) {
373             String JavaDoc dependName = (String JavaDoc) dependIterator.next();
374             JButton JavaDoc dependButton =
375                 new JButton JavaDoc(dependName, new ImageIcon JavaDoc(getClass().getResource(REMOVE_ICON_LOCATION)));
376                 
377             dependButton.setActionCommand(ACTION_REMOVE_DEPEND);
378             dependButton.addActionListener(this);
379             dependButtonMap.put(dependButton, dependName);
380             buttonPanel.add(dependButton);
381         }
382
383         return buttonPanel;
384     }
385
386     /**
387      * Creates the panel listing all of the located tests
388      * with checkboxes next to each to turn it on or off.
389      *
390      * @return the test harness panel
391      */

392     protected JPanel JavaDoc createTestHarnessPanel() {
393         JPanel JavaDoc testHarnessPanel = new JPanel JavaDoc();
394         GridBagLayout JavaDoc gridBagLayout = new GridBagLayout JavaDoc();
395         testHarnessPanel.setLayout(gridBagLayout);
396
397         // Add any header rows before the real list
398
addHeaderRows(testHarnessPanel, gridBagLayout);
399         
400         // Add all of the input class names
401
Iterator JavaDoc inputClassNamesIterator = inputClassNames.iterator();
402         while(inputClassNamesIterator.hasNext()) {
403             String JavaDoc className = (String JavaDoc) inputClassNamesIterator.next();
404             addRow(testHarnessPanel, gridBagLayout, className);
405         }
406
407         return testHarnessPanel;
408     }
409     
410     /**
411      * Add header rows at the top of the testHarnessPanel.
412      * <p>
413      * The only header row is a checkbox that will activate all
414      * other checkboxes in the panel.
415      * </p>
416      *
417      * @param testHarnessPanel the panel to add the row to
418      * @param gridBagLayout the layout manager
419      */

420     protected void addHeaderRows(JPanel JavaDoc testHarnessPanel, GridBagLayout JavaDoc gridBagLayout) {
421         GridBagConstraints JavaDoc gridBagConstraints = new GridBagConstraints JavaDoc();
422
423         selectAllCheckbox = new JCheckBox JavaDoc();
424         selectAllCheckbox.setSelected(true);
425         selectAllCheckbox.setActionCommand(ACTION_CHECK_ALL);
426         selectAllCheckbox.addActionListener(this);
427         gridBagConstraints.anchor = GridBagConstraints.WEST;
428         gridBagConstraints.gridwidth = GridBagConstraints.RELATIVE;
429         gridBagConstraints.insets = widthInset;
430         gridBagLayout.setConstraints(selectAllCheckbox, gridBagConstraints);
431         testHarnessPanel.add(selectAllCheckbox);
432         gridBagConstraints.anchor = GridBagConstraints.CENTER;
433         gridBagConstraints.gridwidth = 1;
434         gridBagConstraints.insets = emptyInset;
435
436         JLabel JavaDoc selectAllLabel = new JLabel JavaDoc("Activate All Tests");
437         gridBagConstraints.anchor = GridBagConstraints.WEST;
438         gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
439         gridBagConstraints.insets = widthInset;
440         gridBagLayout.setConstraints(selectAllLabel, gridBagConstraints);
441         testHarnessPanel.add(selectAllLabel);
442         gridBagConstraints.anchor = GridBagConstraints.CENTER;
443         gridBagConstraints.gridwidth = 1;
444         gridBagConstraints.insets = emptyInset;
445     }
446
447     /**
448      * Add checkbox rows to testHarnessPanel.
449      *
450      * @param testHarnessPanel the panel to add the row to
451      * @param gridBagLayout the layout manager
452      * @param className the name of the class to add a checkbox for
453      */

454     protected void addRow(JPanel JavaDoc testHarnessPanel, GridBagLayout JavaDoc gridBagLayout, String JavaDoc className) {
455         GridBagConstraints JavaDoc gridBagConstraints = new GridBagConstraints JavaDoc();
456
457         JCheckBox JavaDoc selectedCheckbox = new JCheckBox JavaDoc();
458         selectedCheckbox.setSelected(true);
459         gridBagConstraints.anchor = GridBagConstraints.WEST;
460         gridBagConstraints.gridwidth = GridBagConstraints.RELATIVE;
461         gridBagConstraints.insets = widthInset;
462         gridBagLayout.setConstraints(selectedCheckbox, gridBagConstraints);
463         testHarnessPanel.add(selectedCheckbox);
464         gridBagConstraints.anchor = GridBagConstraints.CENTER;
465         gridBagConstraints.gridwidth = 1;
466         gridBagConstraints.insets = emptyInset;
467
468
469         JLabel JavaDoc classNameLabel = new JLabel JavaDoc(className);
470             
471         gridBagConstraints.anchor = GridBagConstraints.WEST;
472         gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
473         gridBagConstraints.insets = widthInset;
474         gridBagLayout.setConstraints(classNameLabel, gridBagConstraints);
475         testHarnessPanel.add(classNameLabel);
476         gridBagConstraints.anchor = GridBagConstraints.CENTER;
477         gridBagConstraints.gridwidth = 1;
478         gridBagConstraints.insets = emptyInset;
479
480         checkBoxToClassNameMap.put(selectedCheckbox, className);
481         classNameToCheckBoxMap.put(className, selectedCheckbox);
482     }
483     
484     /**
485      * Cycles through all the checkboxes and sets the
486      * state.
487      *
488      * @param checkboxState the state to set all checkboxes to
489      */

490     protected void setAllCheckboxes(boolean checkboxState) {
491         Set JavaDoc keySet = checkBoxToClassNameMap.keySet();
492         Iterator JavaDoc keySetIterator = keySet.iterator();
493         while(keySetIterator.hasNext()) {
494             JCheckBox JavaDoc selectedCheckBox = (JCheckBox JavaDoc) keySetIterator.next();
495             selectedCheckBox.setSelected(checkboxState);
496         }
497     }
498     
499     /**
500      * Sets all the checkboxes under a given depends key.
501      *
502      * @param dependName the name of the depend checkboxes to set.
503      * @param checkboxState the state of the checkboxes to set
504      */

505     protected void setDependsCheckboxes(String JavaDoc dependName, boolean checkboxState) {
506         List JavaDoc dependClassesList = (List JavaDoc) dependMap.get(dependName);
507         if(dependClassesList != null) {
508             Iterator JavaDoc dependClassesIterator = dependClassesList.iterator();
509             while(dependClassesIterator.hasNext()) {
510                 String JavaDoc dependClassName = (String JavaDoc) dependClassesIterator.next();
511                 
512                 Iterator JavaDoc classNameIterator = classNameToCheckBoxMap.keySet().iterator();
513                 while(classNameIterator.hasNext()) {
514                     String JavaDoc className = (String JavaDoc) classNameIterator.next();
515                     if(className.startsWith(dependClassName)) {
516                         JCheckBox JavaDoc classCheckBox = (JCheckBox JavaDoc) classNameToCheckBoxMap.get(className);
517                         classCheckBox.setSelected(checkboxState);
518                     }
519                 }
520             }
521         }
522     }
523
524     /**
525      * Populates the selectedClasses field based on the checkboxes,
526      * closes the frame, and calls notifyAll on the WINDOW_NOTIFIER.
527      */

528     protected void closeAndReturn() {
529         Set JavaDoc entrySet = checkBoxToClassNameMap.entrySet();
530         Iterator JavaDoc entrySetIterator = entrySet.iterator();
531         while(entrySetIterator.hasNext()) {
532             Map.Entry JavaDoc mapEntry = (Map.Entry JavaDoc) entrySetIterator.next();
533             JCheckBox JavaDoc selectedCheckBox = (JCheckBox JavaDoc) mapEntry.getKey();
534             String JavaDoc className = (String JavaDoc) mapEntry.getValue();
535
536             if(selectedCheckBox.isSelected()) {
537                 selectedClasses.add(className);
538             }
539         }
540
541         applicationFrame.dispose();
542
543         synchronized(WINDOW_NOTIFIER) {
544             WINDOW_NOTIFIER.notifyAll();
545         }
546     }
547
548     /**
549      * Listens for actions events on the various buttons.
550      *
551      * @param evt the event being performed.
552      */

553     public void actionPerformed(ActionEvent JavaDoc evt) {
554         if(ACTION_DONE.equals(evt.getActionCommand())) {
555             closeAndReturn();
556         }
557         else if(ACTION_CHECK_ALL.equals(evt.getActionCommand())) {
558             selectAllCheckbox.setSelected(true);
559             setAllCheckboxes(true);
560         }
561         else if(ACTION_REMOVE_DEPEND.equals(evt.getActionCommand())) {
562             String JavaDoc dependName = (String JavaDoc) dependButtonMap.get(evt.getSource());
563             setDependsCheckboxes(dependName, false);
564         }
565     }
566
567     /**
568      * Closes the window.
569      */

570     protected class WindowCloser extends WindowAdapter JavaDoc {
571         /**
572          * Listens for a window close, and then closes the window.
573          *
574          * @param evt ignored
575          */

576         public void windowClosing(WindowEvent JavaDoc evt) {
577             setAllCheckboxes(false);
578             closeAndReturn();
579         }
580     }
581 }
582
Popular Tags