KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > jmeter > gui > GuiPackage


1 // $Header: /home/cvs/jakarta-jmeter/src/core/org/apache/jmeter/gui/GuiPackage.java,v 1.33 2004/02/22 19:30:13 sebb Exp $
2
/*
3  * Copyright 2001,2003-2004 The Apache Software Foundation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * 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 */

18
19 package org.apache.jmeter.gui;
20
21 import java.awt.Component JavaDoc;
22 import java.awt.event.MouseEvent JavaDoc;
23 import java.beans.Introspector JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.Map JavaDoc;
26
27 import javax.swing.JPopupMenu JavaDoc;
28
29 import org.apache.jmeter.engine.util.ValueReplacer;
30 import org.apache.jmeter.exceptions.IllegalUserActionException;
31 import org.apache.jmeter.gui.tree.JMeterTreeListener;
32 import org.apache.jmeter.gui.tree.JMeterTreeModel;
33 import org.apache.jmeter.gui.tree.JMeterTreeNode;
34 import org.apache.jmeter.testbeans.TestBean;
35 import org.apache.jmeter.testbeans.gui.TestBeanGUI;
36 import org.apache.jmeter.testelement.TestElement;
37 import org.apache.jmeter.testelement.TestPlan;
38 import org.apache.jmeter.util.JMeterUtils;
39 import org.apache.jmeter.util.LocaleChangeEvent;
40 import org.apache.jmeter.util.LocaleChangeListener;
41 import org.apache.jmeter.visualizers.gui.AbstractVisualizer;
42 import org.apache.jorphan.collections.HashTree;
43 import org.apache.jorphan.logging.LoggingManager;
44 import org.apache.log.Logger;
45
46 /**
47  * GuiPackage is a static class that provides convenient access to information
48  * about the current state of JMeter's GUI. Any GUI class can grab a handle to
49  * GuiPackage by calling the static method {@link #getInstance()} and then use
50  * it to query the GUI about it's state. When actions, for instance, need to
51  * affect the GUI, they typically use GuiPackage to get access to different
52  * parts of the GUI.
53  *
54  * @author Michael Stover
55  * @author <a HREF="mailto:jsalvata@apache.org">Jordi Salvat i Alabart</a>
56  * @version $Revision: 1.33 $ updated on $Date: 2004/02/22 19:30:13 $
57  */

