Package org.apache.jmeter.gui

Source Code of org.apache.jmeter.gui.GuiPackage

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package org.apache.jmeter.gui;

import java.awt.Component;
import java.awt.event.MouseEvent;
import java.beans.Introspector;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;

import org.apache.jmeter.engine.util.ValueReplacer;
import org.apache.jmeter.exceptions.IllegalUserActionException;
import org.apache.jmeter.gui.tree.JMeterTreeListener;
import org.apache.jmeter.gui.tree.JMeterTreeModel;
import org.apache.jmeter.gui.tree.JMeterTreeNode;
import org.apache.jmeter.services.FileServer;
import org.apache.jmeter.testbeans.TestBean;
import org.apache.jmeter.testbeans.gui.TestBeanGUI;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.TestPlan;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jmeter.util.LocaleChangeEvent;
import org.apache.jmeter.util.LocaleChangeListener;
import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;

/**
* GuiPackage is a static class that provides convenient access to information
* about the current state of JMeter's GUI. Any GUI class can grab a handle to
* GuiPackage by calling the static method {@link #getInstance()} and then use
* it to query the GUI about it's state. When actions, for instance, need to
* affect the GUI, they typically use GuiPackage to get access to different
* parts of the GUI.
*
*/
public final class GuiPackage implements LocaleChangeListener {
  /** Logging. */
  private static final Logger log = LoggingManager.getLoggerForClass();

  /** Singleton instance. */
  private static GuiPackage guiPack;

  /**
   * Flag indicating whether or not parts of the tree have changed since they
   * were last saved.
   */
  private boolean dirty = false;

  /**
   * Map from TestElement to JMeterGUIComponent, mapping the nodes in the tree
   * to their corresponding GUI components.
   */
  private Map nodesToGui = new HashMap();

  /**
   * Map from Class to JMeterGUIComponent, mapping the Class of a GUI
   * component to an instance of that component.
   */
  private Map guis = new HashMap();

  /**
   * Map from Class to TestBeanGUI, mapping the Class of a TestBean to an
   * instance of TestBeanGUI to be used to edit such components.
   */
  private Map testBeanGUIs = new HashMap();

  /** The currently selected node in the tree. */
  private JMeterTreeNode currentNode = null;

  private boolean currentNodeUpdated = false;

  /** The model for JMeter's test tree. */
  private JMeterTreeModel treeModel;

  /** The listener for JMeter's test tree. */
  private JMeterTreeListener treeListener;

  /** The main JMeter frame. */
  private MainFrame mainFrame;

  /**
   * Private constructor to permit instantiation only from within this class.
   * Use {@link #getInstance()} to retrieve a singleton instance.
   */
  private GuiPackage() {
    JMeterUtils.addLocaleChangeListener(this);
  }

  /**
   * Retrieve the singleton GuiPackage instance.
   *
   * @return the GuiPackage instance
   */
  public static GuiPackage getInstance() {
    return guiPack;
  }

  /**
   * When GuiPackage is requested for the first time, it should be given
   * handles to JMeter's Tree Listener and TreeModel.
   *
   * @param listener
   *            the TreeListener for JMeter's test tree
   * @param treeModel
   *            the model for JMeter's test tree
   *
   * @return GuiPackage
   */
  public static GuiPackage getInstance(JMeterTreeListener listener, JMeterTreeModel treeModel) {
    if (guiPack == null) {
      guiPack = new GuiPackage();
      guiPack.setTreeListener(listener);
      guiPack.setTreeModel(treeModel);
    }
    return guiPack;
  }

