Home » jakarta-jmeter-2.3.4_src » org.apache.jmeter.gui » [javadoc | source]

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  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;
   22   import java.awt.event.MouseEvent;
   23   import java.beans.Introspector;
   24   import java.io.IOException;
   25   import java.util.HashMap;
   26   import java.util.Map;
   27   
   28   import javax.swing.JPopupMenu;
   29   
   30   import org.apache.jmeter.exceptions.IllegalUserActionException;
   31   import org.apache.jmeter.report.engine.ValueReplacer;
   32   import org.apache.jmeter.report.gui.tree.ReportTreeListener;
   33   import org.apache.jmeter.report.gui.tree.ReportTreeModel;
   34   import org.apache.jmeter.report.gui.tree.ReportTreeNode;
   35   import org.apache.jmeter.services.FileServer;
   36   import org.apache.jmeter.testbeans.TestBean;
   37   import org.apache.jmeter.testbeans.gui.TestBeanGUI;
   38   import org.apache.jmeter.testelement.ReportPlan;
   39   import org.apache.jmeter.testelement.TestElement;
   40   import org.apache.jmeter.util.JMeterUtils;
   41   import org.apache.jmeter.util.LocaleChangeEvent;
   42   import org.apache.jmeter.util.LocaleChangeListener;
   43   import org.apache.jorphan.collections.HashTree;
   44   import org.apache.jorphan.logging.LoggingManager;
   45   import org.apache.log.Logger;
   46   
   47   /**
   48    * ReportGuiPackage is based on GuiPackage, but with changes for
   49    * the reporting tool. Because of how the gui components work, it
   50    * was safer to just make a new class, rather than braking existing
   51    * JMeter gui code.
   52    *
   53    */
   54   public final class ReportGuiPackage implements LocaleChangeListener {
   55       /** Logging. */
   56       private static final Logger log = LoggingManager.getLoggerForClass();
   57   
   58       /** Singleton instance. */
   59       private static ReportGuiPackage guiPack;
   60   
   61       /**
   62        * Flag indicating whether or not parts of the tree have changed since they
   63        * were last saved.
   64        */
   65       private boolean dirty = false;
   66   
   67       /**
   68        * Map from TestElement to JMeterGUIComponent, mapping the nodes in the tree
   69        * to their corresponding GUI components.
   70        */
   71       private Map nodesToGui = new HashMap();
   72   
   73       /**
   74        * Map from Class to JMeterGUIComponent, mapping the Class of a GUI
   75        * component to an instance of that component.
   76        */
   77       private Map guis = new HashMap();
   78   
   79       /**
   80        * Map from Class to TestBeanGUI, mapping the Class of a TestBean to an
   81        * instance of TestBeanGUI to be used to edit such components.
   82        */
   83       private Map testBeanGUIs = new HashMap();
   84   
   85       /** The currently selected node in the tree. */
   86       private ReportTreeNode currentNode = null;
   87   
   88       private boolean currentNodeUpdated = false;
   89   
   90       /** The model for JMeter's test tree. */
   91       private ReportTreeModel treeModel;
   92   
   93       /** The listener for JMeter's test tree. */
   94       private ReportTreeListener treeListener;
   95   
   96       /** The main JMeter frame. */
   97       private ReportMainFrame mainFrame;
   98   
   99       /**
  100        * Private constructor to permit instantiation only from within this class.
  101        * Use {@link #getInstance()} to retrieve a singleton instance.
  102        */
  103       private ReportGuiPackage() {
  104           JMeterUtils.addLocaleChangeListener(this);
  105       }
  106   
  107       /**
  108        * Retrieve the singleton GuiPackage instance.
  109        *
  110        * @return the GuiPackage instance
  111        */
  112       public static ReportGuiPackage getInstance() {
  113           if (guiPack == null){
  114               log.error("ReportGuiPackage is null");
  115           }
  116           return guiPack;
  117       }
  118   
  119       /**
  120        * When GuiPackage is requested for the first time, it should be given
  121        * handles to JMeter's Tree Listener and TreeModel.
  122        *
  123        * @param listener
  124        *            the TreeListener for JMeter's test tree
  125        * @param treeModel
  126        *            the model for JMeter's test tree
  127        *
  128        * @return GuiPackage
  129        */
  130       public static ReportGuiPackage getInstance(ReportTreeListener listener, ReportTreeModel treeModel) {
  131           if (guiPack == null) {
  132               guiPack = new ReportGuiPackage();
  133               guiPack.setTreeListener(listener);
  134               guiPack.setTreeModel(treeModel);
  135           }
  136           return guiPack;
  137       }
  138   
  139       /**
  140        * Get a JMeterGUIComponent for the specified test element. If the GUI has
  141        * already been created, that instance will be returned. Otherwise, if a GUI
  142        * component of the same type has been created, and the component is not
  143        * marked as an {@link UnsharedComponent}, that shared component will be
  144        * returned. Otherwise, a new instance of the component will be created. The
  145        * TestElement's GUI_CLASS property will be used to determine the
  146        * appropriate type of GUI component to use.
  147        *
  148        * @param node
  149        *            the test element which this GUI is being created for
  150        *
  151        * @return the GUI component corresponding to the specified test element
  152        */
  153       public JMeterGUIComponent getGui(TestElement node) {
  154           String testClassName = node.getPropertyAsString(TestElement.TEST_CLASS);
  155           String guiClassName = node.getPropertyAsString(TestElement.GUI_CLASS);
  156           try {
  157               Class testClass;
  158               if (testClassName.equals("")) {
  159                   testClass = node.getClass();
  160               } else {
  161                   testClass = Class.forName(testClassName);
  162               }
  163               Class guiClass = null;
  164               if (!guiClassName.equals("")) {
  165                   guiClass = Class.forName(guiClassName);
  166               }
  167               return getGui(node, guiClass, testClass);
  168           } catch (ClassNotFoundException e) {
  169               log.error("Could not get GUI for " + node, e);
  170               return null;
  171           }
  172       }
  173   
  174       /**
  175        * Get a JMeterGUIComponent for the specified test element. If the GUI has
  176        * already been created, that instance will be returned. Otherwise, if a GUI
  177        * component of the same type has been created, and the component is not
  178        * marked as an {@link UnsharedComponent}, that shared component will be
  179        * returned. Otherwise, a new instance of the component will be created.
  180        *
  181        * @param node
  182        *            the test element which this GUI is being created for
  183        * @param guiClass
  184        *            the fully qualifed class name of the GUI component which will
  185        *            be created if it doesn't already exist
  186        * @param testClass
  187        *            the fully qualifed class name of the test elements which have
  188        *            to be edited by the returned GUI component
  189        *
  190        * @return the GUI component corresponding to the specified test element
  191        */
  192       public JMeterGUIComponent getGui(TestElement node, Class guiClass, Class testClass) {
  193           try {
  194               JMeterGUIComponent comp = (JMeterGUIComponent) nodesToGui.get(node);
  195               if (comp == null) {
  196                   comp = getGuiFromCache(guiClass, testClass);
  197                   nodesToGui.put(node, comp);
  198               }
  199               log.debug("Gui retrieved = " + comp);
  200               return comp;
  201           } catch (Exception e) {
  202               log.error("Problem retrieving gui", e);
  203               return null;
  204           }
  205       }
  206   
  207       /**
  208        * Remove a test element from the tree. This removes the reference to any
  209        * associated GUI component.
  210        *
  211        * @param node
  212        *            the test element being removed
  213        */
  214       public void removeNode(TestElement node) {
  215           nodesToGui.remove(node);
  216       }
  217   
  218       /**
  219        * Convenience method for grabbing the gui for the current node.
  220        *
  221        * @return the GUI component associated with the currently selected node
  222        */
  223       public JMeterGUIComponent getCurrentGui() {
  224           try {
  225               updateCurrentNode();
  226               TestElement curNode = treeListener.getCurrentNode().getTestElement();
  227               JMeterGUIComponent comp = getGui(curNode);
  228               comp.clearGui();
  229               log.debug("Updating gui to new node");
  230               comp.configure(curNode);
  231               currentNodeUpdated = false;
  232               return comp;
  233           } catch (Exception e) {
  234               log.error("Problem retrieving gui", e);
  235               return null;
  236           }
  237       }
  238   
  239       /**
  240        * Find the JMeterTreeNode for a certain TestElement object.
  241        *
  242        * @param userObject
  243        *            the test element to search for
  244        * @return the tree node associated with the test element
  245        */
  246       public ReportTreeNode getNodeOf(TestElement userObject) {
  247           return treeModel.getNodeOf(userObject);
  248       }
  249   
  250       /**
  251        * Create a TestElement corresponding to the specified GUI class.
  252        *
  253        * @param guiClass
  254        *            the fully qualified class name of the GUI component or a
  255        *            TestBean class for TestBeanGUIs.
  256        * @param testClass
  257        *            the fully qualified class name of the test elements edited by
  258        *            this GUI component.
  259        * @return the test element corresponding to the specified GUI class.
  260        */
  261       public TestElement createTestElement(Class guiClass, Class testClass) {
  262           try {
  263               JMeterGUIComponent comp = getGuiFromCache(guiClass, testClass);
  264               comp.clearGui();
  265               TestElement node = comp.createTestElement();
  266               nodesToGui.put(node, comp);
  267               return node;
  268           } catch (Exception e) {
  269               log.error("Problem retrieving gui", e);
  270               return null;
  271           }
  272       }
  273   
  274       /**
  275        * Create a TestElement for a GUI or TestBean class.
  276        * <p>
  277        * This is a utility method to help actions do with one single String
  278        * parameter.
  279        *
  280        * @param objClass
  281        *            the fully qualified class name of the GUI component or of the
  282        *            TestBean subclass for which a TestBeanGUI is wanted.
  283        * @return the test element corresponding to the specified GUI class.
  284        */
  285       public TestElement createTestElement(String objClass) {
  286           JMeterGUIComponent comp;
  287           Class c;
  288           try {
  289               c = Class.forName(objClass);
  290               if (TestBean.class.isAssignableFrom(c)) {
  291                   comp = getGuiFromCache(TestBeanGUI.class, c);
  292               } else {
  293                   comp = getGuiFromCache(c, null);
  294               }
  295               comp.clearGui();
  296               TestElement node = comp.createTestElement();
  297               nodesToGui.put(node, comp);
  298               return node;
  299           } catch (NoClassDefFoundError e) {
  300               log.error("Problem retrieving gui for " + objClass, e);
  301               throw new RuntimeException(e.toString()); // Probably a missing
  302                                                           // jar
  303           } catch (ClassNotFoundException e) {
  304               log.error("Problem retrieving gui for " + objClass, e);
  305               throw new RuntimeException(e.toString()); // Programming error:
  306                                                           // bail out.
  307           } catch (InstantiationException e) {
  308               log.error("Problem retrieving gui for " + objClass, e);
  309               throw new RuntimeException(e.toString()); // Programming error:
  310                                                           // bail out.
  311           } catch (IllegalAccessException e) {
  312               log.error("Problem retrieving gui for " + objClass, e);
  313               throw new RuntimeException(e.toString()); // Programming error:
  314                                                           // bail out.
  315           }
  316       }
  317   
  318       /**
  319        * Get an instance of the specified JMeterGUIComponent class. If an instance
  320        * of the GUI class has previously been created and it is not marked as an
  321        * {@link UnsharedComponent}, that shared instance will be returned.
  322        * Otherwise, a new instance of the component will be created, and shared
  323        * components will be cached for future retrieval.
  324        *
  325        * @param guiClass
  326        *            the fully qualified class name of the GUI component. This
  327        *            class must implement JMeterGUIComponent.
  328        * @param testClass
  329        *            the fully qualified class name of the test elements edited by
  330        *            this GUI component. This class must implement TestElement.
  331        * @return an instance of the specified class
  332        *
  333        * @throws InstantiationException
  334        *             if an instance of the object cannot be created
  335        * @throws IllegalAccessException
  336        *             if access rights do not allow the default constructor to be
  337        *             called
  338        * @throws ClassNotFoundException
  339        *             if the specified GUI class cannot be found
  340        */
  341       private JMeterGUIComponent getGuiFromCache(Class guiClass, Class testClass) throws InstantiationException,
  342               IllegalAccessException {
  343           JMeterGUIComponent comp;
  344           if (guiClass == TestBeanGUI.class) {
  345               comp = (TestBeanGUI) testBeanGUIs.get(testClass);
  346               if (comp == null) {
  347                   comp = new TestBeanGUI(testClass);
  348                   testBeanGUIs.put(testClass, comp);
  349               }
  350           } else {
  351               comp = (JMeterGUIComponent) guis.get(guiClass);
  352               if (comp == null) {
  353                   comp = (JMeterGUIComponent) guiClass.newInstance();
  354                   if (!(comp instanceof UnsharedComponent)) {
  355                       guis.put(guiClass, comp);
  356                   }
  357               }
  358           }
  359           return comp;
  360       }
  361   
  362       /**
  363        * Update the GUI for the currently selected node. The GUI component is
  364        * configured to reflect the settings in the current tree node.
  365        *
  366        */
  367       public void updateCurrentGui() {
  368           updateCurrentNode();
  369           currentNode = treeListener.getCurrentNode();
  370           TestElement element = currentNode.getTestElement();
  371           JMeterGUIComponent comp = getGui(element);
  372           comp.configure(element);
  373           currentNodeUpdated = false;
  374       }
  375   
  376       /**
  377        * This method should be called in order for GuiPackage to change the
  378        * current node. This will save any changes made to the earlier node before
  379        * choosing the new node.
  380        */
  381       public void updateCurrentNode() {
  382           try {
  383               if (currentNode != null && !currentNodeUpdated) {
  384                   log.debug("Updating current node " + currentNode.getName());
  385                   JMeterGUIComponent comp = getGui(currentNode.getTestElement());
  386                   TestElement el = currentNode.getTestElement();
  387                   comp.modifyTestElement(el);
  388               }
  389               if (currentNode != treeListener.getCurrentNode()) {
  390                   currentNodeUpdated = true;
  391               }
  392               currentNode = treeListener.getCurrentNode();
  393           } catch (Exception e) {
  394               log.error("Problem retrieving gui", e);
  395           }
  396       }
  397   
  398       public ReportTreeNode getCurrentNode() {
  399           return treeListener.getCurrentNode();
  400       }
  401   
  402       public TestElement getCurrentElement() {
  403           return getCurrentNode().getTestElement();
  404       }
  405   
  406       /**
  407        * The dirty property is a flag that indicates whether there are parts of
  408        * JMeter's test tree that the user has not saved since last modification.
  409        * Various (@link Command actions) set this property when components are
  410        * modified/created/saved.
  411        *
  412        * @param dirty
  413        *            the new value of the dirty flag
  414        */
  415       public void setDirty(boolean dirty) {
  416           this.dirty = dirty;
  417       }
  418   
  419       /**
  420        * Retrieves the state of the 'dirty' property, a flag that indicates if
  421        * there are test tree components that have been modified since they were
  422        * last saved.
  423        *
  424        * @return true if some tree components have been modified since they were
  425        *         last saved, false otherwise
  426        */
  427       public boolean isDirty() {
  428           return dirty;
  429       }
  430   
  431       /**
  432        * Add a subtree to the currently selected node.
  433        *
  434        * @param subTree
  435        *            the subtree to add.
  436        *
  437        * @return the resulting subtree starting with the currently selected node
  438        *
  439        * @throws IllegalUserActionException
  440        *             if a subtree cannot be added to the currently selected node
  441        */
  442       public HashTree addSubTree(HashTree subTree) throws IllegalUserActionException {
  443           return treeModel.addSubTree(subTree, treeListener.getCurrentNode());
  444       }
  445   
  446       /**
  447        * Get the currently selected subtree.
  448        *
  449        * @return the subtree of the currently selected node
  450        */
  451       public HashTree getCurrentSubTree() {
  452           return treeModel.getCurrentSubTree(treeListener.getCurrentNode());
  453       }
  454   
  455       /**
  456        * Get the model for JMeter's test tree.
  457        *
  458        * @return the JMeter tree model
  459        */
  460       public ReportTreeModel getTreeModel() {
  461           return treeModel;
  462       }
  463   
  464       /**
  465        * Set the model for JMeter's test tree.
  466        *
  467        * @param newTreeModel
  468        *            the new JMeter tree model
  469        */
  470       public void setTreeModel(ReportTreeModel newTreeModel) {
  471           treeModel = newTreeModel;
  472       }
  473   
  474       /**
  475        * Get a ValueReplacer for the test tree.
  476        *
  477        * @return a ValueReplacer configured for the test tree
  478        */
  479       public ValueReplacer getReplacer() {
  480           return new ValueReplacer((ReportPlan) ((ReportTreeNode) getTreeModel().getReportPlan().getArray()[0])
  481                   .getTestElement());
  482       }
  483   
  484       /**
  485        * Set the main JMeter frame.
  486        *
  487        * @param newMainFrame
  488        *            the new JMeter main frame
  489        */
  490       public void setMainFrame(ReportMainFrame newMainFrame) {
  491           this.mainFrame = newMainFrame;
  492       }
  493   
  494       /**
  495        * Get the main JMeter frame.
  496        *
  497        * @return the main JMeter frame
  498        */
  499       public ReportMainFrame getMainFrame() {
  500           return this.mainFrame;
  501       }
  502   
  503       /**
  504        * Set the listener for JMeter's test tree.
  505        *
  506        * @param newTreeListener
  507        *            the new JMeter test tree listener
  508        */
  509       public void setTreeListener(ReportTreeListener newTreeListener) {
  510           treeListener = newTreeListener;
  511       }
  512   
  513       /**
  514        * Get the listener for JMeter's test tree.
  515        *
  516        * @return the JMeter test tree listener
  517        */
  518       public ReportTreeListener getTreeListener() {
  519           return treeListener;
  520       }
  521   
  522       /**
  523        * Display the specified popup menu with the source component and location
  524        * from the specified mouse event.
  525        *
  526        * @param e
  527        *            the mouse event causing this popup to be displayed
  528        * @param popup
  529        *            the popup menu to display
  530        */
  531       public void displayPopUp(MouseEvent e, JPopupMenu popup) {
  532           displayPopUp((Component) e.getSource(), e, popup);
  533       }
  534   
  535       /**
  536        * Display the specified popup menu at the location specified by a mouse
  537        * event with the specified source component.
  538        *
  539        * @param invoker
  540        *            the source component
  541        * @param e
  542        *            the mouse event causing this popup to be displayed
  543        * @param popup
  544        *            the popup menu to display
  545        */
  546       public void displayPopUp(Component invoker, MouseEvent e, JPopupMenu popup) {
  547           if (popup != null) {
  548               log.debug("Showing pop up for " + invoker + " at x,y = " + e.getX() + "," + e.getY());
  549   
  550               popup.pack();
  551               popup.show(invoker, e.getX(), e.getY());
  552               popup.setVisible(true);
  553               popup.requestFocus();
  554           }
  555       }
  556   
  557       /*
  558        * (non-Javadoc)
  559        *
  560        * @see org.apache.jmeter.util.LocaleChangeListener#localeChanged(org.apache.jmeter.util.LocaleChangeEvent)
  561        */
  562       public void localeChanged(LocaleChangeEvent event) {
  563           // FIrst make sure we save the content of the current GUI (since we
  564           // will flush it away):
  565           updateCurrentNode();
  566   
  567           // Forget about all GUIs we've created so far: we'll need to re-created
  568           // them all!
  569           guis = new HashMap();
  570           nodesToGui = new HashMap();
  571           testBeanGUIs = new HashMap();
  572   
  573           // BeanInfo objects also contain locale-sensitive data -- flush them
  574           // away:
  575           Introspector.flushCaches();
  576   
  577           // Now put the current GUI in place. [This code was copied from the
  578           // EditCommand action -- we can't just trigger the action because that
  579           // would populate the current node with the contents of the new GUI --
  580           // which is empty.]
  581           ReportMainFrame mf = getMainFrame(); // Fetch once
  582           if (mf == null) // Probably caused by unit testing on headless system
  583           {
  584               log.warn("Mainframe is null");
  585           } else {
  586               mf.setMainPanel((javax.swing.JComponent) getCurrentGui());
  587               mf.setEditMenu(getTreeListener().getCurrentNode().createPopupMenu());
  588           }
  589       }
  590   
  591       private String reportPlanFile;
  592   
  593       /**
  594        * Sets the filepath of the current test plan. It's shown in the main frame
  595        * title and used on saving.
  596        *
  597        * @param f
  598        */
  599       public void setReportPlanFile(String f) {
  600           reportPlanFile = f;
  601           ReportGuiPackage.getInstance().getMainFrame().setExtendedFrameTitle(reportPlanFile);
  602           try {
  603               FileServer.getFileServer().setBasedir(reportPlanFile);
  604           } catch (IOException e1) {
  605               log.error("Failure setting file server's base dir", e1);
  606           }
  607       }
  608   
  609       public String getReportPlanFile() {
  610           return reportPlanFile;
  611       }
  612   }

Home » jakarta-jmeter-2.3.4_src » org.apache.jmeter.gui » [javadoc | source]