blob: 02a284bd980565f7fd6f6798ce652fbc7ac805d0 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 */
23
24/*
25 * @test
26 * @bug 4682386
27 * @summary Tests for PropertyChangeSupport refactoring
28 * @author Mark Davidson
29 */
30
31import java.beans.Beans;
32import java.beans.IntrospectionException;
33import java.beans.Introspector;
34import java.beans.PropertyChangeEvent;
35import java.beans.PropertyChangeListener;
36import java.beans.PropertyChangeSupport;
37import java.beans.PropertyDescriptor;
38
39import java.lang.reflect.Method;
40
41import javax.swing.JApplet;
42import javax.swing.JButton;
43import javax.swing.JCheckBox;
44import javax.swing.JComboBox;
45import javax.swing.JComponent;
46import javax.swing.JLabel;
47import javax.swing.JList;
48import javax.swing.JMenuItem;
49import javax.swing.JProgressBar;
50import javax.swing.JTextArea;
51import javax.swing.JTextPane;
52import javax.swing.JTextField;
53import javax.swing.JToolBar;
54import javax.swing.JTabbedPane;
55import javax.swing.JTree;
56import javax.swing.JTable;
57
58/**
59 * This class tests the multi-threaded access to PropertyChangeSupport and
60 * will also use reflection to test propertyChanges on Swing components.
61 * <p/>
62 * There is no new functionality from the implementation of this RFE.
63 * Semantically, it should be equivalent.
64 */
65public class Test4682386 {
66 private static final String FOO = "foo";
67 private static final String BAR = "bar";
68
69 private static final int NUM_LISTENERS = 100;
70 private static final boolean DEBUG = true;
71
72 private static final Class[] TYPES = {
73 JApplet.class,
74 JButton.class,
75 JCheckBox.class,
76 JComboBox.class,
77 JLabel.class,
78 JList.class,
79 JMenuItem.class,
80 JProgressBar.class,
81 JTextArea.class,
82 JTextPane.class,
83 JTextField.class,
84 JToolBar.class,
85 JTabbedPane.class,
86 JTree.class,
87 JTable.class,
88 };
89
90 public static void main(String[] args) {
91 testSwingProperties();
92
93 // tests the multi-threaded access
94
95 TestBean bean = new TestBean();
96
97 Thread add = new Thread(new AddThread(bean));
98 Thread remove = new Thread(new RemoveThread(bean));
99 Thread prop = new Thread(new PropertyThread(bean));
100
101 add.start();
102 prop.start();
103 remove.start();
104 }
105
106 /**
107 * Should be exectuted with $JAVA_HOME/lib/dt.jar in the classpath
108 * so that there will be a lot more bound properties.
109 * <p/>
110 * This test isn't really appropriate for automated testing.
111 */
112 private static void testSwingProperties() {
113 long start = System.currentTimeMillis();
114 for (Class type : TYPES) {
115 try {
116 Object bean = Beans.instantiate(type.getClassLoader(), type.getName());
117
118 JComponent comp = (JComponent) bean;
119 for (int k = 0; k < NUM_LISTENERS; k++) {
120 comp.addPropertyChangeListener(new PropertyListener());
121 }
122
123 for (PropertyDescriptor pd : getPropertyDescriptors(type)) {
124 if (pd.isBound()) {
125 if (DEBUG) {
126 System.out.println("Bound property found: " + pd.getName());
127 }
128
129 Method read = pd.getReadMethod();
130 Method write = pd.getWriteMethod();
131 try {
132 write.invoke(
133 bean,
134 getValue(
135 pd.getPropertyType(),
136 read.invoke(bean)));
137 } catch (Exception ex) {
138 // do nothing - just move on.
139 if (DEBUG) {
140 System.out.println("Reflective method invocation Exception for " + type + " : " + ex.getMessage());
141 }
142 }
143 }
144 }
145 } catch (Exception ex) {
146 // do nothing - just move on.
147 if (DEBUG) {
148 System.out.println("Exception for " + type.getName() +
149 " : " + ex.getMessage());
150 }
151 }
152 }
153 System.out.println("Exec time (ms): " + (System.currentTimeMillis() - start));
154 }
155
156 /**
157 * Gets a fake value from a type and old value;
158 */
159 public static Object getValue(Class type, Object value) {
160 if (String.class.equals(type)) {
161 return "test string";
162 }
163 if (value instanceof Integer) {
164 Integer i = (Integer) value;
165 return Integer.valueOf(i + 1);
166 }
167 if (value instanceof Boolean) {
168 Boolean b = (Boolean) value;
169 return Boolean.valueOf(!b);
170 }
171 return null;
172 }
173
174 public static PropertyDescriptor[] getPropertyDescriptors(Class type) {
175 try {
176 return Introspector.getBeanInfo(type).getPropertyDescriptors();
177 } catch (IntrospectionException exception) {
178 throw new Error("unexpected exception", exception);
179 }
180 }
181
182 private static void sleep(long ms) {
183 try {
184 Thread.sleep(ms);
185 } catch (InterruptedException exception) {
186 }
187 }
188
189 private static class AddThread implements Runnable {
190 private final TestBean bean;
191
192 AddThread(TestBean bean) {
193 this.bean = bean;
194 }
195
196 public void run() {
197 for (int i = 0; i < NUM_LISTENERS; i++) {
198 for (int j = 0; j < 10; j++) {
199 this.bean.addPropertyChangeListener(new PropertyListener());
200 }
201 if (DEBUG) {
202 System.out.println("10 listeners added");
203 }
204 sleep(25L);
205 }
206 }
207 }
208
209 private static class RemoveThread implements Runnable {
210 private final TestBean bean;
211
212 RemoveThread(TestBean bean) {
213 this.bean = bean;
214 }
215
216 public void run() {
217 for (int k = 0; k < NUM_LISTENERS; k++) {
218 sleep(100L);
219 PropertyChangeListener[] listeners = this.bean.getPropertyChangeListners();
220 for (int i = listeners.length - 1; i >= 0; i--) {
221 this.bean.removePropertyChangeListener(listeners[i]);
222 }
223 if (DEBUG) {
224 System.out.println(listeners.length + " listeners removed");
225 }
226 }
227 }
228 }
229
230 private static class PropertyThread implements Runnable {
231 private final TestBean bean;
232
233 PropertyThread(TestBean bean) {
234 this.bean = bean;
235 }
236
237 public void run() {
238 for (int i = 0; i < NUM_LISTENERS; i++) {
239 boolean flag = this.bean.isFoo();
240 this.bean.setFoo(!flag);
241 this.bean.setBar(Boolean.toString(flag));
242 if (DEBUG) {
243 System.out.println("Executed property changes");
244 }
245 sleep(40L);
246 }
247 }
248 }
249
250 /**
251 * Handler for the property change events.
252 */
253 private static class PropertyListener implements PropertyChangeListener {
254 public void propertyChange(PropertyChangeEvent event) {
255 // blank since this should execute as fast as possible.
256 }
257 }
258
259 /**
260 * A simple bean to test multi-threaded acccess to the listeners.
261 */
262 public static class TestBean {
263 private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
264 private boolean foo;
265 private String bar;
266
267 public void addPropertyChangeListener(PropertyChangeListener listener) {
268 this.pcs.addPropertyChangeListener(listener);
269 }
270
271 public void removePropertyChangeListener(PropertyChangeListener listener) {
272 this.pcs.removePropertyChangeListener(listener);
273 }
274
275 public PropertyChangeListener[] getPropertyChangeListners() {
276 return this.pcs.getPropertyChangeListeners();
277 }
278
279 public boolean isFoo() {
280 return this.foo;
281 }
282
283 public void setFoo(boolean foo) {
284 boolean old = this.foo;
285 this.foo = foo;
286 this.pcs.firePropertyChange(FOO, old, foo);
287 }
288
289 public String getBar() {
290 return this.bar;
291 }
292
293 public void setBar(String bar) {
294 String old = this.bar;
295 this.bar = bar;
296 this.pcs.firePropertyChange(BAR, old, bar);
297 }
298 }
299}