  /**
   * Get a JMeterGUIComponent for the specified test element. If the GUI has
   * already been created, that instance will be returned. Otherwise, if a GUI
   * component of the same type has been created, and the component is not
   * marked as an {@link UnsharedComponent}, that shared component will be
   * returned. Otherwise, a new instance of the component will be created. The
   * TestElement's GUI_CLASS property will be used to determine the
   * appropriate type of GUI component to use.
   *
   * @param node
   *            the test element which this GUI is being created for
   *
   * @return the GUI component corresponding to the specified test element
   */
  public JMeterGUIComponent getGui(TestElement node) {
    String testClassName = node.getPropertyAsString(TestElement.TEST_CLASS);
    String guiClassName = node.getPropertyAsString(TestElement.GUI_CLASS);
    try {
      Class testClass;
      if (testClassName.equals("")) { // $NON-NLS-1$
        testClass = node.getClass();
      } else {
        testClass = Class.forName(testClassName);
      }
      Class guiClass = null;
      if (!guiClassName.equals("")) { // $NON-NLS-1$
        guiClass = Class.forName(guiClassName);
      }
      return getGui(node, guiClass, testClass);
    } catch (ClassNotFoundException e) {
      log.error("Could not get GUI for " + node, e);
      return null;
    }
  }

  /**
   * Get a JMeterGUIComponent for the specified test element. If the GUI has
   * already been created, that instance will be returned. Otherwise, if a GUI
   * component of the same type has been created, and the component is not
   * marked as an {@link UnsharedComponent}, that shared component will be
   * returned. Otherwise, a new instance of the component will be created.
   *
   * @param node
   *            the test element which this GUI is being created for
   * @param guiClass
   *            the fully qualifed class name of the GUI component which will
   *            be created if it doesn't already exist
   * @param testClass
   *            the fully qualifed class name of the test elements which have
   *            to be edited by the returned GUI component
   *
   * @return the GUI component corresponding to the specified test element
   */
  public JMeterGUIComponent getGui(TestElement node, Class guiClass, Class testClass) {
    try {
      JMeterGUIComponent comp = (JMeterGUIComponent) nodesToGui.get(node);
      if (comp == null) {
        comp = getGuiFromCache(guiClass, testClass);
        nodesToGui.put(node, comp);
      }
      log.debug("Gui retrieved = " + comp);
      return comp;
    } catch (Exception e) {
      log.error("Problem retrieving gui", e);
      return null;
    }
  }

  /**
   * Remove a test element from the tree. This removes the reference to any
   * associated GUI component.
   *
   * @param node
   *            the test element being removed
   */
  public void removeNode(TestElement node) {
    nodesToGui.remove(node);
  }

  /**
   * Convenience method for grabbing the gui for the current node.
   *
   * @return the GUI component associated with the currently selected node
   */
  public JMeterGUIComponent getCurrentGui() {
    try {
      updateCurrentNode();
      TestElement curNode = treeListener.getCurrentNode().getTestElement();
      JMeterGUIComponent comp = getGui(curNode);
      comp.clearGui();
      log.debug("Updating gui to new node");
      comp.configure(curNode);
      currentNodeUpdated = false;
      return comp;
    } catch (Exception e) {
      log.error("Problem retrieving gui", e);
      return null;
    }
  }

  /**
   * Find the JMeterTreeNode for a certain TestElement object.
   *
   * @param userObject
   *            the test element to search for
   * @return the tree node associated with the test element
   */
  public JMeterTreeNode getNodeOf(TestElement userObject) {
    return treeModel.getNodeOf(userObject);
  }

  /**
   * Create a TestElement corresponding to the specified GUI class.
   *
   * @param guiClass
   *            the fully qualified class name of the GUI component or a
   *            TestBean class for TestBeanGUIs.
   * @param testClass
   *            the fully qualified class name of the test elements edited by
   *            this GUI component.
   * @return the test element corresponding to the specified GUI class.
   */
  public TestElement createTestElement(Class guiClass, Class testClass) {
    try {
      JMeterGUIComponent comp = getGuiFromCache(guiClass, testClass);
      comp.clearGui();
      TestElement node = comp.createTestElement();
      nodesToGui.put(node, comp);
      return node;
    } catch (Exception e) {
      log.error("Problem retrieving gui", e);
      return null;
    }
  }