58 public final class GuiPackage implements LocaleChangeListener
59 {
60     /** Logging. */
61     private static transient Logger log =
62         LoggingManager.getLoggerForClass();
63
64     /** Singleton instance. */
65     private static GuiPackage guiPack;
66     
67     /**
68      * Flag indicating whether or not parts of the tree have changed since
69      * they were last saved.
70      */

71     private boolean dirty = false;
72     
73     /**
74      * Map from TestElement to JMeterGUIComponent, mapping the nodes in the
75      * tree to their corresponding GUI components.
76      */

77     private Map JavaDoc nodesToGui = new HashMap JavaDoc();
78     
79     /**
80      * Map from Class to JMeterGUIComponent, mapping the Class of a GUI
81      * component to an instance of that component.
82      */

83     private Map JavaDoc guis = new HashMap JavaDoc();
84     
85     /**
86      * Map from Class to TestBeanGUI, mapping the Class of a TestBean to an
87      * instance of TestBeanGUI to be used to edit such components.
88      */

89     private Map JavaDoc testBeanGUIs= new HashMap JavaDoc();
90
91     /** The currently selected node in the tree. */
92     private JMeterTreeNode currentNode = null;
93     
94     /** The model for JMeter's test tree. */
95     private JMeterTreeModel treeModel;
96     
97     /** The listener for JMeter's test tree. */
98     private JMeterTreeListener treeListener;
99
100     /** The main JMeter frame. */
101     private MainFrame mainFrame;
102
103     
104     /**
105      * Private constructor to permit instantiation only from within this class.
106      * Use {@link #getInstance()} to retrieve a singleton instance.
107      */

108     private GuiPackage()
109     {
110         JMeterUtils.addLocaleChangeListener(this);
111     }
112     
113     /**
114      * Retrieve the singleton GuiPackage instance.
115      *
116      * @return the GuiPackage instance
117      */

118     public static GuiPackage getInstance()
119     {
120         return guiPack;
121     }
122     
123     /**
124      * When GuiPackage is requested for the first time, it should be given
125      * handles to JMeter's Tree Listener and TreeModel.
126      *
127      * @param listener the TreeListener for JMeter's test tree
128      * @param treeModel the model for JMeter's test tree
129      *
130      * @return GuiPackage
131      */

132     public static GuiPackage getInstance(
133         JMeterTreeListener listener,
134         JMeterTreeModel treeModel)
135     {
136         if (guiPack == null)
137         {
138             guiPack = new GuiPackage();
139             guiPack.setTreeListener(listener);
140             guiPack.setTreeModel(treeModel);
141         }
142         return guiPack;
143     }
144
145     /**
146      * Get a JMeterGUIComponent for the specified test element. If the GUI has
147      * already been created, that instance will be returned. Otherwise, if a
148      * GUI component of the same type has been created, and the component is
149      * not marked as an {@link UnsharedComponent}, that shared component will
150      * be returned. Otherwise, a new instance of the component will be created.
151      * The TestElement's GUI_CLASS property will be used to determine the
152      * appropriate type of GUI component to use.
153      *
154      * @param node the test element which this GUI is being created for
155      *
156      * @return the GUI component corresponding to the specified test
157      * element
158      */

159     public JMeterGUIComponent getGui(TestElement node)
160     {
161         String JavaDoc testClassName= node.getPropertyAsString(TestElement.TEST_CLASS);
162         String JavaDoc guiClassName= node.getPropertyAsString(TestElement.GUI_CLASS);
163         try
164         {
165             Class JavaDoc testClass;
166             if (testClassName.equals(""))
167             {
168                 testClass= node.getClass();
169             }
170             else
171             {
172                 testClass= Class.forName(testClassName);
173             }
174             Class JavaDoc guiClass= null;
175             if (! guiClassName.equals(""))
176             {
177                 guiClass= Class.forName(guiClassName);
178             }
179             return getGui(node, guiClass, testClass);
180         }
181         catch (ClassNotFoundException JavaDoc e)
182         {
183             log.error("Could not get GUI for " + node, e);
184             return null;
185         }
186     }
187
188     /**
189      * Get a JMeterGUIComponent for the specified test element. If the GUI has
190      * already been created, that instance will be returned. Otherwise, if a
191      * GUI component of the same type has been created, and the component is
192      * not marked as an {@link UnsharedComponent}, that shared component will
193      * be returned. Otherwise, a new instance of the component will be created.
194      *
195      * @param node the test element which this GUI is being created for
196      * @param guiClass the fully qualifed class name of the GUI component which
197      * will be created if it doesn't already exist
198      * @param testClass the fully qualifed class name of the test elements which
199      * have to be edited by the returned GUI component
200      *
201      * @return the GUI component corresponding to the specified test
202      * element
203      */

204     public JMeterGUIComponent getGui(
205         TestElement node, Class JavaDoc guiClass, Class JavaDoc testClass)
206     {
207         try
208         {
209             JMeterGUIComponent comp = (JMeterGUIComponent) nodesToGui.get(node);
210             if (comp == null)
211             {
212                 comp = getGuiFromCache(guiClass, testClass);
213                 nodesToGui.put(node, comp);
214             }
215             log.debug("Gui retrieved = " + comp);
216             return comp;
217         }
218         catch (Exception JavaDoc e)
219         {
220             log.error("Problem retrieving gui", e);
221             return null;
222         }
223     }
224
225     /**
226      * Remove a test element from the tree. This removes the reference to any
227      * associated GUI component.
228      *
229      * @param node the test element being removed
230      */

231     public void removeNode(TestElement node)
232     {
233         nodesToGui.remove(node);
234     }
235     
236     /**
237      * Convenience method for grabbing the gui for the current node.
238      *
239      * @return the GUI component associated with the currently selected node
240      */

241     public JMeterGUIComponent getCurrentGui()
242     {
243         try
244         {
245             TestElement currentNode =
246                 treeListener.getCurrentNode().getTestElement();
247             JMeterGUIComponent comp = getGui(currentNode);
248             if(!(comp instanceof AbstractVisualizer)) // TODO: a hack that needs to be fixed for 2.0
249
{
250                 comp.clear();
251             }
252             comp.configure(currentNode);
253             return comp;
254         }
255         catch (Exception JavaDoc e)
256         {
257             log.error("Problem retrieving gui", e);
258             return null;
259         }
260     }
261     
262     /**
263      * Find the JMeterTreeNode for a certain TestElement object.
264      * @param userObject the test element to search for
265      * @return the tree node associated with the test element
266      */

267     public JMeterTreeNode getNodeOf(TestElement userObject)
268     {
269         return treeModel.getNodeOf(userObject);
270     }
271     
272     /**
273      * Create a TestElement corresponding to the specified GUI class.
274      *
275      * @param guiClass the fully qualified class name of the GUI component
276      * or a TestBean class for TestBeanGUIs.
277      * @param testClass the fully qualified class name of the test elements
278      * edited by this GUI component.
279      * @return the test element corresponding to the specified GUI class.
280      */

281     public TestElement createTestElement(Class JavaDoc guiClass, Class JavaDoc testClass)
282     {
283         try
284         {
285             JMeterGUIComponent comp = getGuiFromCache(guiClass, testClass);
286             comp.clear();
287             TestElement node = comp.createTestElement();
288             nodesToGui.put(node, comp);
289             return node;
290         }
291         catch (Exception JavaDoc e)
292         {
293             log.error("Problem retrieving gui", e);
294             return null;
295         }
296     }
297
298     /**
299      * Create a TestElement for a GUI or TestBean class.
300      * <p>
301      * This is a utility method to help actions do with one single String
302      * parameter.
303      *
304      * @param objClass the fully qualified class name of the GUI component or of
305      * the TestBean subclass for which a TestBeanGUI is wanted.
306      * @return the test element corresponding to the specified GUI class.
307      */

308     public TestElement createTestElement(String JavaDoc objClass)
309     {
310         JMeterGUIComponent comp;
311         Class JavaDoc c;
312         try
313         {
314             c= Class.forName(objClass);
315             if (TestBean.class.isAssignableFrom(c))
316             {
317                 comp= getGuiFromCache(TestBeanGUI.class, c);
318             }
319             else
320             {
321                 comp= getGuiFromCache(c, null);
322             }
323             comp.clear();
324             TestElement node = comp.createTestElement();
325             nodesToGui.put(node, comp);
326             return node;
327         }
328         catch (ClassNotFoundException JavaDoc e)
329         {
330             log.error("Problem retrieving gui for "+objClass, e);
331             throw new Error JavaDoc(e.toString()); // Programming error: bail out.
332
} catch (InstantiationException JavaDoc e)
333         {
334             log.error("Problem retrieving gui for "+objClass, e);
335             throw new Error JavaDoc(e.toString()); // Programming error: bail out.
336
} catch (IllegalAccessException JavaDoc e)
337         {
338             log.error("Problem retrieving gui for "+objClass, e);
339             throw new Error JavaDoc(e.toString()); // Programming error: bail out.
340
}
341     }
342     /**
343      * Get an instance of the specified JMeterGUIComponent class. If an
344      * instance of the GUI class has previously been created and it is not
345      * marked as an {@link UnsharedComponent}, that shared instance will be
346      * returned. Otherwise, a new instance of the component will be created,
347      * and shared components will be cached for future retrieval.
348      *
349      * @param guiClass the fully qualified class name of the GUI component.
350      * This class must implement JMeterGUIComponent.
351      * @param testClass the fully qualified class name of the test elements
352      * edited by this GUI component. This class must
353      * implement TestElement.
354      * @return an instance of the specified class
355      *
356      * @throws InstantiationException if an instance of the object cannot be
357      * created
358      * @throws IllegalAccessException if access rights do not allow the default
359      * constructor to be called
360      * @throws ClassNotFoundException if the specified GUI class cannot be
361      * found
362      */

363     private JMeterGUIComponent getGuiFromCache(Class JavaDoc guiClass, Class JavaDoc testClass)
364         throws InstantiationException JavaDoc,
365                IllegalAccessException JavaDoc,
366                ClassNotFoundException JavaDoc
367     {
368         JMeterGUIComponent comp ;
369         if (guiClass == TestBeanGUI.class)
370         {
371             comp= (TestBeanGUI) testBeanGUIs.get(testClass);
372             if (comp == null)
373             {
374                 comp= new TestBeanGUI(testClass);
375                 testBeanGUIs.put(testClass, comp);
376             }
377         }
378         else
379         {
380             comp= (JMeterGUIComponent) guis.get(guiClass);
381             if (comp == null)
382             {
383                 comp = (JMeterGUIComponent) guiClass.newInstance();
384                 if (!(comp instanceof UnsharedComponent))
385                 {
386                     guis.put(guiClass, comp);
387                 }
388             }
389         }
390         return comp;
391     }
392
393     /**
394      * Update the GUI for the currently selected node. The GUI component is
395      * configured to reflect the settings in the current tree node.
396      *
397      */

398     public void updateCurrentGui()
399     {
400         currentNode= treeListener.getCurrentNode();
401         TestElement element = currentNode.getTestElement();
402         JMeterGUIComponent comp = getGui(element);
403         comp.configure(element);
404     }
405
406     /**
407      * This method should be called in order for GuiPackage to change the
408      * current node. This will save any changes made to the earlier node
409      * before choosing the new node.
410      */

411     public void updateCurrentNode()
412     {
413         try
414         {
415             if (currentNode != null)
416             {
417                 log.debug(
418                     "Updating current node " + currentNode.getName());
419                 JMeterGUIComponent comp =
420                     getGui(currentNode.getTestElement());
421                 TestElement el = currentNode.getTestElement();
422                 comp.modifyTestElement(el);
423             }
424             currentNode = treeListener.getCurrentNode();
425         }
426         catch (Exception JavaDoc e)
427         {
428             log.error("Problem retrieving gui", e);
429         }
430     }
431     
432     public JMeterTreeNode getCurrentNode()
433     {
434         return treeListener.getCurrentNode();
435     }
436     
437     public TestElement getCurrentElement()
438     {
439         return getCurrentNode().getTestElement();
440     }
441
442     /**
443      * The dirty property is a flag that indicates whether there are parts of
444      * JMeter's test tree that the user has not saved since last modification.
445      * Various (@link Command actions) set this property when components are
446      * modified/created/saved.
447      *
448      * @param dirty the new value of the dirty flag
449      */

450     public void setDirty(boolean dirty)
451     {
452         this.dirty = dirty;
453     }
454     
455     /**
456      * Retrieves the state of the 'dirty' property, a flag that indicates if
457      * there are test tree components that have been modified since they were
458      * last saved.
459      *
460      * @return true if some tree components have been modified since they were
461      * last saved, false otherwise
462      */

463     public boolean isDirty()
464     {
465         return dirty;
466     }
467     
468     /**
469      * Add a subtree to the currently selected node.
470      *
471      * @param subTree the subtree to add.
472      *
473      * @return the resulting subtree starting with the currently selected node
474      *
475      * @throws IllegalUserActionException if a subtree cannot be added to the
476      * currently selected node
477      */

478     public HashTree addSubTree(HashTree subTree)
479         throws IllegalUserActionException
480     {
481         return treeModel.addSubTree(subTree, treeListener.getCurrentNode());
482     }
483     
484     /**
485      * Get the currently selected subtree.
486      *
487      * @return the subtree of the currently selected node
488      */

489     public HashTree getCurrentSubTree()
490     {
491         return treeModel.getCurrentSubTree(treeListener.getCurrentNode());
492     }
493     
494     /**
495      * Get the model for JMeter's test tree.
496      *
497      * @return the JMeter tree model
498      */

499     public JMeterTreeModel getTreeModel()
500     {
501         return treeModel;
502     }
503
504     /**
505      * Set the model for JMeter's test tree.
506      *
507      * @param newTreeModel the new JMeter tree model
508      */

509     public void setTreeModel(JMeterTreeModel newTreeModel)
510     {
511         treeModel = newTreeModel;
512     }
513     
514     /**
515      * Get a ValueReplacer for the test tree.
516      *
517      * @return a ValueReplacer configured for the test tree
518      */

519     public ValueReplacer getReplacer()
520     {
521         return new ValueReplacer(
522             (TestPlan) ((JMeterTreeNode) getTreeModel()
523                 .getTestPlan()
524                 .getArray()[0])
525                 .getTestElement());
526     }
527
528     /**
529      * Set the main JMeter frame.
530      *
531      * @param newMainFrame the new JMeter main frame
532      */

533     public void setMainFrame(MainFrame newMainFrame)
534     {
535         mainFrame = newMainFrame;
536     }
537     
538     /**
539      * Get the main JMeter frame.
540      *
541      * @return the main JMeter frame
542      */

543     public MainFrame getMainFrame()
544     {
545         return mainFrame;
546     }
547     
548     /**
549      * Set the listener for JMeter's test tree.
550      *
551      * @param newTreeListener the new JMeter test tree listener
552      */

553     public void setTreeListener(JMeterTreeListener newTreeListener)
554     {
555         treeListener = newTreeListener;
556     }
557     
558     /**
559      * Get the listener for JMeter's test tree.
560      *
561      * @return the JMeter test tree listener
562      */

563     public JMeterTreeListener getTreeListener()
564     {
565         return treeListener;
566     }
567     
568     /**
569      * Display the specified popup menu with the source component and location
570      * from the specified mouse event.
571      *
572      * @param e the mouse event causing this popup to be displayed
573      * @param popup the popup menu to display
574      */

575     public void displayPopUp(MouseEvent JavaDoc e, JPopupMenu JavaDoc popup)
576     {
577         displayPopUp((Component JavaDoc) e.getSource(), e, popup);
578     }
579
580     /**
581      * Display the specified popup menu at the location specified by a mouse
582      * event with the specified source component.
583      *
584      * @param invoker the source component
585      * @param e the mouse event causing this popup to be displayed
586      * @param popup the popup menu to display
587      */

588     public void displayPopUp(Component JavaDoc invoker, MouseEvent JavaDoc e, JPopupMenu JavaDoc popup)
589     {
590         if (popup != null)
591         {
592             log.debug(
593                 "Showing pop up for " + invoker
594                 + " at x,y = " + e.getX() + "," + e.getY());
595                 
596             popup.pack();
597             popup.show(invoker, e.getX(), e.getY());
598             popup.setVisible(true);
599             popup.requestFocus();
600         }
601     }
602
603     /* (non-Javadoc)
604      * @see org.apache.jmeter.util.LocaleChangeListener#localeChanged(org.apache.jmeter.util.LocaleChangeEvent)
605      */

606     public void localeChanged(LocaleChangeEvent event)
607     {
608         // FIrst make sure we save the content of the current GUI (since we
609
// will flush it away):
610
updateCurrentNode();
611
612         // Forget about all GUIs we've created so far: we'll need to re-created them all!
613
guis= new HashMap JavaDoc();
614         nodesToGui= new HashMap JavaDoc();
615         testBeanGUIs= new HashMap JavaDoc();
616
617         // BeanInfo objects also contain locale-sensitive data -- flush them away:
618
Introspector.flushCaches();
619
620         // Now put the current GUI in place. [This code was copied from the
621
// EditCommand action -- we can't just trigger the action because that
622
// would populate the current node with the contents of the new GUI --
623
// which is empty.]
624
MainFrame mf = getMainFrame(); // Fetch once
625
if (mf == null) //Probably caused by unit testing on headless system
626
{
627             log.warn("Mainframe is null");
628         }
629         else
630         {
631             mf.setMainPanel((javax.swing.JComponent JavaDoc) getCurrentGui());
632             mf.setEditMenu(getTreeListener().getCurrentNode().createPopupMenu());
633         }
634     }
635 }
Popular Tags