You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jmeter-dev@jakarta.apache.org by js...@apache.org on 2004/01/04 02:42:52 UTC

cvs commit: jakarta-jmeter/src/core/org/apache/jmeter/testbeans/gui WrapperEditor.java

jsalvata    2004/01/03 17:42:52

  Modified:    src/core/org/apache/jmeter/testbeans/gui Tag:
                        testbeans_experimental_branch WrapperEditor.java
  Log:
  * Provide support for undefined (null) values.
  * Provide support for editors whose getTags() method
  returns a non-null list.
  * Added some unit tests for the issues found during
  development.
  
  Revision  Changes    Path
  No                   revision
  No                   revision
  1.1.2.2   +357 -121  jakarta-jmeter/src/core/org/apache/jmeter/testbeans/gui/Attic/WrapperEditor.java
  
  Index: WrapperEditor.java
  ===================================================================
  RCS file: /home/cvs/jakarta-jmeter/src/core/org/apache/jmeter/testbeans/gui/Attic/WrapperEditor.java,v
  retrieving revision 1.1.2.1
  retrieving revision 1.1.2.2
  diff -u -r1.1.2.1 -r1.1.2.2
  --- WrapperEditor.java	1 Jan 2004 23:43:22 -0000	1.1.2.1
  +++ WrapperEditor.java	4 Jan 2004 01:42:52 -0000	1.1.2.2
  @@ -60,18 +60,20 @@
   import java.awt.Component;
   import java.awt.Graphics;
   import java.awt.Rectangle;
  -import java.awt.event.FocusEvent;
  -import java.awt.event.FocusListener;
   import java.beans.PropertyChangeListener;
   import java.beans.PropertyDescriptor;
   import java.beans.PropertyEditor;
  +import java.beans.PropertyEditorManager;
  +import java.util.Arrays;
  +import java.util.Vector;
   
  -import javax.swing.JTextField;
  -import javax.swing.text.BadLocationException;
  -import javax.swing.text.Document;
  +import javax.swing.JComboBox;
   
   import org.apache.jmeter.testbeans.TestBean;
   import org.apache.jmeter.testelement.property.JMeterProperty;
  +import org.apache.jmeter.testelement.property.NullProperty;
  +import org.apache.jmeter.testelement.property.BooleanProperty;
  +import org.apache.jmeter.testelement.property.StringProperty;
   import org.apache.jorphan.logging.LoggingManager;
   import org.apache.log.Logger;
   
  @@ -79,33 +81,108 @@
    * This class implements a property editor that wraps another PropertyEditor
    * so that:
    * <ul>
  - * <li>It handles JMeterProperty values.
  + * <li>It handles and returns JMeterProperty values wrapping the values
  + * handled and returned by the wrapped PropertyEditor.
    * <li>It provides a suitable GUI component (custom editor) for simple
    * property editors that don't have one of their own.
    * </ul>
  + * <p>
  + * For PropertyEditors that provide a custom editor, this essentially acts
  + * as a delegate, with no added functionality beyond the wrapping/unwrapping
  + * in JMeterProperties.
  + * <p>
  + * For PropertyEditors without a custom editor, the provided GUI is a combo
  + * box with:
  + * <ul>
  + * <li>An option for "undefined" (corresponding to the null value, not the
  + *      NullProperty).
  + * <li>An option for each value returned by the getTags() method on the wrapped
  + * 	editor.
  + * <li>The possibility to write your own value, which will be parsed by the
  + *		wrapped editor to convert into the edited type unless (and this is an
  + *		heuristic) it contains the string "${", in which case it will be
  + *		assumed to be an 'expression' containing JMeter variables and will
  + *		not be parsed at all, but just handled as a string.
  + * </ul>
    */
  -class WrapperEditor
  -    implements PropertyEditor, FocusListener
  +class WrapperEditor implements PropertyEditor
   {
  -    private static Logger log = LoggingManager.getLoggerForClass();
  +    private static Logger log= LoggingManager.getLoggerForClass();
   
  -    PropertyEditor editor;
  -    PropertyDescriptor descriptor;
  +    private static Object UNDEFINED= new Object()
  +    {
  +        public String toString()
  +        {
  +            return "Undefined"; // TODO: should be a resource.
  +        }
  +    };
  +    // The above is a funny hack: if you use a plain String, 
  +    // entering the text of the string in the editor will make the
  +    // combo revert to that option -- which actually amounts to
  +    // making that string 'reserved'. I preferred to avoid this by
  +    // using a different type, but an object that has the same
  +    // .toString().
  +    // TODO: use a renderer that paints
  +    // the field distinct from when the same string is typed in.
  +
  +	/**
  +	 * Base PropertyEditor for the property at hand. Most methods in this class
  +	 * are delegated from this one.
  +	 */
  +    private PropertyEditor editor;
  +    
  +    /**
  +     * Property descriptor for the property to be edited by this editor.
  +     */
  +    private PropertyDescriptor descriptor;
   
  +	/**
  +	 * The type of the objects that will be assigned to or obtained from this
  +	 * property. That is: the type of the property or, if this is a primitive 
  +	 * type (e.g. int), the corresponding wrapping type (e.g. Integer).
  +	 */
  +	private Class type;
  +	
       /**
  -     * The swing component doing the actual GUI work.
  +     * The swing component doing the actual GUI work. May be a customer
  +     * editor component provided by the delegatee editor or a combo box we
  +     * will create otherwise.
        */
  -    Component component;
  +    private Component component;
   
       /**
  -     * Copy of component if it's a text field.
  +     * Copy of component if it's the combo box we've created within this
  +     * editor, or null if the delegatee editor provides a custom editor
  +     * component. This is just a convenience to avoid having to cast
  +     * field 'component' into a JComboBox again and again. 
        */
  -    JTextField field= null;
  -     
  +    private JComboBox combo= null;
  +
       WrapperEditor(PropertyEditor editor, PropertyDescriptor descriptor)
       {
           this.editor= editor;
           this.descriptor= descriptor;
  +        
  +        type= descriptor.getPropertyType();
  +        if (type.isPrimitive())
  +        {
  +        	// Sorry for this -- I have not found a better way:
  +        	if (type == boolean.class) type= Boolean.class;
  +        	else if (type == char.class) type= Character.class;
  +        	else if (type == byte.class) type= Byte.class;
  +			else if (type == short.class) type= Short.class;
  +        	else if (type == int.class) type= Integer.class;
  +        	else if (type == long.class) type= Long.class;
  +        	else if (type == float.class) type= Float.class;
  +			else if (type == double.class) type= Double.class;
  +			else if (type == void.class) type= Void.class;
  +			else
  +			{
  +				log.error("Class "+type+" is an unknown primitive type.");
  +            	throw new Error("Class "+type+" is an unknown primitive type");
  +            		// programming error: bail out.
  +            }
  +        }
   
           if (editor.supportsCustomEditor())
           {
  @@ -113,9 +190,24 @@
           }
           else
           {
  -            field= new JTextField();
  -            field.addFocusListener(this);
  -            component= field;
  +            // Build the list of available values for this property:
  +            Vector options= new Vector();
  +
  +            // The first available value is "undefined" (null).
  +            options.add(UNDEFINED);
  +
  +            // Add the list of values given by the editor, if there is one:
  +            String[] tags= editor.getTags();
  +            if (tags != null)
  +            {
  +                options.addAll(Arrays.asList(tags));
  +            }
  +
  +            // Create the combo box we will use to edit this property:
  +            combo= new JComboBox(options);
  +            combo.setEditable(true);
  +
  +            component= combo;
           }
       }
   
  @@ -128,19 +220,6 @@
       }
   
       /* (non-Javadoc)
  -     * @see java.beans.PropertyEditor#getAsText()
  -     */
  -    public String getAsText()
  -    {
  -        String result= editor.getAsText();
  -        if (log.isDebugEnabled())
  -        {
  -            log.debug(descriptor.getName()+"->\""+result+"\"");
  -        }
  -        return result;
  -    }
  -
  -    /* (non-Javadoc)
        * @see java.beans.PropertyEditor#getCustomEditor()
        */
       public Component getCustomEditor()
  @@ -174,18 +253,178 @@
       {
           String name= descriptor.getName();
           JMeterProperty result;
  -            
  -        result= TestBean.wrapInProperty(editor.getValue());
  -        result.setName(name);
  +
  +        Object value;
  +
  +		if (editor.supportsCustomEditor())
  +		{
  +			value= editor.getValue();
  +		}
  +		else
  +        {
  +        	value= combo.getSelectedItem();
  +			if (value == UNDEFINED)
  +			{
  +				value= null;
  +			}
  +			else {
  +				String text= (String) value;
  +				if (combo.getSelectedIndex() > 0
  +					|| text.indexOf("${") == -1)
  +				{
  +					// if it's not a JMeter 'expression'...
  +					try
  +					{
  +						editor.setAsText(text);
  +						value= editor.getValue();
  +					}
  +					catch (IllegalArgumentException e)
  +					{
  +						// TODO: how to warn the user?
  +						// Maybe we should do this check earlier in the edit
  +						// process, maybe upon ItemChangeEvents?
  +						value= null;
  +					}
  +				}
  +			}
  +        }
  +
  +		if (value != null)
  +		{
  +			result= TestBean.wrapInProperty(value);
  +			result.setName(name);
  +		}
  +		else result= null;
  +        
           if (log.isDebugEnabled())
           {
  -            log.debug(descriptor.getName()+"->"
  -                +(result!=null?result.getClass().getName():"NULL")
  -                +":"+result);
  +            log.debug(
  +                descriptor.getName()
  +                    + "->"
  +                    + (result != null ? result.getClass().getName() : "NULL")
  +                    + ":"
  +                    + result);
           }
           return result;
       }
   
  +	/* (non-Javadoc)
  +	 * @see java.beans.PropertyEditor#setValue(java.lang.Object)
  +	 */
  +	public void setValue(Object value)
  +	{
  +		if (log.isDebugEnabled())
  +		{
  +			log.debug(
  +				descriptor.getName()
  +					+ "<-"
  +					+ (value != null ? value.getClass().getName() : "NULL")
  +					+ ":"
  +					+ value);
  +		}
  +		if (value instanceof JMeterProperty)
  +		{
  +			/*value= TestBean.unwrapProperty(
  +				(JMeterProperty)value,
  +				type);*/
  +			value= ((JMeterProperty)value).getObjectValue();
  +		}
  +		if (editor.supportsCustomEditor())
  +		{
  +			editor.setValue(value);
  +		}
  +		else
  +		{
  +			if (value == null)
  +			{
  +				value= UNDEFINED;
  +			}
  +			else if (type.isInstance(value))
  +			{
  +				editor.setValue(value);
  +				value= editor.getAsText();
  +			}
  +			else
  +			{
  +				// In this case I'll just assume value is a string -- I believe it
  +				// always is but, just in case, I'll check:
  +				if (! (value instanceof String))
  +				{
  +					log.error("When editing property "+descriptor.getName()
  +						+", of type "+type
  +						+" got value of type "+value.getClass());
  +					throw new Error("String expected, got "+value.getClass());
  +						// programming error, so bail out.
  +			    } 
  +			}
  +			combo.setSelectedItem(value);
  +		}
  +	}
  +
  +	/* (non-Javadoc)
  +	 * @see java.beans.PropertyEditor#getAsText()
  +	 */
  +	public String getAsText()
  +	{
  +		String text;
  +		
  +		if (editor.supportsCustomEditor())
  +		{
  +			text= editor.getAsText();
  +		}
  +		else
  +		{
  +			Object value= combo.getSelectedItem();
  +			if (value == UNDEFINED)
  +			{
  +				text= null;
  +			}
  +			else {
  +				text= (String) value;
  +				if (combo.getSelectedIndex() > 0
  +					|| text.indexOf("${") == -1)
  +				{
  +					// if it's not a JMeter 'expression'...
  +					editor.setAsText(text);
  +					text= editor.getAsText();
  +				}
  +			}
  +		}
  +		if (log.isDebugEnabled())
  +		{
  +			log.debug(descriptor.getName() + "->\"" + text + "\"");
  +		}
  +		return text;
  +	}
  +
  +	/* (non-Javadoc)
  +	 * @see java.beans.PropertyEditor#setAsText(java.lang.String)
  +	 */
  +	public void setAsText(String text) throws IllegalArgumentException
  +	{
  +		if (log.isDebugEnabled())
  +		{
  +			log.debug(
  +				descriptor.getName()
  +					+ (text == null ? "<-null" : "<-\"" + text + "\""));
  +		}
  +		if (editor.supportsCustomEditor())
  +		{
  +			editor.setAsText(text);
  +		}
  +		else
  +		{
  +			if (text == null)
  +			{
  +				combo.setSelectedItem(UNDEFINED);
  +			}
  +			else 
  +			{
  +				combo.setSelectedItem(text);
  +			}
  +		}
  +	}
  +
       /* (non-Javadoc)
        * @see java.beans.PropertyEditor#isPaintable()
        */
  @@ -211,91 +450,88 @@
       }
   
       /* (non-Javadoc)
  -     * @see java.beans.PropertyEditor#setAsText(java.lang.String)
  -     */
  -    public void setAsText(String text) throws IllegalArgumentException
  -    {
  -        if (log.isDebugEnabled())
  -        {
  -            log.debug(descriptor.getName()+"<-\""+text+"\"");
  -        }
  -        if (field != null)
  -        {
  -            field.setText(text);
  -        }
  -        editor.setAsText(text);
  -    }
  -
  -    /* (non-Javadoc)
  -     * @see java.beans.PropertyEditor#setValue(java.lang.Object)
  -     */
  -    public void setValue(Object value)
  -    {
  -        if (log.isDebugEnabled())
  -        {
  -            log.debug(descriptor.getName()+"<-"
  -                +(value!=null?value.getClass().getName():"NULL")
  -                +":"+value);
  -        }
  -        if (value instanceof JMeterProperty)
  -        {
  -            value= TestBean.unwrapProperty(
  -                (JMeterProperty)value, descriptor.getPropertyType());
  -        }
  -        editor.setValue(value);
  -        if (field != null)
  -        {
  -            field.setText(editor.getAsText());
  -        }
  -    }
  -
  -    /* (non-Javadoc)
        * @see java.beans.PropertyEditor#supportsCustomEditor()
        */
       public boolean supportsCustomEditor()
       {
           return true;
       }
  -
  -    /* (non-Javadoc)
  -     * @see java.awt.event.FocusListener#focusGained(java.awt.event.FocusEvent)
  -     */
  -    public void focusGained(FocusEvent e)
  -    {
  -        // no-op
  -    }
  -
  -    /* (non-Javadoc)
  -     * @see java.awt.event.FocusListener#focusLost(java.awt.event.FocusEvent)
  -     */
  -    public void focusLost(FocusEvent e)
  -    {
  -        // Copy our data back to the property editor:
  -            
  -        Document d= field.getDocument();
  -        String text;
  -        try
  -        {
  -            text= d.getText(0, d.getLength());
  -        }
  -        catch (BadLocationException e1)
  -        {
  -            log.error("This can't happen!", e1);
  -            throw new Error(e1); // Bail out.
  -        }
  -
  -        if (log.isDebugEnabled())
  -        {
  -            log.debug(descriptor.getName()+": "+text);
  -        }
  -
  -        try
  -        {
  -            editor.setAsText(text);
  -        }
  -        catch (IllegalArgumentException e1)
  -        {
  -            // TODO: report to the user??
  -        }
  -    }
  -}
  +    
  +	public static class Test extends junit.framework.TestCase
  +	{
  +		public Test(String name)
  +		{
  +			super(name);
  +		}
  +		
  +		private abstract class ABean {
  +			public abstract void setB(boolean b);
  +			public abstract boolean getB();
  +			public abstract void setS(String b);
  +			public abstract String getS();
  +		}
  +		
  +		private void testSetGet(WrapperEditor e, Object value) throws Exception
  +		{
  +			e.setValue(value);
  +			assertEquals(value, e.getValue());
  +		}
  +		private void testSetGetAsText(WrapperEditor e, String text) throws Exception
  +		{
  +			e.setAsText(text);
  +			assertEquals(text, e.getAsText());
  +		}
  +		public void testSetGetOnSimpleEditor() throws Exception
  +		{
  +			WrapperEditor e= new WrapperEditor(
  +				PropertyEditorManager.findEditor(boolean.class), 
  +				new PropertyDescriptor("B", ABean.class));
  +				
  +			testSetGet(e, new BooleanProperty("B", true));
  +			testSetGet(e, new BooleanProperty("B", false));
  +			testSetGet(e, null);
  +			testSetGet(e, new StringProperty("B", "${var}"));
  +			
  +			e.setValue(new StringProperty("B", "true"));
  +			assertEquals(new BooleanProperty("B", true), e.getValue());
  +
  +			e.setValue(new StringProperty("B", "True"));
  +			assertEquals(new BooleanProperty("B", true), e.getValue());
  +		}
  +		public void testSetGetAsTextOnSimpleEditor() throws Exception
  +		{
  +			WrapperEditor e= new WrapperEditor(
  +				PropertyEditorManager.findEditor(boolean.class), 
  +				new PropertyDescriptor("B", ABean.class));
  +				
  +			testSetGetAsText(e, "True");
  +			testSetGetAsText(e, "False");
  +			testSetGetAsText(e, null);
  +			testSetGetAsText(e, "${var}");
  +			
  +			e.setAsText("true");
  +			assertEquals(new BooleanProperty("B", true), e.getValue());
  +
  +			e.setAsText("True");
  +			assertEquals(new BooleanProperty("B", true), e.getValue());
  +			
  +			e.setAsText("invalid");
  +			assertEquals(null, e.getValue());
  +		}
  +		public void testSetGetAsTextOnString() throws Exception
  +		{
  +			WrapperEditor e= new WrapperEditor(
  +				PropertyEditorManager.findEditor(String.class), 
  +				new PropertyDescriptor("S", ABean.class));
  +				
  +			testSetGetAsText(e, "any string");
  +			testSetGetAsText(e, "");
  +			testSetGetAsText(e, null);
  +			testSetGetAsText(e, "${var}");
  +			
  +			// Check "Undefined" does not become a "reserved word":
  +			e.setAsText(UNDEFINED.toString());
  +			assertNotNull(e.getValue());
  +		}
  +	}
  +}
  \ No newline at end of file
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: jmeter-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jmeter-dev-help@jakarta.apache.org