  /**
   * Create a TestElement for a GUI or TestBean class.
   * <p>
   * This is a utility method to help actions do with one single String
   * parameter.
   *
   * @param objClass
   *            the fully qualified class name of the GUI component or of the
   *            TestBean subclass for which a TestBeanGUI is wanted.
   * @return the test element corresponding to the specified GUI class.
   */
  public TestElement createTestElement(String objClass) {
    JMeterGUIComponent comp;
    Class c;
    try {
      c = Class.forName(objClass);
      if (TestBean.class.isAssignableFrom(c)) {
        comp = getGuiFromCache(TestBeanGUI.class, c);
      } else {
        comp = getGuiFromCache(c, null);
      }
      comp.clearGui();
      TestElement node = comp.createTestElement();
      nodesToGui.put(node, comp);
      return node;
    } catch (NoClassDefFoundError e) {
      log.error("Problem retrieving gui for " + objClass, e);
            String msg="Cannot find class: "+e.getMessage();
            JOptionPane.showMessageDialog(null,
                    msg,
                    "Missing jar? See log file." ,
                    JOptionPane.ERROR_MESSAGE);
      throw new RuntimeException(e.toString()); // Probably a missing
                            // jar
    } catch (ClassNotFoundException e) {
      log.error("Problem retrieving gui for " + objClass, e);
      throw new RuntimeException(e.toString()); // Programming error:
                            // bail out.
    } catch (InstantiationException e) {
      log.error("Problem retrieving gui for " + objClass, e);
      throw new RuntimeException(e.toString()); // Programming error:
                            // bail out.
    } catch (IllegalAccessException e) {
      log.error("Problem retrieving gui for " + objClass, e);
      throw new RuntimeException(e.toString()); // Programming error:
                            // bail out.
    }
  }

  /**
   * Get an instance of the specified JMeterGUIComponent class. If an instance
   * of the GUI class has previously been created and it is not marked as an
   * {@link UnsharedComponent}, that shared instance will be returned.
   * Otherwise, a new instance of the component will be created, and shared
   * components will be cached for future retrieval.
   *
   * @param guiClass
   *            the fully qualified class name of the GUI component. This
   *            class must implement JMeterGUIComponent.
   * @param testClass
   *            the fully qualified class name of the test elements edited by
   *            this GUI component. This class must implement TestElement.
   * @return an instance of the specified class
   *
   * @throws InstantiationException
   *             if an instance of the object cannot be created
   * @throws IllegalAccessException
   *             if access rights do not allow the default constructor to be
   *             called
   * @throws ClassNotFoundException
   *             if the specified GUI class cannot be found
   */
  private JMeterGUIComponent getGuiFromCache(Class guiClass, Class testClass) throws InstantiationException,
      IllegalAccessException {
    JMeterGUIComponent comp;
    if (guiClass == TestBeanGUI.class) {
      comp = (TestBeanGUI) testBeanGUIs.get(testClass);
      if (comp == null) {
        comp = new TestBeanGUI(testClass);
        testBeanGUIs.put(testClass, comp);
      }
    } else {
      comp = (JMeterGUIComponent) guis.get(guiClass);
      if (comp == null) {
        comp = (JMeterGUIComponent) guiClass.newInstance();
        if (!(comp instanceof UnsharedComponent)) {
          guis.put(guiClass, comp);
        }
      }
    }
    return comp;
  }

  /**
   * Update the GUI for the currently selected node. The GUI component is
   * configured to reflect the settings in the current tree node.
   *
   */
  public void updateCurrentGui() {
    updateCurrentNode();
    currentNode = treeListener.getCurrentNode();
    TestElement element = currentNode.getTestElement();
    JMeterGUIComponent comp = getGui(element);
    comp.configure(element);
    currentNodeUpdated = false;
  }

