generictestbeancustomizer.java
来自「测试工具」· Java 代码 · 共 614 行 · 第 1/2 页
JAVA
614 行
/*
* 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.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
/**
* The GenericTestBeanCustomizer is designed to provide developers with a
* mechanism to quickly implement GUIs for new components.
* <p>
* It allows editing each of the public exposed properties of the edited type 'a
* la JavaBeans': as far as the types of those properties have an associated
* editor, there's no GUI development required.
* <p>
* This class understands the following PropertyDescriptor attributes:
* <dl>
* <dt>group: String</dt>
* <dd>Group under which the property should be shown in the GUI. The string is
* also used as a group title (but see comment on resourceBundle below). The
* default group is "".</dd>
* <dt>order: Integer</dt>
* <dd>Order in which the property will be shown in its group. A smaller
* integer means higher up in the GUI. The default order is 0. Properties of
* equal order are sorted alphabetically.</dd>
* <dt>tags: String[]</dt>
* <dd>List of values to be offered for the property in addition to those
* offered by its property editor.</dd>
* <dt>notUndefined: Boolean</dt>
* <dd>If true, the property should not be left undefined. A <b>default</b>
* attribute must be provided if this is set.</dd>
* <dd>notExpression: Boolean</dd>
* <dd>If true, the property content should always be constant: JMeter
* 'expressions' (strings using ${var}, etc...) can't be used.</dt>
* <dd>notOther: Boolean</dd>
* <dd>If true, the property content must always be one of the tags values or
* null.</dt>
* <dt>default: Object</dt>
* <dd>Initial value for the property's GUI. Must be provided and be non-null
* if <b>notUndefined</b> is set. Must be one of the provided tags (or null) if
* <b>notOther</b> is set.
* </dl>
* <p>
* The following BeanDescriptor attributes are also understood:
* <dl>
* <dt>group.<i>group</i>.order: Integer</dt>
* <dd>where <b><i>group</i></b> is a group name used in a <b>group</b>
* attribute in one or more PropertyDescriptors. Defines the order in which the
* group will be shown in the GUI. A smaller integer means higher up in the GUI.
* The default order is 0. Groups of equal order are sorted alphabetically.</dd>
* <dt>resourceBundle: ResourceBundle</dt>
* <dd>A resource bundle to be used for GUI localization: group display names
* will be obtained from property "<b><i>group</i>.displayName</b>" if
* available (where <b><i>group</i></b> is the group name).
* </dl>
*
* @author <a href="mailto:jsalvata@apache.org">Jordi Salvat i Alabart</a>
*/
public class GenericTestBeanCustomizer extends JPanel implements SharedCustomizer {
private static final Logger log = LoggingManager.getLoggerForClass();
public static final String GROUP = "group"; //$NON-NLS-1$
public static final String ORDER = "order"; //$NON-NLS-1$
public static final String TAGS = "tags"; //$NON-NLS-1$
public static final String NOT_UNDEFINED = "notUndefined"; //$NON-NLS-1$
public static final String NOT_EXPRESSION = "notExpression"; //$NON-NLS-1$
public static final String NOT_OTHER = "notOther"; //$NON-NLS-1$
public static final String DEFAULT = "default"; //$NON-NLS-1$
public static final String RESOURCE_BUNDLE = "resourceBundle"; //$NON-NLS-1$
public static final String ORDER(String group) {
return "group." + group + ".order";
}
public static final String DEFAULT_GROUP = "";
private int scrollerCount = 0;
/**
* BeanInfo object for the class of the objects being edited.
*/
private transient BeanInfo beanInfo;
/**
* Property descriptors from the beanInfo.
*/
private transient PropertyDescriptor[] descriptors;
/**
* Property editors -- or null if the property can't be edited. Unused if
* customizerClass==null.
*/
private transient PropertyEditor[] editors;
/**
* Message format for property field labels:
*/
private MessageFormat propertyFieldLabelMessage;
/**
* Message format for property tooltips:
*/
private MessageFormat propertyToolTipMessage;
/**
* The Map we're currently customizing. Set by setObject().
*/
private Map propertyMap;
public GenericTestBeanCustomizer(){
log.warn("Constructor only intended for use in testing"); // $NON-NLS-1$
}
/**
* Create a customizer for a given test bean type.
*
* @param testBeanClass
* a subclass of TestBean
* @see org.apache.jmeter.testbeans.TestBean
*/
GenericTestBeanCustomizer(BeanInfo beanInfo) {
super();
this.beanInfo = beanInfo;
// Get and sort the property descriptors:
descriptors = beanInfo.getPropertyDescriptors();
Arrays.sort(descriptors, new PropertyComparator());
// Obtain the propertyEditors:
editors = new PropertyEditor[descriptors.length];
for (int i = 0; i < descriptors.length; i++) {
String name = descriptors[i].getName();
// Don't get editors for hidden or non-read-write properties:
if (descriptors[i].isHidden() || (descriptors[i].isExpert() && !JMeterUtils.isExpertMode())
|| descriptors[i].getReadMethod() == null || descriptors[i].getWriteMethod() == null) {
log.debug("No editor for property " + name);
editors[i] = null;
continue;
}
PropertyEditor propertyEditor;
Class editorClass = descriptors[i].getPropertyEditorClass();
if (log.isDebugEnabled()) {
log.debug("Property " + name + " has editor class " + editorClass);
}
if (editorClass != null) {
try {
propertyEditor = (PropertyEditor) editorClass.newInstance();
} catch (InstantiationException e) {
log.error("Can't create property editor.", e);
throw new Error(e.toString());
} catch (IllegalAccessException e) {
log.error("Can't create property editor.", e);
throw new Error(e.toString());
}
} else {
Class c = descriptors[i].getPropertyType();
propertyEditor = PropertyEditorManager.findEditor(c);
}
if (log.isDebugEnabled()) {
log.debug("Property " + name + " has property editor " + propertyEditor);
}
if (propertyEditor == null) {
log.debug("No editor for property " + name);
editors[i] = null;
continue;
}
if (!propertyEditor.supportsCustomEditor()) {
propertyEditor = createWrapperEditor(propertyEditor, descriptors[i]);
if (log.isDebugEnabled()) {
log.debug("Editor for property " + name + " is wrapped in " + propertyEditor);
}
}
if (propertyEditor.getCustomEditor() instanceof JScrollPane) {
scrollerCount++;
}
editors[i] = propertyEditor;
// Initialize the editor with the provided default value or null:
setEditorValue(i, descriptors[i].getValue(DEFAULT));
}
// Obtain message formats:
propertyFieldLabelMessage = new MessageFormat(JMeterUtils.getResString("property_as_field_label")); //$NON-NLS-1$
propertyToolTipMessage = new MessageFormat(JMeterUtils.getResString("property_tool_tip")); //$NON-NLS-1$
// Initialize the GUI:
init();
}
/**
* Find the default typeEditor and a suitable guiEditor for the given
* property descriptor, and combine them in a WrapperEditor.
*
* @param typeEditor
* @param descriptor
* @return
*/
private WrapperEditor createWrapperEditor(PropertyEditor typeEditor, PropertyDescriptor descriptor) {
String[] editorTags = typeEditor.getTags();
String[] additionalTags = (String[]) descriptor.getValue(TAGS);
String[] tags = null;
if (editorTags == null)
tags = additionalTags;
else if (additionalTags == null)
tags = editorTags;
else {
tags = new String[editorTags.length + additionalTags.length];
int j = 0;
for (int i = 0; i < editorTags.length; i++)
tags[j++] = editorTags[i];
for (int i = 0; i < additionalTags.length; i++)
tags[j++] = additionalTags[i];
}
boolean notNull = Boolean.TRUE.equals(descriptor.getValue(NOT_UNDEFINED));
boolean notExpression = Boolean.TRUE.equals(descriptor.getValue(NOT_EXPRESSION));
boolean notOther = Boolean.TRUE.equals(descriptor.getValue(NOT_OTHER));
PropertyEditor guiEditor;
if (notNull && tags == null) {
guiEditor = new FieldStringEditor();
} else {
ComboStringEditor e = new ComboStringEditor();
e.setNoUndefined(notNull);
e.setNoEdit(notExpression && notOther);
e.setTags(tags);
guiEditor = e;
}
WrapperEditor wrapper = new WrapperEditor(typeEditor, guiEditor, !notNull, // acceptsNull
!notExpression, // acceptsExpressions
!notOther, // acceptsOther
descriptor.getValue(DEFAULT));
return wrapper;
}
/**
* Set the value of the i-th property, properly reporting a possible
* failure.
*
* @param i
* the index of the property in the descriptors and editors
* arrays
* @param value
* the value to be stored in the editor
*
* @throws IllegalArgumentException
* if the editor refuses the value
*/
private void setEditorValue(int i, Object value) throws IllegalArgumentException {
editors[i].setValue(value);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?