You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
299 lines
9.5 KiB
299 lines
9.5 KiB
/* |
|
* Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. |
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
* |
|
* This code is free software; you can redistribute it and/or modify it |
|
* under the terms of the GNU General Public License version 2 only, as |
|
* published by the Free Software Foundation. |
|
* |
|
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
* version 2 for more details (a copy is included in the LICENSE file that |
|
* accompanied this code). |
|
* |
|
* You should have received a copy of the GNU General Public License version |
|
* 2 along with this work; if not, write to the Free Software Foundation, |
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
* |
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
* or visit www.oracle.com if you need additional information or have any |
|
* questions. |
|
*/ |
|
|
|
/* |
|
* @test |
|
* @bug 4682386 |
|
* @summary Tests for PropertyChangeSupport refactoring |
|
* @author Mark Davidson |
|
*/ |
|
|
|
import java.beans.Beans; |
|
import java.beans.IntrospectionException; |
|
import java.beans.Introspector; |
|
import java.beans.PropertyChangeEvent; |
|
import java.beans.PropertyChangeListener; |
|
import java.beans.PropertyChangeSupport; |
|
import java.beans.PropertyDescriptor; |
|
|
|
import java.lang.reflect.Method; |
|
|
|
import javax.swing.JApplet; |
|
import javax.swing.JButton; |
|
import javax.swing.JCheckBox; |
|
import javax.swing.JComboBox; |
|
import javax.swing.JComponent; |
|
import javax.swing.JLabel; |
|
import javax.swing.JList; |
|
import javax.swing.JMenuItem; |
|
import javax.swing.JProgressBar; |
|
import javax.swing.JTextArea; |
|
import javax.swing.JTextPane; |
|
import javax.swing.JTextField; |
|
import javax.swing.JToolBar; |
|
import javax.swing.JTabbedPane; |
|
import javax.swing.JTree; |
|
import javax.swing.JTable; |
|
|
|
/** |
|
* This class tests the multi-threaded access to PropertyChangeSupport and |
|
* will also use reflection to test propertyChanges on Swing components. |
|
* <p/> |
|
* There is no new functionality from the implementation of this RFE. |
|
* Semantically, it should be equivalent. |
|
*/ |
|
public class Test4682386 { |
|
private static final String FOO = "foo"; |
|
private static final String BAR = "bar"; |
|
|
|
private static final int NUM_LISTENERS = 100; |
|
private static final boolean DEBUG = true; |
|
|
|
private static final Class[] TYPES = { |
|
JApplet.class, |
|
JButton.class, |
|
JCheckBox.class, |
|
JComboBox.class, |
|
JLabel.class, |
|
JList.class, |
|
JMenuItem.class, |
|
JProgressBar.class, |
|
JTextArea.class, |
|
JTextPane.class, |
|
JTextField.class, |
|
JToolBar.class, |
|
JTabbedPane.class, |
|
JTree.class, |
|
JTable.class, |
|
}; |
|
|
|
public static void main(String[] args) { |
|
testSwingProperties(); |
|
|
|
// tests the multi-threaded access |
|
|
|
TestBean bean = new TestBean(); |
|
|
|
Thread add = new Thread(new AddThread(bean)); |
|
Thread remove = new Thread(new RemoveThread(bean)); |
|
Thread prop = new Thread(new PropertyThread(bean)); |
|
|
|
add.start(); |
|
prop.start(); |
|
remove.start(); |
|
} |
|
|
|
/** |
|
* Should be exectuted with $JAVA_HOME/lib/dt.jar in the classpath |
|
* so that there will be a lot more bound properties. |
|
* <p/> |
|
* This test isn't really appropriate for automated testing. |
|
*/ |
|
private static void testSwingProperties() { |
|
long start = System.currentTimeMillis(); |
|
for (Class type : TYPES) { |
|
try { |
|
Object bean = Beans.instantiate(type.getClassLoader(), type.getName()); |
|
|
|
JComponent comp = (JComponent) bean; |
|
for (int k = 0; k < NUM_LISTENERS; k++) { |
|
comp.addPropertyChangeListener(new PropertyListener()); |
|
} |
|
|
|
for (PropertyDescriptor pd : getPropertyDescriptors(type)) { |
|
if (pd.isBound()) { |
|
if (DEBUG) { |
|
System.out.println("Bound property found: " + pd.getName()); |
|
} |
|
|
|
Method read = pd.getReadMethod(); |
|
Method write = pd.getWriteMethod(); |
|
try { |
|
write.invoke( |
|
bean, |
|
getValue( |
|
pd.getPropertyType(), |
|
read.invoke(bean))); |
|
} catch (Exception ex) { |
|
// do nothing - just move on. |
|
if (DEBUG) { |
|
System.out.println("Reflective method invocation Exception for " + type + " : " + ex.getMessage()); |
|
} |
|
} |
|
} |
|
} |
|
} catch (Exception ex) { |
|
// do nothing - just move on. |
|
if (DEBUG) { |
|
System.out.println("Exception for " + type.getName() + |
|
" : " + ex.getMessage()); |
|
} |
|
} |
|
} |
|
System.out.println("Exec time (ms): " + (System.currentTimeMillis() - start)); |
|
} |
|
|
|
/** |
|
* Gets a fake value from a type and old value; |
|
*/ |
|
public static Object getValue(Class type, Object value) { |
|
if (String.class.equals(type)) { |
|
return "test string"; |
|
} |
|
if (value instanceof Integer) { |
|
Integer i = (Integer) value; |
|
return Integer.valueOf(i + 1); |
|
} |
|
if (value instanceof Boolean) { |
|
Boolean b = (Boolean) value; |
|
return Boolean.valueOf(!b); |
|
} |
|
return null; |
|
} |
|
|
|
public static PropertyDescriptor[] getPropertyDescriptors(Class type) { |
|
try { |
|
return Introspector.getBeanInfo(type).getPropertyDescriptors(); |
|
} catch (IntrospectionException exception) { |
|
throw new Error("unexpected exception", exception); |
|
} |
|
} |
|
|
|
private static void sleep(long ms) { |
|
try { |
|
Thread.sleep(ms); |
|
} catch (InterruptedException exception) { |
|
} |
|
} |
|
|
|
private static class AddThread implements Runnable { |
|
private final TestBean bean; |
|
|
|
AddThread(TestBean bean) { |
|
this.bean = bean; |
|
} |
|
|
|
public void run() { |
|
for (int i = 0; i < NUM_LISTENERS; i++) { |
|
for (int j = 0; j < 10; j++) { |
|
this.bean.addPropertyChangeListener(new PropertyListener()); |
|
} |
|
if (DEBUG) { |
|
System.out.println("10 listeners added"); |
|
} |
|
sleep(25L); |
|
} |
|
} |
|
} |
|
|
|
private static class RemoveThread implements Runnable { |
|
private final TestBean bean; |
|
|
|
RemoveThread(TestBean bean) { |
|
this.bean = bean; |
|
} |
|
|
|
public void run() { |
|
for (int k = 0; k < NUM_LISTENERS; k++) { |
|
sleep(100L); |
|
PropertyChangeListener[] listeners = this.bean.getPropertyChangeListners(); |
|
for (int i = listeners.length - 1; i >= 0; i--) { |
|
this.bean.removePropertyChangeListener(listeners[i]); |
|
} |
|
if (DEBUG) { |
|
System.out.println(listeners.length + " listeners removed"); |
|
} |
|
} |
|
} |
|
} |
|
|
|
private static class PropertyThread implements Runnable { |
|
private final TestBean bean; |
|
|
|
PropertyThread(TestBean bean) { |
|
this.bean = bean; |
|
} |
|
|
|
public void run() { |
|
for (int i = 0; i < NUM_LISTENERS; i++) { |
|
boolean flag = this.bean.isFoo(); |
|
this.bean.setFoo(!flag); |
|
this.bean.setBar(Boolean.toString(flag)); |
|
if (DEBUG) { |
|
System.out.println("Executed property changes"); |
|
} |
|
sleep(40L); |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* Handler for the property change events. |
|
*/ |
|
private static class PropertyListener implements PropertyChangeListener { |
|
public void propertyChange(PropertyChangeEvent event) { |
|
// blank since this should execute as fast as possible. |
|
} |
|
} |
|
|
|
/** |
|
* A simple bean to test multi-threaded acccess to the listeners. |
|
*/ |
|
public static class TestBean { |
|
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); |
|
private boolean foo; |
|
private String bar; |
|
|
|
public void addPropertyChangeListener(PropertyChangeListener listener) { |
|
this.pcs.addPropertyChangeListener(listener); |
|
} |
|
|
|
public void removePropertyChangeListener(PropertyChangeListener listener) { |
|
this.pcs.removePropertyChangeListener(listener); |
|
} |
|
|
|
public PropertyChangeListener[] getPropertyChangeListners() { |
|
return this.pcs.getPropertyChangeListeners(); |
|
} |
|
|
|
public boolean isFoo() { |
|
return this.foo; |
|
} |
|
|
|
public void setFoo(boolean foo) { |
|
boolean old = this.foo; |
|
this.foo = foo; |
|
this.pcs.firePropertyChange(FOO, old, foo); |
|
} |
|
|
|
public String getBar() { |
|
return this.bar; |
|
} |
|
|
|
public void setBar(String bar) { |
|
String old = this.bar; |
|
this.bar = bar; |
|
this.pcs.firePropertyChange(BAR, old, bar); |
|
} |
|
} |
|
}
|
|
|