  /**
   * This method should be called in order for GuiPackage to change the
   * current node. This will save any changes made to the earlier node before
   * choosing the new node.
   */
  public void updateCurrentNode() {
    try {
      if (currentNode != null && !currentNodeUpdated) {
        log.debug("Updating current node " + currentNode.getName());
        JMeterGUIComponent comp = getGui(currentNode.getTestElement());
        TestElement el = currentNode.getTestElement();
        comp.modifyTestElement(el);
      }
      // The current node is now updated
      currentNodeUpdated = true;
      currentNode = treeListener.getCurrentNode();
    } catch (Exception e) {
      log.error("Problem retrieving gui", e);
    }
  }

  public JMeterTreeNode getCurrentNode() {
    return treeListener.getCurrentNode();
  }

  public TestElement getCurrentElement() {
    return getCurrentNode().getTestElement();
  }

  /**
   * The dirty property is a flag that indicates whether there are parts of
   * JMeter's test tree that the user has not saved since last modification.
   * Various (@link Command actions) set this property when components are
   * modified/created/saved.
   *
   * @param dirty
   *            the new value of the dirty flag
   */
  public void setDirty(boolean dirty) {
    this.dirty = dirty;
  }

  /**
   * Retrieves the state of the 'dirty' property, a flag that indicates if
   * there are test tree components that have been modified since they were
   * last saved.
   *
   * @return true if some tree components have been modified since they were
   *         last saved, false otherwise
   */
  public boolean isDirty() {
    return dirty;
  }

  /**
   * Add a subtree to the currently selected node.
   *
   * @param subTree
   *            the subtree to add.
   *
   * @return the resulting subtree starting with the currently selected node
   *
   * @throws IllegalUserActionException
   *             if a subtree cannot be added to the currently selected node
   */
  public HashTree addSubTree(HashTree subTree) throws IllegalUserActionException {
    return treeModel.addSubTree(subTree, treeListener.getCurrentNode());
  }

  /**
   * Get the currently selected subtree.
   *
   * @return the subtree of the currently selected node
   */
  public HashTree getCurrentSubTree() {
    return treeModel.getCurrentSubTree(treeListener.getCurrentNode());
  }

  /**
   * Get the model for JMeter's test tree.
   *
   * @return the JMeter tree model
   */
  /*
   * TODO consider removing this method, and providing method wrappers instead.
   * This would allow the Gui package to do any additional clearups if required,
   * as has been done with clearTestPlan()
  */
  public JMeterTreeModel getTreeModel() {
    return treeModel;
  }

  /**
   * Set the model for JMeter's test tree.
   *
   * @param newTreeModel
   *            the new JMeter tree model
   */
  public void setTreeModel(JMeterTreeModel newTreeModel) {
    treeModel = newTreeModel;
  }

  /**
   * Get a ValueReplacer for the test tree.
   *
   * @return a ValueReplacer configured for the test tree
   */
  public ValueReplacer getReplacer() {
    return new ValueReplacer((TestPlan) ((JMeterTreeNode) getTreeModel().getTestPlan().getArray()[0])
        .getTestElement());
  }

  /**
   * Set the main JMeter frame.
   *
   * @param newMainFrame
   *            the new JMeter main frame
   */
  public void setMainFrame(MainFrame newMainFrame) {
    mainFrame = newMainFrame;
  }

  /**
   * Get the main JMeter frame.
   *
   * @return the main JMeter frame
   */
  public MainFrame getMainFrame() {
    return mainFrame;
  }

  /**
   * Set the listener for JMeter's test tree.
   *
   * @param newTreeListener
   *            the new JMeter test tree listener
   */
  public void setTreeListener(JMeterTreeListener newTreeListener) {
    treeListener = newTreeListener;
  }

  /**
   * Get the listener for JMeter's test tree.
   *
   * @return the JMeter test tree listener
   */
  public JMeterTreeListener getTreeListener() {
    return treeListener;
  }

