alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

JMeter example source code file (WrapperEditor.java)

This example JMeter source code file (WrapperEditor.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - JMeter tags/keywords

awt, bean, combostringeditor, error, gui, illegalargumentexception, illegalargumentexception, javabean, non-nls-1, non-nls-1, null, object, override, override, propertyeditor, string, string, swing, text

The JMeter WrapperEditor.java source code

/*
 * 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.testbeans.gui;

import java.awt.Component;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorSupport;

import javax.swing.JOptionPane;

import org.apache.jmeter.gui.GuiPackage;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;

/**
 * This is an implementation of a full-fledged property editor, providing both
 * object-text transformation and an editor GUI (a custom editor component),
 * from two simpler property editors providing only one of these functionalities
 * each, namely:
 * <dl>
 * <dt>typeEditor
 * <dt>
 * <dd>Provides suitable object-to-string and string-to-object transformation
 * for the property's type. That is: it's a simple editor that only need to
 * support the set/getAsText and set/getValue methods.</dd>
 * <dt>guiEditor
 * <dd>Provides a suitable GUI for the property, but works on [possibly null]
 * String values. That is: it supportsCustomEditor, but get/setAsText and
 * get/setValue are indentical.</dd>
 * </dl>
 * <p>
 * The resulting editor provides optional support for null values (you can
 * choose whether <b>null is to be a valid property value). It also
 * provides optional support for JMeter 'expressions' (you can choose whether
 * they make valid property values).
 *
 */
class WrapperEditor extends PropertyEditorSupport implements PropertyChangeListener {
    private static final Logger log = LoggingManager.getLoggerForClass();

    /**
     * The type's property editor.
     */
    private PropertyEditor typeEditor;

    /**
     * The gui property editor
     */
    private PropertyEditor guiEditor;

    /**
     * Whether to allow <b>null as a property value.
     */
    private boolean acceptsNull;

    /**
     * Whether to allow JMeter 'expressions' as property values.
     */
    private boolean acceptsExpressions;

    /**
     * Whether to allow any constant values different from the provided tags.
     */
    private boolean acceptsOther;

    /**
     * Keep track of the last valid value in the editor, so that we can revert
     * to it if the user enters an invalid value.
     */
    private String lastValidValue = null;

    /**
     * Constructor for use when a PropertyEditor is delegating to us.
     */
    WrapperEditor(Object source, PropertyEditor typeEditor, PropertyEditor guiEditor, boolean acceptsNull,
            boolean acceptsExpressions, boolean acceptsOther, Object defaultValue) {
        super(source);
        initialize(typeEditor, guiEditor, acceptsNull, acceptsExpressions, acceptsOther, defaultValue);
    }

    /**
     * Constructor for use for regular instantiation and by subclasses.
     */
    WrapperEditor(PropertyEditor typeEditor, PropertyEditor guiEditor, boolean acceptsNull, boolean acceptsExpressions,
            boolean acceptsOther, Object defaultValue) {
        super();
        initialize(typeEditor, guiEditor, acceptsNull, acceptsExpressions, acceptsOther, defaultValue);
    }

    private void initialize(PropertyEditor _typeEditor, PropertyEditor _guiEditor, boolean _acceptsNull,
            boolean _acceptsExpressions, boolean _acceptsOther, Object defaultValue) {
        this.typeEditor = _typeEditor;
        this.guiEditor = _guiEditor;
        this.acceptsNull = _acceptsNull;
        this.acceptsExpressions = _acceptsExpressions;
        this.acceptsOther = _acceptsOther;

        setValue(defaultValue);
        lastValidValue = getAsText();

        if (_guiEditor instanceof ComboStringEditor) {
            String[] tags = ((ComboStringEditor) _guiEditor).getTags();

            // Provide an initial edit value if necessary -- this is an
            // heuristic that tries to provide the most convenient
            // initial edit value:

            String v;
            if (!_acceptsOther) {
                v = "${}"; //$NON-NLS-1$
            } else if (isValidValue("")) { //$NON-NLS-1$
                v = ""; //$NON-NLS-1$
            } else if (_acceptsExpressions) {
                v = "${}"; //$NON-NLS-1$
            } else if (tags != null && tags.length > 0) {
                v = tags[0];
            } else {
                v = getAsText();
            }

            ((ComboStringEditor) _guiEditor).setInitialEditValue(v);
        }

        _guiEditor.addPropertyChangeListener(this);
    }

    @Override
    public boolean supportsCustomEditor() {
        return true;
    }

    @Override
    public Component getCustomEditor() {
        return guiEditor.getCustomEditor();
    }

    @Override
    public String[] getTags() {
        return guiEditor.getTags();
    }

    /**
     * Determine wheter a string is one of the known tags.
     *
     * @param text
     * @return true iif text equals one of the getTags()
     */
    private boolean isATag(String text) {
        String[] tags = getTags();
        if (tags == null) {
            return false;
        }
        for (int i = 0; i < tags.length; i++) {
            if (tags[i].equals(text)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Determine whether a string is a valid value for the property.
     *
     * @param text
     *            the value to be checked
     * @return true iif text is a valid value
     */
    private boolean isValidValue(String text) {
        if (text == null) {
            return acceptsNull;
        }

        if (acceptsExpressions && isExpression(text)) {
            return true;
        }

        // Not an expression (isn't or can't be), not null.

        // The known tags are assumed to be valid:
        if (isATag(text)) {
            return true;
        }
        // Was not a tag, so if we can't accept other values...
        if (!acceptsOther) {
            return false;
        }

        // Delegate the final check to the typeEditor:
        try {
            typeEditor.setAsText(text);
        } catch (IllegalArgumentException e1) {
            // setAsText failed: not valid
            return false;
        }
        // setAsText succeeded: valid
        return true;
    }

    /**
     * This method is used to do some low-cost defensive programming: it is
     * called when a condition that the program logic should prevent from
     * happening occurs. I hope this will help early detection of logical bugs
     * in property value handling.
     *
     * @throws Error
     *             always throws an error.
     */
    private final void shouldNeverHappen(String msg) throws Error {
        throw new Error(msg); // Programming error: bail out.
    }

    /**
     * Same as shouldNeverHappen(), but provide a source exception.
     *
     * @param e
     *            the exception that helped identify the problem
     * @throws Error
     *             always throws one.
     */
    private final void shouldNeverHappen(Exception e) throws Error {
        throw new Error(e.toString()); // Programming error: bail out.
    }

    /**
     * Check if a string is a valid JMeter 'expression'.
     * <p>
     * The current implementation is very basic: it just accepts any string
     * containing "${" as a valid expression. TODO: improve, but keep returning
     * true for "${}".
     */
    private final boolean isExpression(String text) {
        return text.indexOf("${") != -1;//$NON-NLS-1$
    }

    /**
     * Same as isExpression(String).
     *
     * @param text
     * @return true iif text is a String and isExpression(text).
     */
    private final boolean isExpression(Object text) {
        return text instanceof String && isExpression((String) text);
    }

    /**
     * @see java.beans.PropertyEditor#getValue()
     * @see org.apache.jmeter.testelement.property.JMeterProperty
     */
    @Override
    public Object getValue() {
        String text = (String) guiEditor.getValue();

        Object value;

        if (text == null) {
            if (!acceptsNull) {
                shouldNeverHappen("Text is null but null is not allowed");
            }
            value = null;
        } else {
            if (acceptsExpressions && isExpression(text)) {
                value = text;
            } else {
                // not an expression (isn't or can't be), not null.

                // a check, just in case:
                if (!acceptsOther && !isATag(text)) {
                    shouldNeverHappen("Text is not a tag but other entries are not allowed");
                }

                try {
                    // Bug 44314  Number field does not seem to accept ""
                    try {
                        typeEditor.setAsText(text);
                    } catch (NumberFormatException e) {
                        if (text.length()==0){
                            text="0";//$NON-NLS-1$
                            typeEditor.setAsText(text);
                        } else {
                            shouldNeverHappen(e);
                        }
                    }
                } catch (IllegalArgumentException e) {
                    shouldNeverHappen(e);
                }
                value = typeEditor.getValue();
            }
        }

        if (log.isDebugEnabled()) {
            log.debug("->" + (value != null ? value.getClass().getName() : "NULL") + ":" + value);
        }
        return value;
    }

    @Override
    public void setValue(Object value) {
        String text;

        if (log.isDebugEnabled()) {
            log.debug("<-" + (value != null ? value.getClass().getName() : "NULL") + ":" + value);
        }

        if (value == null) {
            if (!acceptsNull) {
                throw new IllegalArgumentException("Null is not allowed");
            }
            text = null;
        } else if (acceptsExpressions && isExpression(value)) {
            text = (String) value;
        } else {
            // Not an expression (isn't or can't be), not null.
            typeEditor.setValue(value); // may throw IllegalArgumentExc.
            text = fixGetAsTextBug(typeEditor.getAsText());

            if (!acceptsOther && !isATag(text)) {
                throw new IllegalArgumentException("Value not allowed: "+text);
            }
        }

        guiEditor.setValue(text);
    }

    /*
     * Fix bug in JVMs that return true/false rather than True/False
     * from the type editor getAsText() method
     */
    private String fixGetAsTextBug(String asText) {
        if (asText == null){
            return asText;
        }
        if (asText.equals("true")){
            log.debug("true=>True");// so we can detect it
            return "True";
        }
        if (asText.equals("false")){
            log.debug("false=>False");// so we can detect it
            return "False";
        }
        return asText;
    }

    @Override
    public String getAsText() {
        String text = fixGetAsTextBug(guiEditor.getAsText());

        if (text == null) {
            if (!acceptsNull) {
                shouldNeverHappen("Text is null, but null is not allowed");
            }
        } else if (!acceptsExpressions || !isExpression(text)) {
            // not an expression (can't be or isn't), not null.
            try {
                typeEditor.setAsText(text);
            } catch (IllegalArgumentException e) {
                shouldNeverHappen(e);
            }
            text = fixGetAsTextBug(typeEditor.getAsText());

            // a check, just in case:
            if (!acceptsOther && !isATag(text)) {
                shouldNeverHappen("Text is not a tag, but other values are not allowed");
            }
        }

        if (log.isDebugEnabled()) {
            log.debug("->\"" + text + "\"");
        }
        return text;
    }

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        if (log.isDebugEnabled()) {
            log.debug(text == null ? "<-null" : "<-\"" + text + "\"");
        }

        String value;

        if (text == null) {
            if (!acceptsNull) {
                throw new IllegalArgumentException("Null parameter not allowed");
            }
            value = null;
        } else {
            if (acceptsExpressions && isExpression(text)) {
                value = text;
            } else {
                // Some editors do tiny transformations (e.g. "true" to
                // "True",...):
                typeEditor.setAsText(text); // may throw IllegalArgumentException
                value = typeEditor.getAsText();

                if (!acceptsOther && !isATag(text)) {
                    throw new IllegalArgumentException("Value not allowed: "+text);
                }
            }
        }

        guiEditor.setValue(value);
    }

    public void propertyChange(PropertyChangeEvent event) {
        String text = fixGetAsTextBug(guiEditor.getAsText());
        if (isValidValue(text)) {
            lastValidValue = text;
            firePropertyChange();
        } else {
            if (GuiPackage.getInstance() == null){
                log.warn("Invalid value: "+text+" "+guiEditor);
            } else {
                JOptionPane.showMessageDialog(guiEditor.getCustomEditor().getParent(),
                   JMeterUtils.getResString("property_editor.value_is_invalid_message"),//$NON-NLS-1$
                    JMeterUtils.getResString("property_editor.value_is_invalid_title"),  //$NON-NLS-1$
                    JOptionPane.WARNING_MESSAGE);
            }
            // Revert to the previous value:
            guiEditor.setAsText(lastValidValue);
        }
    }
}

Other JMeter examples (source code examples)

Here is a short list of links related to this JMeter WrapperEditor.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.