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