  /**
   * Display the specified popup menu with the source component and location
   * from the specified mouse event.
   *
   * @param e
   *            the mouse event causing this popup to be displayed
   * @param popup
   *            the popup menu to display
   */
  public void displayPopUp(MouseEvent e, JPopupMenu popup) {
    displayPopUp((Component) e.getSource(), e, popup);
  }

  /**
   * Display the specified popup menu at the location specified by a mouse
   * event with the specified source component.
   *
   * @param invoker
   *            the source component
   * @param e
   *            the mouse event causing this popup to be displayed
   * @param popup
   *            the popup menu to display
   */
  public void displayPopUp(Component invoker, MouseEvent e, JPopupMenu popup) {
    if (popup != null) {
      log.debug("Showing pop up for " + invoker + " at x,y = " + e.getX() + "," + e.getY());

      popup.pack();
      popup.show(invoker, e.getX(), e.getY());
      popup.setVisible(true);
      popup.requestFocus();
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see org.apache.jmeter.util.LocaleChangeListener#localeChanged(org.apache.jmeter.util.LocaleChangeEvent)
   */
  public void localeChanged(LocaleChangeEvent event) {
    // FIrst make sure we save the content of the current GUI (since we
    // will flush it away):
    updateCurrentNode();

    // Forget about all GUIs we've created so far: we'll need to re-created
    // them all!
    guis = new HashMap();
    nodesToGui = new HashMap();
    testBeanGUIs = new HashMap();

    // BeanInfo objects also contain locale-sensitive data -- flush them
    // away:
    Introspector.flushCaches();

    // Now put the current GUI in place. [This code was copied from the
    // EditCommand action -- we can't just trigger the action because that
    // would populate the current node with the contents of the new GUI --
    // which is empty.]
    MainFrame mf = getMainFrame(); // Fetch once
    if (mf == null) // Probably caused by unit testing on headless system
    {
      log.warn("Mainframe is null");
    } else {
      mf.setMainPanel((javax.swing.JComponent) getCurrentGui());
      mf.setEditMenu(getTreeListener().getCurrentNode().createPopupMenu());
    }
  }

  private String testPlanFile;

  /**
   * Sets the filepath of the current test plan. It's shown in the main frame
   * title and used on saving.
   *
   * @param f
   */
  public void setTestPlanFile(String f) {
    testPlanFile = f;
        getMainFrame().setExtendedFrameTitle(testPlanFile);
        // Enable file revert action if a file is used
        getMainFrame().setFileRevertEnabled(f != null);
        getMainFrame().setProjectFileLoaded(f);

    try {
      FileServer.getFileServer().setBasedir(testPlanFile);
    } catch (IOException e1) {
      log.error("Failure setting file server's base dir", e1);
    }
  }

  public String getTestPlanFile() {
    return testPlanFile;
  }

  /**
   * Clears the test plan and associated objects.
   * Clears the test plan file name.
   */
    public void clearTestPlan() {
        getTreeModel().clearTestPlan();
        nodesToGui.clear();
        setTestPlanFile(null);
    }

    /**
     * Clears the test plan element and associated object
     *
     * @param element to clear
     */
    public void clearTestPlan(TestElement element) {
        getTreeModel().clearTestPlan(element);
        removeNode(element);
    }

    public static void showErrorMessage(final String message, final String title){
        showMessage(message,title,JOptionPane.ERROR_MESSAGE);
    }

    public static void showInfoMessage(final String message, final String title){
        showMessage(message,title,JOptionPane.INFORMATION_MESSAGE);
    }

    public static void showWarningMessage(final String message, final String title){
        showMessage(message,title,JOptionPane.WARNING_MESSAGE);
    }

    public static void showMessage(final String message, final String title, final int type){
        if (guiPack == null) {
            return ;
        }
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JOptionPane.showMessageDialog(null,message,title,type);
            }
        });
       
    }
}
TOP

Related Classes of org.apache.jmeter.gui.GuiPackage

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.