blob: 4771bb7d3c140880d50177ea1afad58730262a1b [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25package java.beans;
26
27import java.awt.AWTKeyStroke;
28import java.awt.BorderLayout;
29import java.awt.Dimension;
30import java.awt.Color;
31import java.awt.Font;
32import java.awt.GridBagConstraints;
33import java.awt.Insets;
34import java.awt.Point;
35import java.awt.Rectangle;
36import java.awt.event.KeyEvent;
37import java.awt.font.TextAttribute;
38
39import java.lang.reflect.Array;
40import java.lang.reflect.Constructor;
41import java.lang.reflect.Field;
42import java.lang.reflect.Method;
43
44import java.security.AccessController;
45import java.security.PrivilegedAction;
46
47import java.sql.Timestamp;
48
49import java.util.*;
50
51import javax.swing.Box;
52import javax.swing.JLayeredPane;
53import javax.swing.border.MatteBorder;
54import javax.swing.plaf.ColorUIResource;
55
56import sun.swing.PrintColorUIResource;
57
58/*
59 * Like the <code>Intropector</code>, the <code>MetaData</code> class
60 * contains <em>meta</em> objects that describe the way
61 * classes should express their state in terms of their
62 * own public APIs.
63 *
64 * @see java.beans.Intropector
65 *
66 * @author Philip Milne
67 * @author Steve Langley
68 */
69
70class NullPersistenceDelegate extends PersistenceDelegate {
71 // Note this will be called by all classes when they reach the
72 // top of their superclass chain.
73 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
74 }
75 protected Expression instantiate(Object oldInstance, Encoder out) { return null; }
76
77 public void writeObject(Object oldInstance, Encoder out) {
78 // System.out.println("NullPersistenceDelegate:writeObject " + oldInstance);
79 }
80}
81
82/**
83 * The persistence delegate for <CODE>enum</CODE> classes.
84 *
85 * @author Sergey A. Malenkov
86 */
87class EnumPersistenceDelegate extends PersistenceDelegate {
88 protected boolean mutatesTo(Object oldInstance, Object newInstance) {
89 return oldInstance == newInstance;
90 }
91
92 protected Expression instantiate(Object oldInstance, Encoder out) {
93 Enum e = (Enum) oldInstance;
94 return new Expression(e, Enum.class, "valueOf", new Object[]{e.getClass(), e.name()});
95 }
96}
97
98class PrimitivePersistenceDelegate extends PersistenceDelegate {
99 protected boolean mutatesTo(Object oldInstance, Object newInstance) {
100 return oldInstance.equals(newInstance);
101 }
102
103 protected Expression instantiate(Object oldInstance, Encoder out) {
104 return new Expression(oldInstance, oldInstance.getClass(),
105 "new", new Object[]{oldInstance.toString()});
106 }
107}
108
109class ArrayPersistenceDelegate extends PersistenceDelegate {
110 protected boolean mutatesTo(Object oldInstance, Object newInstance) {
111 return (newInstance != null &&
112 oldInstance.getClass() == newInstance.getClass() && // Also ensures the subtype is correct.
113 Array.getLength(oldInstance) == Array.getLength(newInstance));
114 }
115
116 protected Expression instantiate(Object oldInstance, Encoder out) {
117 // System.out.println("instantiate: " + type + " " + oldInstance);
118 Class oldClass = oldInstance.getClass();
119 return new Expression(oldInstance, Array.class, "newInstance",
120 new Object[]{oldClass.getComponentType(),
121 new Integer(Array.getLength(oldInstance))});
122 }
123
124 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
125 int n = Array.getLength(oldInstance);
126 for (int i = 0; i < n; i++) {
127 Object index = new Integer(i);
128 // Expression oldGetExp = new Expression(Array.class, "get", new Object[]{oldInstance, index});
129 // Expression newGetExp = new Expression(Array.class, "get", new Object[]{newInstance, index});
130 Expression oldGetExp = new Expression(oldInstance, "get", new Object[]{index});
131 Expression newGetExp = new Expression(newInstance, "get", new Object[]{index});
132 try {
133 Object oldValue = oldGetExp.getValue();
134 Object newValue = newGetExp.getValue();
135 out.writeExpression(oldGetExp);
136 if (!MetaData.equals(newValue, out.get(oldValue))) {
137 // System.out.println("Not equal: " + newGetExp + " != " + actualGetExp);
138 // invokeStatement(Array.class, "set", new Object[]{oldInstance, index, oldValue}, out);
139 DefaultPersistenceDelegate.invokeStatement(oldInstance, "set", new Object[]{index, oldValue}, out);
140 }
141 }
142 catch (Exception e) {
143 // System.err.println("Warning:: failed to write: " + oldGetExp);
144 out.getExceptionListener().exceptionThrown(e);
145 }
146 }
147 }
148}
149
150class ProxyPersistenceDelegate extends PersistenceDelegate {
151 protected Expression instantiate(Object oldInstance, Encoder out) {
152 Class type = oldInstance.getClass();
153 java.lang.reflect.Proxy p = (java.lang.reflect.Proxy)oldInstance;
154 // This unappealing hack is not required but makes the
155 // representation of EventHandlers much more concise.
156 java.lang.reflect.InvocationHandler ih = java.lang.reflect.Proxy.getInvocationHandler(p);
157 if (ih instanceof EventHandler) {
158 EventHandler eh = (EventHandler)ih;
159 Vector args = new Vector();
160 args.add(type.getInterfaces()[0]);
161 args.add(eh.getTarget());
162 args.add(eh.getAction());
163 if (eh.getEventPropertyName() != null) {
164 args.add(eh.getEventPropertyName());
165 }
166 if (eh.getListenerMethodName() != null) {
167 args.setSize(4);
168 args.add(eh.getListenerMethodName());
169 }
170 return new Expression(oldInstance,
171 EventHandler.class,
172 "create",
173 args.toArray());
174 }
175 return new Expression(oldInstance,
176 java.lang.reflect.Proxy.class,
177 "newProxyInstance",
178 new Object[]{type.getClassLoader(),
179 type.getInterfaces(),
180 ih});
181 }
182}
183
184// Strings
185class java_lang_String_PersistenceDelegate extends PersistenceDelegate {
186 protected Expression instantiate(Object oldInstance, Encoder out) { return null; }
187
188 public void writeObject(Object oldInstance, Encoder out) {
189 // System.out.println("NullPersistenceDelegate:writeObject " + oldInstance);
190 }
191}
192
193// Classes
194class java_lang_Class_PersistenceDelegate extends PersistenceDelegate {
195 protected boolean mutatesTo(Object oldInstance, Object newInstance) {
196 return oldInstance.equals(newInstance);
197 }
198
199 protected Expression instantiate(Object oldInstance, Encoder out) {
200 Class c = (Class)oldInstance;
201 // As of 1.3 it is not possible to call Class.forName("int"),
202 // so we have to generate different code for primitive types.
203 // This is needed for arrays whose subtype may be primitive.
204 if (c.isPrimitive()) {
205 Field field = null;
206 try {
207 field = ReflectionUtils.typeToClass(c).getDeclaredField("TYPE");
208 } catch (NoSuchFieldException ex) {
209 System.err.println("Unknown primitive type: " + c);
210 }
211 return new Expression(oldInstance, field, "get", new Object[]{null});
212 }
213 else if (oldInstance == String.class) {
214 return new Expression(oldInstance, "", "getClass", new Object[]{});
215 }
216 else if (oldInstance == Class.class) {
217 return new Expression(oldInstance, String.class, "getClass", new Object[]{});
218 }
219 else {
220 return new Expression(oldInstance, Class.class, "forName", new Object[]{c.getName()});
221 }
222 }
223}
224
225// Fields
226class java_lang_reflect_Field_PersistenceDelegate extends PersistenceDelegate {
227 protected boolean mutatesTo(Object oldInstance, Object newInstance) {
228 return oldInstance.equals(newInstance);
229 }
230
231 protected Expression instantiate(Object oldInstance, Encoder out) {
232 Field f = (Field)oldInstance;
233 return new Expression(oldInstance,
234 f.getDeclaringClass(),
235 "getField",
236 new Object[]{f.getName()});
237 }
238}
239
240// Methods
241class java_lang_reflect_Method_PersistenceDelegate extends PersistenceDelegate {
242 protected boolean mutatesTo(Object oldInstance, Object newInstance) {
243 return oldInstance.equals(newInstance);
244 }
245
246 protected Expression instantiate(Object oldInstance, Encoder out) {
247 Method m = (Method)oldInstance;
248 return new Expression(oldInstance,
249 m.getDeclaringClass(),
250 "getMethod",
251 new Object[]{m.getName(), m.getParameterTypes()});
252 }
253}
254
255// Dates
256
257/**
258 * The persistence delegate for <CODE>java.util.Date</CODE> classes.
259 * Do not extend DefaultPersistenceDelegate to improve performance and
260 * to avoid problems with <CODE>java.sql.Date</CODE>,
261 * <CODE>java.sql.Time</CODE> and <CODE>java.sql.Timestamp</CODE>.
262 *
263 * @author Sergey A. Malenkov
264 */
265class java_util_Date_PersistenceDelegate extends PersistenceDelegate {
266 protected boolean mutatesTo(Object oldInstance, Object newInstance) {
267 if (!super.mutatesTo(oldInstance, newInstance)) {
268 return false;
269 }
270 Date oldDate = (Date)oldInstance;
271 Date newDate = (Date)newInstance;
272
273 return oldDate.getTime() == newDate.getTime();
274 }
275
276 protected Expression instantiate(Object oldInstance, Encoder out) {
277 Date date = (Date)oldInstance;
278 return new Expression(date, date.getClass(), "new", new Object[] {date.getTime()});
279 }
280}
281
282/**
283 * The persistence delegate for <CODE>java.sql.Timestamp</CODE> classes.
284 * It supports nanoseconds.
285 *
286 * @author Sergey A. Malenkov
287 */
288final class java_sql_Timestamp_PersistenceDelegate extends java_util_Date_PersistenceDelegate {
289 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
290 Timestamp oldTime = (Timestamp)oldInstance;
291 Timestamp newTime = (Timestamp)newInstance;
292
293 int nanos = oldTime.getNanos();
294 if (nanos != newTime.getNanos()) {
295 out.writeStatement(new Statement(oldTime, "setNanos", new Object[] {nanos}));
296 }
297 }
298}
299
300// Collections
301
302/*
303The Hashtable and AbstractMap classes have no common ancestor yet may
304be handled with a single persistence delegate: one which uses the methods
305of the Map insterface exclusively. Attatching the persistence delegates
306to the interfaces themselves is fraught however since, in the case of
307the Map, both the AbstractMap and HashMap classes are declared to
308implement the Map interface, leaving the obvious implementation prone
309to repeating their initialization. These issues and questions around
310the ordering of delegates attached to interfaces have lead us to
311ignore any delegates attached to interfaces and force all persistence
312delegates to be registered with concrete classes.
313*/
314
315/**
316 * The base class for persistence delegates for inner classes
317 * that can be created using {@link Collections}.
318 *
319 * @author Sergey A. Malenkov
320 */
321abstract class java_util_Collections extends PersistenceDelegate {
322 protected boolean mutatesTo(Object oldInstance, Object newInstance) {
323 if (!super.mutatesTo(oldInstance, newInstance)) {
324 return false;
325 }
326 if ((oldInstance instanceof List) || (oldInstance instanceof Set) || (oldInstance instanceof Map)) {
327 return oldInstance.equals(newInstance);
328 }
329 Collection oldC = (Collection) oldInstance;
330 Collection newC = (Collection) newInstance;
331 return (oldC.size() == newC.size()) && oldC.containsAll(newC);
332 }
333
334 static Object getPrivateField(final Object instance, final String name) {
335 return AccessController.doPrivileged(
336 new PrivilegedAction() {
337 public Object run() {
338 Class type = instance.getClass();
339 while ( true ) {
340 try {
341 Field field = type.getDeclaredField(name);
342 field.setAccessible(true);
343 return field.get( instance );
344 }
345 catch (NoSuchFieldException exception) {
346 type = type.getSuperclass();
347 if (type == null) {
348 throw new IllegalStateException("Could not find field " + name, exception);
349 }
350 }
351 catch (Exception exception) {
352 throw new IllegalStateException("Could not get value " + type.getName() + '.' + name, exception);
353 }
354 }
355 }
356 } );
357 }
358
359 static final class EmptyList_PersistenceDelegate extends java_util_Collections {
360 protected Expression instantiate(Object oldInstance, Encoder out) {
361 return new Expression(oldInstance, Collections.class, "emptyList", null);
362 }
363 }
364
365 static final class EmptySet_PersistenceDelegate extends java_util_Collections {
366 protected Expression instantiate(Object oldInstance, Encoder out) {
367 return new Expression(oldInstance, Collections.class, "emptySet", null);
368 }
369 }
370
371 static final class EmptyMap_PersistenceDelegate extends java_util_Collections {
372 protected Expression instantiate(Object oldInstance, Encoder out) {
373 return new Expression(oldInstance, Collections.class, "emptyMap", null);
374 }
375 }
376
377 static final class SingletonList_PersistenceDelegate extends java_util_Collections {
378 protected Expression instantiate(Object oldInstance, Encoder out) {
379 List list = (List) oldInstance;
380 return new Expression(oldInstance, Collections.class, "singletonList", new Object[]{list.get(0)});
381 }
382 }
383
384 static final class SingletonSet_PersistenceDelegate extends java_util_Collections {
385 protected Expression instantiate(Object oldInstance, Encoder out) {
386 Set set = (Set) oldInstance;
387 return new Expression(oldInstance, Collections.class, "singleton", new Object[]{set.iterator().next()});
388 }
389 }
390
391 static final class SingletonMap_PersistenceDelegate extends java_util_Collections {
392 protected Expression instantiate(Object oldInstance, Encoder out) {
393 Map map = (Map) oldInstance;
394 Object key = map.keySet().iterator().next();
395 return new Expression(oldInstance, Collections.class, "singletonMap", new Object[]{key, map.get(key)});
396 }
397 }
398
399 static final class UnmodifiableCollection_PersistenceDelegate extends java_util_Collections {
400 protected Expression instantiate(Object oldInstance, Encoder out) {
401 List list = new ArrayList((Collection) oldInstance);
402 return new Expression(oldInstance, Collections.class, "unmodifiableCollection", new Object[]{list});
403 }
404 }
405
406 static final class UnmodifiableList_PersistenceDelegate extends java_util_Collections {
407 protected Expression instantiate(Object oldInstance, Encoder out) {
408 List list = new LinkedList((Collection) oldInstance);
409 return new Expression(oldInstance, Collections.class, "unmodifiableList", new Object[]{list});
410 }
411 }
412
413 static final class UnmodifiableRandomAccessList_PersistenceDelegate extends java_util_Collections {
414 protected Expression instantiate(Object oldInstance, Encoder out) {
415 List list = new ArrayList((Collection) oldInstance);
416 return new Expression(oldInstance, Collections.class, "unmodifiableList", new Object[]{list});
417 }
418 }
419
420 static final class UnmodifiableSet_PersistenceDelegate extends java_util_Collections {
421 protected Expression instantiate(Object oldInstance, Encoder out) {
422 Set set = new HashSet((Set) oldInstance);
423 return new Expression(oldInstance, Collections.class, "unmodifiableSet", new Object[]{set});
424 }
425 }
426
427 static final class UnmodifiableSortedSet_PersistenceDelegate extends java_util_Collections {
428 protected Expression instantiate(Object oldInstance, Encoder out) {
429 SortedSet set = new TreeSet((SortedSet) oldInstance);
430 return new Expression(oldInstance, Collections.class, "unmodifiableSortedSet", new Object[]{set});
431 }
432 }
433
434 static final class UnmodifiableMap_PersistenceDelegate extends java_util_Collections {
435 protected Expression instantiate(Object oldInstance, Encoder out) {
436 Map map = new HashMap((Map) oldInstance);
437 return new Expression(oldInstance, Collections.class, "unmodifiableMap", new Object[]{map});
438 }
439 }
440
441 static final class UnmodifiableSortedMap_PersistenceDelegate extends java_util_Collections {
442 protected Expression instantiate(Object oldInstance, Encoder out) {
443 SortedMap map = new TreeMap((SortedMap) oldInstance);
444 return new Expression(oldInstance, Collections.class, "unmodifiableSortedMap", new Object[]{map});
445 }
446 }
447
448 static final class SynchronizedCollection_PersistenceDelegate extends java_util_Collections {
449 protected Expression instantiate(Object oldInstance, Encoder out) {
450 List list = new ArrayList((Collection) oldInstance);
451 return new Expression(oldInstance, Collections.class, "synchronizedCollection", new Object[]{list});
452 }
453 }
454
455 static final class SynchronizedList_PersistenceDelegate extends java_util_Collections {
456 protected Expression instantiate(Object oldInstance, Encoder out) {
457 List list = new LinkedList((Collection) oldInstance);
458 return new Expression(oldInstance, Collections.class, "synchronizedList", new Object[]{list});
459 }
460 }
461
462 static final class SynchronizedRandomAccessList_PersistenceDelegate extends java_util_Collections {
463 protected Expression instantiate(Object oldInstance, Encoder out) {
464 List list = new ArrayList((Collection) oldInstance);
465 return new Expression(oldInstance, Collections.class, "synchronizedList", new Object[]{list});
466 }
467 }
468
469 static final class SynchronizedSet_PersistenceDelegate extends java_util_Collections {
470 protected Expression instantiate(Object oldInstance, Encoder out) {
471 Set set = new HashSet((Set) oldInstance);
472 return new Expression(oldInstance, Collections.class, "synchronizedSet", new Object[]{set});
473 }
474 }
475
476 static final class SynchronizedSortedSet_PersistenceDelegate extends java_util_Collections {
477 protected Expression instantiate(Object oldInstance, Encoder out) {
478 SortedSet set = new TreeSet((SortedSet) oldInstance);
479 return new Expression(oldInstance, Collections.class, "synchronizedSortedSet", new Object[]{set});
480 }
481 }
482
483 static final class SynchronizedMap_PersistenceDelegate extends java_util_Collections {
484 protected Expression instantiate(Object oldInstance, Encoder out) {
485 Map map = new HashMap((Map) oldInstance);
486 return new Expression(oldInstance, Collections.class, "synchronizedMap", new Object[]{map});
487 }
488 }
489
490 static final class SynchronizedSortedMap_PersistenceDelegate extends java_util_Collections {
491 protected Expression instantiate(Object oldInstance, Encoder out) {
492 SortedMap map = new TreeMap((SortedMap) oldInstance);
493 return new Expression(oldInstance, Collections.class, "synchronizedSortedMap", new Object[]{map});
494 }
495 }
496
497 static final class CheckedCollection_PersistenceDelegate extends java_util_Collections {
498 protected Expression instantiate(Object oldInstance, Encoder out) {
499 Object type = getPrivateField(oldInstance, "type");
500 List list = new ArrayList((Collection) oldInstance);
501 return new Expression(oldInstance, Collections.class, "checkedCollection", new Object[]{list, type});
502 }
503 }
504
505 static final class CheckedList_PersistenceDelegate extends java_util_Collections {
506 protected Expression instantiate(Object oldInstance, Encoder out) {
507 Object type = getPrivateField(oldInstance, "type");
508 List list = new LinkedList((Collection) oldInstance);
509 return new Expression(oldInstance, Collections.class, "checkedList", new Object[]{list, type});
510 }
511 }
512
513 static final class CheckedRandomAccessList_PersistenceDelegate extends java_util_Collections {
514 protected Expression instantiate(Object oldInstance, Encoder out) {
515 Object type = getPrivateField(oldInstance, "type");
516 List list = new ArrayList((Collection) oldInstance);
517 return new Expression(oldInstance, Collections.class, "checkedList", new Object[]{list, type});
518 }
519 }
520
521 static final class CheckedSet_PersistenceDelegate extends java_util_Collections {
522 protected Expression instantiate(Object oldInstance, Encoder out) {
523 Object type = getPrivateField(oldInstance, "type");
524 Set set = new HashSet((Set) oldInstance);
525 return new Expression(oldInstance, Collections.class, "checkedSet", new Object[]{set, type});
526 }
527 }
528
529 static final class CheckedSortedSet_PersistenceDelegate extends java_util_Collections {
530 protected Expression instantiate(Object oldInstance, Encoder out) {
531 Object type = getPrivateField(oldInstance, "type");
532 SortedSet set = new TreeSet((SortedSet) oldInstance);
533 return new Expression(oldInstance, Collections.class, "checkedSortedSet", new Object[]{set, type});
534 }
535 }
536
537 static final class CheckedMap_PersistenceDelegate extends java_util_Collections {
538 protected Expression instantiate(Object oldInstance, Encoder out) {
539 Object keyType = getPrivateField(oldInstance, "keyType");
540 Object valueType = getPrivateField(oldInstance, "valueType");
541 Map map = new HashMap((Map) oldInstance);
542 return new Expression(oldInstance, Collections.class, "checkedMap", new Object[]{map, keyType, valueType});
543 }
544 }
545
546 static final class CheckedSortedMap_PersistenceDelegate extends java_util_Collections {
547 protected Expression instantiate(Object oldInstance, Encoder out) {
548 Object keyType = getPrivateField(oldInstance, "keyType");
549 Object valueType = getPrivateField(oldInstance, "valueType");
550 SortedMap map = new TreeMap((SortedMap) oldInstance);
551 return new Expression(oldInstance, Collections.class, "checkedSortedMap", new Object[]{map, keyType, valueType});
552 }
553 }
554}
555
556/**
557 * The persistence delegate for <CODE>java.util.EnumMap</CODE> classes.
558 *
559 * @author Sergey A. Malenkov
560 */
561class java_util_EnumMap_PersistenceDelegate extends PersistenceDelegate {
562 protected boolean mutatesTo(Object oldInstance, Object newInstance) {
563 return super.mutatesTo(oldInstance, newInstance) && (getType(oldInstance) == getType(newInstance));
564 }
565
566 protected Expression instantiate(Object oldInstance, Encoder out) {
567 return new Expression(oldInstance, EnumMap.class, "new", new Object[] {getType(oldInstance)});
568 }
569
570 private static Object getType(Object instance) {
571 return java_util_Collections.getPrivateField(instance, "keyType");
572 }
573}
574
575/**
576 * The persistence delegate for <CODE>java.util.EnumSet</CODE> classes.
577 *
578 * @author Sergey A. Malenkov
579 */
580class java_util_EnumSet_PersistenceDelegate extends PersistenceDelegate {
581 protected boolean mutatesTo(Object oldInstance, Object newInstance) {
582 return super.mutatesTo(oldInstance, newInstance) && (getType(oldInstance) == getType(newInstance));
583 }
584
585 protected Expression instantiate(Object oldInstance, Encoder out) {
586 return new Expression(oldInstance, EnumSet.class, "noneOf", new Object[] {getType(oldInstance)});
587 }
588
589 private static Object getType(Object instance) {
590 return java_util_Collections.getPrivateField(instance, "elementType");
591 }
592}
593
594// Collection
595class java_util_Collection_PersistenceDelegate extends DefaultPersistenceDelegate {
596 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
597 java.util.Collection oldO = (java.util.Collection)oldInstance;
598 java.util.Collection newO = (java.util.Collection)newInstance;
599
600 if (newO.size() != 0) {
601 invokeStatement(oldInstance, "clear", new Object[]{}, out);
602 }
603 for (Iterator i = oldO.iterator(); i.hasNext();) {
604 invokeStatement(oldInstance, "add", new Object[]{i.next()}, out);
605 }
606 }
607}
608
609// List
610class java_util_List_PersistenceDelegate extends DefaultPersistenceDelegate {
611 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
612 java.util.List oldO = (java.util.List)oldInstance;
613 java.util.List newO = (java.util.List)newInstance;
614 int oldSize = oldO.size();
615 int newSize = (newO == null) ? 0 : newO.size();
616 if (oldSize < newSize) {
617 invokeStatement(oldInstance, "clear", new Object[]{}, out);
618 newSize = 0;
619 }
620 for (int i = 0; i < newSize; i++) {
621 Object index = new Integer(i);
622
623 Expression oldGetExp = new Expression(oldInstance, "get", new Object[]{index});
624 Expression newGetExp = new Expression(newInstance, "get", new Object[]{index});
625 try {
626 Object oldValue = oldGetExp.getValue();
627 Object newValue = newGetExp.getValue();
628 out.writeExpression(oldGetExp);
629 if (!MetaData.equals(newValue, out.get(oldValue))) {
630 invokeStatement(oldInstance, "set", new Object[]{index, oldValue}, out);
631 }
632 }
633 catch (Exception e) {
634 out.getExceptionListener().exceptionThrown(e);
635 }
636 }
637 for (int i = newSize; i < oldSize; i++) {
638 invokeStatement(oldInstance, "add", new Object[]{oldO.get(i)}, out);
639 }
640 }
641}
642
643
644// Map
645class java_util_Map_PersistenceDelegate extends DefaultPersistenceDelegate {
646 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
647 // System.out.println("Initializing: " + newInstance);
648 java.util.Map oldMap = (java.util.Map)oldInstance;
649 java.util.Map newMap = (java.util.Map)newInstance;
650 // Remove the new elements.
651 // Do this first otherwise we undo the adding work.
652 if (newMap != null) {
653 for ( Object newKey : newMap.keySet() ) {
654 // PENDING: This "key" is not in the right environment.
655 if (!oldMap.containsKey(newKey)) {
656 invokeStatement(oldInstance, "remove", new Object[]{newKey}, out);
657 }
658 }
659 }
660 // Add the new elements.
661 for ( Object oldKey : oldMap.keySet() ) {
662 Expression oldGetExp = new Expression(oldInstance, "get", new Object[]{oldKey});
663 // Pending: should use newKey.
664 Expression newGetExp = new Expression(newInstance, "get", new Object[]{oldKey});
665 try {
666 Object oldValue = oldGetExp.getValue();
667 Object newValue = newGetExp.getValue();
668 out.writeExpression(oldGetExp);
669 if (!MetaData.equals(newValue, out.get(oldValue))) {
670 invokeStatement(oldInstance, "put", new Object[]{oldKey, oldValue}, out);
671 } else if ((newValue == null) && !newMap.containsKey(oldKey)) {
672 // put oldValue(=null?) if oldKey is absent in newMap
673 invokeStatement(oldInstance, "put", new Object[]{oldKey, oldValue}, out);
674 }
675 }
676 catch (Exception e) {
677 out.getExceptionListener().exceptionThrown(e);
678 }
679 }
680 }
681}
682
683class java_util_AbstractCollection_PersistenceDelegate extends java_util_Collection_PersistenceDelegate {}
684class java_util_AbstractList_PersistenceDelegate extends java_util_List_PersistenceDelegate {}
685class java_util_AbstractMap_PersistenceDelegate extends java_util_Map_PersistenceDelegate {}
686class java_util_Hashtable_PersistenceDelegate extends java_util_Map_PersistenceDelegate {}
687
688
689// Beans
690class java_beans_beancontext_BeanContextSupport_PersistenceDelegate extends java_util_Collection_PersistenceDelegate {}
691
692// AWT
693
694/**
695 * The persistence delegate for {@link Dimension}.
696 * It is impossible to use {@link DefaultPersistenceDelegate}
697 * because all getters have return types that differ from parameter types
698 * of the constructor {@link Dimension#Dimension(int, int)}.
699 *
700 * @author Sergey A. Malenkov
701 */
702final class java_awt_Dimension_PersistenceDelegate extends PersistenceDelegate {
703 protected boolean mutatesTo(Object oldInstance, Object newInstance) {
704 return oldInstance.equals(newInstance);
705 }
706
707 protected Expression instantiate(Object oldInstance, Encoder out) {
708 Dimension dimension = (Dimension) oldInstance;
709 Object[] args = new Object[] {
710 dimension.width,
711 dimension.height,
712 };
713 return new Expression(dimension, dimension.getClass(), "new", args);
714 }
715}
716
717/**
718 * The persistence delegate for {@link GridBagConstraints}.
719 * It is impossible to use {@link DefaultPersistenceDelegate}
720 * because this class does not have any properties.
721 *
722 * @author Sergey A. Malenkov
723 */
724final class java_awt_GridBagConstraints_PersistenceDelegate extends PersistenceDelegate {
725 protected Expression instantiate(Object oldInstance, Encoder out) {
726 GridBagConstraints gbc = (GridBagConstraints) oldInstance;
727 Object[] args = new Object[] {
728 gbc.gridx,
729 gbc.gridy,
730 gbc.gridwidth,
731 gbc.gridheight,
732 gbc.weightx,
733 gbc.weighty,
734 gbc.anchor,
735 gbc.fill,
736 gbc.insets,
737 gbc.ipadx,
738 gbc.ipady,
739 };
740 return new Expression(gbc, gbc.getClass(), "new", args);
741 }
742}
743
744/**
745 * The persistence delegate for {@link Insets}.
746 * It is impossible to use {@link DefaultPersistenceDelegate}
747 * because this class does not have any properties.
748 *
749 * @author Sergey A. Malenkov
750 */
751final class java_awt_Insets_PersistenceDelegate extends PersistenceDelegate {
752 protected boolean mutatesTo(Object oldInstance, Object newInstance) {
753 return oldInstance.equals(newInstance);
754 }
755
756 protected Expression instantiate(Object oldInstance, Encoder out) {
757 Insets insets = (Insets) oldInstance;
758 Object[] args = new Object[] {
759 insets.top,
760 insets.left,
761 insets.bottom,
762 insets.right,
763 };
764 return new Expression(insets, insets.getClass(), "new", args);
765 }
766}
767
768/**
769 * The persistence delegate for {@link Point}.
770 * It is impossible to use {@link DefaultPersistenceDelegate}
771 * because all getters have return types that differ from parameter types
772 * of the constructor {@link Point#Point(int, int)}.
773 *
774 * @author Sergey A. Malenkov
775 */
776final class java_awt_Point_PersistenceDelegate extends PersistenceDelegate {
777 protected boolean mutatesTo(Object oldInstance, Object newInstance) {
778 return oldInstance.equals(newInstance);
779 }
780
781 protected Expression instantiate(Object oldInstance, Encoder out) {
782 Point point = (Point) oldInstance;
783 Object[] args = new Object[] {
784 point.x,
785 point.y,
786 };
787 return new Expression(point, point.getClass(), "new", args);
788 }
789}
790
791/**
792 * The persistence delegate for {@link Rectangle}.
793 * It is impossible to use {@link DefaultPersistenceDelegate}
794 * because all getters have return types that differ from parameter types
795 * of the constructor {@link Rectangle#Rectangle(int, int, int, int)}.
796 *
797 * @author Sergey A. Malenkov
798 */
799final class java_awt_Rectangle_PersistenceDelegate extends PersistenceDelegate {
800 protected boolean mutatesTo(Object oldInstance, Object newInstance) {
801 return oldInstance.equals(newInstance);
802 }
803
804 protected Expression instantiate(Object oldInstance, Encoder out) {
805 Rectangle rectangle = (Rectangle) oldInstance;
806 Object[] args = new Object[] {
807 rectangle.x,
808 rectangle.y,
809 rectangle.width,
810 rectangle.height,
811 };
812 return new Expression(rectangle, rectangle.getClass(), "new", args);
813 }
814}
815
816/**
817 * The persistence delegate for {@link Font}.
818 * It is impossible to use {@link DefaultPersistenceDelegate}
819 * because size of the font can be float value.
820 *
821 * @author Sergey A. Malenkov
822 */
823final class java_awt_Font_PersistenceDelegate extends PersistenceDelegate {
824 protected boolean mutatesTo(Object oldInstance, Object newInstance) {
825 return oldInstance.equals(newInstance);
826 }
827
828 protected Expression instantiate(Object oldInstance, Encoder out) {
829 Font font = (Font) oldInstance;
830
831 int count = 0;
832 String family = null;
833 int style = Font.PLAIN;
834 int size = 12;
835
836 Map basic = font.getAttributes();
837 Map clone = new HashMap(basic.size());
838 for (Object key : basic.keySet()) {
839 Object value = basic.get(key);
840 if (value != null) {
841 clone.put(key, value);
842 }
843 if (key == TextAttribute.FAMILY) {
844 if (value instanceof String) {
845 count++;
846 family = (String) value;
847 }
848 }
849 else if (key == TextAttribute.WEIGHT) {
850 if (TextAttribute.WEIGHT_REGULAR.equals(value)) {
851 count++;
852 } else if (TextAttribute.WEIGHT_BOLD.equals(value)) {
853 count++;
854 style |= Font.BOLD;
855 }
856 }
857 else if (key == TextAttribute.POSTURE) {
858 if (TextAttribute.POSTURE_REGULAR.equals(value)) {
859 count++;
860 } else if (TextAttribute.POSTURE_OBLIQUE.equals(value)) {
861 count++;
862 style |= Font.ITALIC;
863 }
864 } else if (key == TextAttribute.SIZE) {
865 if (value instanceof Number) {
866 Number number = (Number) value;
867 size = number.intValue();
868 if (size == number.floatValue()) {
869 count++;
870 }
871 }
872 }
873 }
874 Class type = font.getClass();
875 if (count == clone.size()) {
876 return new Expression(font, type, "new", new Object[]{family, style, size});
877 }
878 if (type == Font.class) {
879 return new Expression(font, type, "getFont", new Object[]{clone});
880 }
881 return new Expression(font, type, "new", new Object[]{Font.getFont(clone)});
882 }
883}
884
885/**
886 * The persistence delegate for {@link AWTKeyStroke}.
887 * It is impossible to use {@link DefaultPersistenceDelegate}
888 * because this class have no public constructor.
889 *
890 * @author Sergey A. Malenkov
891 */
892final class java_awt_AWTKeyStroke_PersistenceDelegate extends PersistenceDelegate {
893 protected boolean mutatesTo(Object oldInstance, Object newInstance) {
894 return oldInstance.equals(newInstance);
895 }
896
897 protected Expression instantiate(Object oldInstance, Encoder out) {
898 AWTKeyStroke key = (AWTKeyStroke) oldInstance;
899
900 char ch = key.getKeyChar();
901 int code = key.getKeyCode();
902 int mask = key.getModifiers();
903 boolean onKeyRelease = key.isOnKeyRelease();
904
905 Object[] args = null;
906 if (ch == KeyEvent.CHAR_UNDEFINED) {
907 args = !onKeyRelease
908 ? new Object[]{code, mask}
909 : new Object[]{code, mask, onKeyRelease};
910 } else if (code == KeyEvent.VK_UNDEFINED) {
911 if (!onKeyRelease) {
912 args = (mask == 0)
913 ? new Object[]{ch}
914 : new Object[]{ch, mask};
915 } else if (mask == 0) {
916 args = new Object[]{ch, onKeyRelease};
917 }
918 }
919 if (args == null) {
920 throw new IllegalStateException("Unsupported KeyStroke: " + key);
921 }
922 Class type = key.getClass();
923 String name = type.getName();
924 // get short name of the class
925 int index = name.lastIndexOf('.') + 1;
926 if (index > 0) {
927 name = name.substring(index);
928 }
929 return new Expression( key, type, "get" + name, args );
930 }
931}
932
933class StaticFieldsPersistenceDelegate extends PersistenceDelegate {
934 protected void installFields(Encoder out, Class<?> cls) {
935 Field fields[] = cls.getFields();
936 for(int i = 0; i < fields.length; i++) {
937 Field field = fields[i];
938 // Don't install primitives, their identity will not be preserved
939 // by wrapping.
940 if (Object.class.isAssignableFrom(field.getType())) {
941 out.writeExpression(new Expression(field, "get", new Object[]{null}));
942 }
943 }
944 }
945
946 protected Expression instantiate(Object oldInstance, Encoder out) {
947 throw new RuntimeException("Unrecognized instance: " + oldInstance);
948 }
949
950 public void writeObject(Object oldInstance, Encoder out) {
951 if (out.getAttribute(this) == null) {
952 out.setAttribute(this, Boolean.TRUE);
953 installFields(out, oldInstance.getClass());
954 }
955 super.writeObject(oldInstance, out);
956 }
957}
958
959// SystemColor
960class java_awt_SystemColor_PersistenceDelegate extends StaticFieldsPersistenceDelegate {}
961
962// TextAttribute
963class java_awt_font_TextAttribute_PersistenceDelegate extends StaticFieldsPersistenceDelegate {}
964
965// MenuShortcut
966class java_awt_MenuShortcut_PersistenceDelegate extends PersistenceDelegate {
967 protected boolean mutatesTo(Object oldInstance, Object newInstance) {
968 return oldInstance.equals(newInstance);
969 }
970
971 protected Expression instantiate(Object oldInstance, Encoder out) {
972 java.awt.MenuShortcut m = (java.awt.MenuShortcut)oldInstance;
973 return new Expression(oldInstance, m.getClass(), "new",
974 new Object[]{new Integer(m.getKey()), Boolean.valueOf(m.usesShiftModifier())});
975 }
976}
977
978// Component
979class java_awt_Component_PersistenceDelegate extends DefaultPersistenceDelegate {
980 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
981 super.initialize(type, oldInstance, newInstance, out);
982 java.awt.Component c = (java.awt.Component)oldInstance;
983 java.awt.Component c2 = (java.awt.Component)newInstance;
984 // The "background", "foreground" and "font" properties.
985 // The foreground and font properties of Windows change from
986 // null to defined values after the Windows are made visible -
987 // special case them for now.
988 if (!(oldInstance instanceof java.awt.Window)) {
989 String[] fieldNames = new String[]{"background", "foreground", "font"};
990 for(int i = 0; i < fieldNames.length; i++) {
991 String name = fieldNames[i];
992 Object oldValue = ReflectionUtils.getPrivateField(oldInstance, java.awt.Component.class, name, out.getExceptionListener());
993 Object newValue = (newInstance == null) ? null : ReflectionUtils.getPrivateField(newInstance, java.awt.Component.class, name, out.getExceptionListener());
994 if (oldValue != null && !oldValue.equals(newValue)) {
995 invokeStatement(oldInstance, "set" + NameGenerator.capitalize(name), new Object[]{oldValue}, out);
996 }
997 }
998 }
999
1000 // Bounds
1001 java.awt.Container p = c.getParent();
1002 if (p == null || p.getLayout() == null) {
1003 // Use the most concise construct.
1004 boolean locationCorrect = c.getLocation().equals(c2.getLocation());
1005 boolean sizeCorrect = c.getSize().equals(c2.getSize());
1006 if (!locationCorrect && !sizeCorrect) {
1007 invokeStatement(oldInstance, "setBounds", new Object[]{c.getBounds()}, out);
1008 }
1009 else if (!locationCorrect) {
1010 invokeStatement(oldInstance, "setLocation", new Object[]{c.getLocation()}, out);
1011 }
1012 else if (!sizeCorrect) {
1013 invokeStatement(oldInstance, "setSize", new Object[]{c.getSize()}, out);
1014 }
1015 }
1016 }
1017}
1018
1019// Container
1020class java_awt_Container_PersistenceDelegate extends DefaultPersistenceDelegate {
1021 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
1022 super.initialize(type, oldInstance, newInstance, out);
1023 // Ignore the children of a JScrollPane.
1024 // Pending(milne) find a better way to do this.
1025 if (oldInstance instanceof javax.swing.JScrollPane) {
1026 return;
1027 }
1028 java.awt.Container oldC = (java.awt.Container)oldInstance;
1029 java.awt.Component[] oldChildren = oldC.getComponents();
1030 java.awt.Container newC = (java.awt.Container)newInstance;
1031 java.awt.Component[] newChildren = (newC == null) ? new java.awt.Component[0] : newC.getComponents();
1032
1033 BorderLayout layout = ( oldC.getLayout() instanceof BorderLayout )
1034 ? ( BorderLayout )oldC.getLayout()
1035 : null;
1036
1037 JLayeredPane oldLayeredPane = (oldInstance instanceof JLayeredPane)
1038 ? (JLayeredPane) oldInstance
1039 : null;
1040
1041 // Pending. Assume all the new children are unaltered.
1042 for(int i = newChildren.length; i < oldChildren.length; i++) {
1043 Object[] args = ( layout != null )
1044 ? new Object[] {oldChildren[i], layout.getConstraints( oldChildren[i] )}
1045 : (oldLayeredPane != null)
1046 ? new Object[] {oldChildren[i], oldLayeredPane.getLayer(oldChildren[i]), Integer.valueOf(-1)}
1047 : new Object[] {oldChildren[i]};
1048
1049 invokeStatement(oldInstance, "add", args, out);
1050 }
1051 }
1052}
1053
1054// Choice
1055class java_awt_Choice_PersistenceDelegate extends DefaultPersistenceDelegate {
1056 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
1057 super.initialize(type, oldInstance, newInstance, out);
1058 java.awt.Choice m = (java.awt.Choice)oldInstance;
1059 java.awt.Choice n = (java.awt.Choice)newInstance;
1060 for (int i = n.getItemCount(); i < m.getItemCount(); i++) {
1061 invokeStatement(oldInstance, "add", new Object[]{m.getItem(i)}, out);
1062 }
1063 }
1064}
1065
1066// Menu
1067class java_awt_Menu_PersistenceDelegate extends DefaultPersistenceDelegate {
1068 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
1069 super.initialize(type, oldInstance, newInstance, out);
1070 java.awt.Menu m = (java.awt.Menu)oldInstance;
1071 java.awt.Menu n = (java.awt.Menu)newInstance;
1072 for (int i = n.getItemCount(); i < m.getItemCount(); i++) {
1073 invokeStatement(oldInstance, "add", new Object[]{m.getItem(i)}, out);
1074 }
1075 }
1076}
1077
1078// MenuBar
1079class java_awt_MenuBar_PersistenceDelegate extends DefaultPersistenceDelegate {
1080 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
1081 super.initialize(type, oldInstance, newInstance, out);
1082 java.awt.MenuBar m = (java.awt.MenuBar)oldInstance;
1083 java.awt.MenuBar n = (java.awt.MenuBar)newInstance;
1084 for (int i = n.getMenuCount(); i < m.getMenuCount(); i++) {
1085 invokeStatement(oldInstance, "add", new Object[]{m.getMenu(i)}, out);
1086 }
1087 }
1088}
1089
1090// List
1091class java_awt_List_PersistenceDelegate extends DefaultPersistenceDelegate {
1092 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
1093 super.initialize(type, oldInstance, newInstance, out);
1094 java.awt.List m = (java.awt.List)oldInstance;
1095 java.awt.List n = (java.awt.List)newInstance;
1096 for (int i = n.getItemCount(); i < m.getItemCount(); i++) {
1097 invokeStatement(oldInstance, "add", new Object[]{m.getItem(i)}, out);
1098 }
1099 }
1100}
1101
1102
1103// LayoutManagers
1104
1105// BorderLayout
1106class java_awt_BorderLayout_PersistenceDelegate extends DefaultPersistenceDelegate {
1107 protected void initialize(Class<?> type, Object oldInstance,
1108 Object newInstance, Encoder out) {
1109 super.initialize(type, oldInstance, newInstance, out);
1110 String[] locations = {"north", "south", "east", "west", "center"};
1111 String[] names = {java.awt.BorderLayout.NORTH, java.awt.BorderLayout.SOUTH,
1112 java.awt.BorderLayout.EAST, java.awt.BorderLayout.WEST,
1113 java.awt.BorderLayout.CENTER};
1114 for(int i = 0; i < locations.length; i++) {
1115 Object oldC = ReflectionUtils.getPrivateField(oldInstance,
1116 java.awt.BorderLayout.class,
1117 locations[i],
1118 out.getExceptionListener());
1119 Object newC = ReflectionUtils.getPrivateField(newInstance,
1120 java.awt.BorderLayout.class,
1121 locations[i],
1122 out.getExceptionListener());
1123 // Pending, assume any existing elements are OK.
1124 if (oldC != null && newC == null) {
1125 invokeStatement(oldInstance, "addLayoutComponent",
1126 new Object[]{oldC, names[i]}, out);
1127 }
1128 }
1129 }
1130}
1131
1132// CardLayout
1133class java_awt_CardLayout_PersistenceDelegate extends DefaultPersistenceDelegate {
1134 protected void initialize(Class<?> type, Object oldInstance,
1135 Object newInstance, Encoder out) {
1136 super.initialize(type, oldInstance, newInstance, out);
1137 Hashtable tab = (Hashtable)ReflectionUtils.getPrivateField(oldInstance,
1138 java.awt.CardLayout.class,
1139 "tab",
1140 out.getExceptionListener());
1141 if (tab != null) {
1142 for(Enumeration e = tab.keys(); e.hasMoreElements();) {
1143 Object child = e.nextElement();
1144 invokeStatement(oldInstance, "addLayoutComponent",
1145 new Object[]{child, (String)tab.get(child)}, out);
1146 }
1147 }
1148 }
1149}
1150
1151// GridBagLayout
1152class java_awt_GridBagLayout_PersistenceDelegate extends DefaultPersistenceDelegate {
1153 protected void initialize(Class<?> type, Object oldInstance,
1154 Object newInstance, Encoder out) {
1155 super.initialize(type, oldInstance, newInstance, out);
1156 Hashtable comptable = (Hashtable)ReflectionUtils.getPrivateField(oldInstance,
1157 java.awt.GridBagLayout.class,
1158 "comptable",
1159 out.getExceptionListener());
1160 if (comptable != null) {
1161 for(Enumeration e = comptable.keys(); e.hasMoreElements();) {
1162 Object child = e.nextElement();
1163 invokeStatement(oldInstance, "addLayoutComponent",
1164 new Object[]{child, comptable.get(child)}, out);
1165 }
1166 }
1167 }
1168}
1169
1170// Swing
1171
1172// JFrame (If we do this for Window instead of JFrame, the setVisible call
1173// will be issued before we have added all the children to the JFrame and
1174// will appear blank).
1175class javax_swing_JFrame_PersistenceDelegate extends DefaultPersistenceDelegate {
1176 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
1177 super.initialize(type, oldInstance, newInstance, out);
1178 java.awt.Window oldC = (java.awt.Window)oldInstance;
1179 java.awt.Window newC = (java.awt.Window)newInstance;
1180 boolean oldV = oldC.isVisible();
1181 boolean newV = newC.isVisible();
1182 if (newV != oldV) {
1183 // false means: don't execute this statement at write time.
1184 boolean executeStatements = out.executeStatements;
1185 out.executeStatements = false;
1186 invokeStatement(oldInstance, "setVisible", new Object[]{Boolean.valueOf(oldV)}, out);
1187 out.executeStatements = executeStatements;
1188 }
1189 }
1190}
1191
1192// Models
1193
1194// DefaultListModel
1195class javax_swing_DefaultListModel_PersistenceDelegate extends DefaultPersistenceDelegate {
1196 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
1197 // Note, the "size" property will be set here.
1198 super.initialize(type, oldInstance, newInstance, out);
1199 javax.swing.DefaultListModel m = (javax.swing.DefaultListModel)oldInstance;
1200 javax.swing.DefaultListModel n = (javax.swing.DefaultListModel)newInstance;
1201 for (int i = n.getSize(); i < m.getSize(); i++) {
1202 invokeStatement(oldInstance, "add", // Can also use "addElement".
1203 new Object[]{m.getElementAt(i)}, out);
1204 }
1205 }
1206}
1207
1208// DefaultComboBoxModel
1209class javax_swing_DefaultComboBoxModel_PersistenceDelegate extends DefaultPersistenceDelegate {
1210 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
1211 super.initialize(type, oldInstance, newInstance, out);
1212 javax.swing.DefaultComboBoxModel m = (javax.swing.DefaultComboBoxModel)oldInstance;
1213 for (int i = 0; i < m.getSize(); i++) {
1214 invokeStatement(oldInstance, "addElement", new Object[]{m.getElementAt(i)}, out);
1215 }
1216 }
1217}
1218
1219
1220// DefaultMutableTreeNode
1221class javax_swing_tree_DefaultMutableTreeNode_PersistenceDelegate extends DefaultPersistenceDelegate {
1222 protected void initialize(Class<?> type, Object oldInstance, Object
1223 newInstance, Encoder out) {
1224 super.initialize(type, oldInstance, newInstance, out);
1225 javax.swing.tree.DefaultMutableTreeNode m =
1226 (javax.swing.tree.DefaultMutableTreeNode)oldInstance;
1227 javax.swing.tree.DefaultMutableTreeNode n =
1228 (javax.swing.tree.DefaultMutableTreeNode)newInstance;
1229 for (int i = n.getChildCount(); i < m.getChildCount(); i++) {
1230 invokeStatement(oldInstance, "add", new
1231 Object[]{m.getChildAt(i)}, out);
1232 }
1233 }
1234}
1235
1236// ToolTipManager
1237class javax_swing_ToolTipManager_PersistenceDelegate extends PersistenceDelegate {
1238 protected Expression instantiate(Object oldInstance, Encoder out) {
1239 return new Expression(oldInstance, javax.swing.ToolTipManager.class,
1240 "sharedInstance", new Object[]{});
1241 }
1242}
1243
1244// JTabbedPane
1245class javax_swing_JTabbedPane_PersistenceDelegate extends DefaultPersistenceDelegate {
1246 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
1247 super.initialize(type, oldInstance, newInstance, out);
1248 javax.swing.JTabbedPane p = (javax.swing.JTabbedPane)oldInstance;
1249 for (int i = 0; i < p.getTabCount(); i++) {
1250 invokeStatement(oldInstance, "addTab",
1251 new Object[]{
1252 p.getTitleAt(i),
1253 p.getIconAt(i),
1254 p.getComponentAt(i)}, out);
1255 }
1256 }
1257}
1258
1259// Box
1260class javax_swing_Box_PersistenceDelegate extends DefaultPersistenceDelegate {
1261 protected boolean mutatesTo(Object oldInstance, Object newInstance) {
1262 return super.mutatesTo(oldInstance, newInstance) && getAxis(oldInstance).equals(getAxis(newInstance));
1263 }
1264
1265 protected Expression instantiate(Object oldInstance, Encoder out) {
1266 return new Expression(oldInstance, oldInstance.getClass(), "new", new Object[] {getAxis(oldInstance)});
1267 }
1268
1269 private Integer getAxis(Object object) {
1270 Box box = (Box) object;
1271 return (Integer) java_util_Collections.getPrivateField(box.getLayout(), "axis");
1272 }
1273}
1274
1275// JMenu
1276// Note that we do not need to state the initialiser for
1277// JMenuItems since the getComponents() method defined in
1278// Container will return all of the sub menu items that
1279// need to be added to the menu item.
1280// Not so for JMenu apparently.
1281class javax_swing_JMenu_PersistenceDelegate extends DefaultPersistenceDelegate {
1282 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
1283 super.initialize(type, oldInstance, newInstance, out);
1284 javax.swing.JMenu m = (javax.swing.JMenu)oldInstance;
1285 java.awt.Component[] c = m.getMenuComponents();
1286 for (int i = 0; i < c.length; i++) {
1287 invokeStatement(oldInstance, "add", new Object[]{c[i]}, out);
1288 }
1289 }
1290}
1291
1292/**
1293 * The persistence delegate for {@link MatteBorder}.
1294 * It is impossible to use {@link DefaultPersistenceDelegate}
1295 * because this class does not have writable properties.
1296 *
1297 * @author Sergey A. Malenkov
1298 */
1299final class javax_swing_border_MatteBorder_PersistenceDelegate extends PersistenceDelegate {
1300 protected Expression instantiate(Object oldInstance, Encoder out) {
1301 MatteBorder border = (MatteBorder) oldInstance;
1302 Insets insets = border.getBorderInsets();
1303 Object object = border.getTileIcon();
1304 if (object == null) {
1305 object = border.getMatteColor();
1306 }
1307 Object[] args = new Object[] {
1308 insets.top,
1309 insets.left,
1310 insets.bottom,
1311 insets.right,
1312 object,
1313 };
1314 return new Expression(border, border.getClass(), "new", args);
1315 }
1316}
1317
1318/* XXX - doens't seem to work. Debug later.
1319class javax_swing_JMenu_PersistenceDelegate extends DefaultPersistenceDelegate {
1320 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
1321 super.initialize(type, oldInstance, newInstance, out);
1322 javax.swing.JMenu m = (javax.swing.JMenu)oldInstance;
1323 javax.swing.JMenu n = (javax.swing.JMenu)newInstance;
1324 for (int i = n.getItemCount(); i < m.getItemCount(); i++) {
1325 invokeStatement(oldInstance, "add", new Object[]{m.getItem(i)}, out);
1326 }
1327 }
1328}
1329*/
1330
1331/**
1332 * The persistence delegate for {@link PrintColorUIResource}.
1333 * It is impossible to use {@link DefaultPersistenceDelegate}
1334 * because this class has special rule for serialization:
1335 * it should be converted to {@link ColorUIResource}.
1336 *
1337 * @see PrintColorUIResource#writeReplace
1338 *
1339 * @author Sergey A. Malenkov
1340 */
1341final class sun_swing_PrintColorUIResource_PersistenceDelegate extends PersistenceDelegate {
1342 protected boolean mutatesTo(Object oldInstance, Object newInstance) {
1343 return oldInstance.equals(newInstance);
1344 }
1345
1346 protected Expression instantiate(Object oldInstance, Encoder out) {
1347 Color color = (Color) oldInstance;
1348 Object[] args = new Object[] {color.getRGB()};
1349 return new Expression(color, ColorUIResource.class, "new", args);
1350 }
1351}
1352
1353class MetaData {
1354 private static Hashtable internalPersistenceDelegates = new Hashtable();
1355 private static Hashtable transientProperties = new Hashtable();
1356
1357 private static PersistenceDelegate nullPersistenceDelegate = new NullPersistenceDelegate();
1358 private static PersistenceDelegate enumPersistenceDelegate = new EnumPersistenceDelegate();
1359 private static PersistenceDelegate primitivePersistenceDelegate = new PrimitivePersistenceDelegate();
1360 private static PersistenceDelegate defaultPersistenceDelegate = new DefaultPersistenceDelegate();
1361 private static PersistenceDelegate arrayPersistenceDelegate;
1362 private static PersistenceDelegate proxyPersistenceDelegate;
1363
1364 static {
1365
1366 internalPersistenceDelegates.put("java.net.URI",
1367 new PrimitivePersistenceDelegate());
1368
1369 // it is possible because MatteBorder is assignable from MatteBorderUIResource
1370 internalPersistenceDelegates.put("javax.swing.plaf.BorderUIResource$MatteBorderUIResource",
1371 new javax_swing_border_MatteBorder_PersistenceDelegate());
1372
1373 // it is possible because FontUIResource is supported by java_awt_Font_PersistenceDelegate
1374 internalPersistenceDelegates.put("javax.swing.plaf.FontUIResource",
1375 new java_awt_Font_PersistenceDelegate());
1376
1377 // it is possible because KeyStroke is supported by java_awt_AWTKeyStroke_PersistenceDelegate
1378 internalPersistenceDelegates.put("javax.swing.KeyStroke",
1379 new java_awt_AWTKeyStroke_PersistenceDelegate());
1380
1381 internalPersistenceDelegates.put("java.sql.Date", new java_util_Date_PersistenceDelegate());
1382 internalPersistenceDelegates.put("java.sql.Time", new java_util_Date_PersistenceDelegate());
1383
1384 internalPersistenceDelegates.put("java.util.JumboEnumSet", new java_util_EnumSet_PersistenceDelegate());
1385 internalPersistenceDelegates.put("java.util.RegularEnumSet", new java_util_EnumSet_PersistenceDelegate());
1386
1387// Transient properties
1388
1389 // awt
1390
1391 // Infinite graphs.
1392 removeProperty("java.awt.geom.RectangularShape", "frame");
1393 // removeProperty("java.awt.Rectangle2D", "frame");
1394 // removeProperty("java.awt.Rectangle", "frame");
1395
1396 removeProperty("java.awt.Rectangle", "bounds");
1397 removeProperty("java.awt.Dimension", "size");
1398 removeProperty("java.awt.Point", "location");
1399
1400 // The color and font properties in Component need special treatment, see above.
1401 removeProperty("java.awt.Component", "foreground");
1402 removeProperty("java.awt.Component", "background");
1403 removeProperty("java.awt.Component", "font");
1404
1405 // The visible property of Component needs special treatment because of Windows.
1406 removeProperty("java.awt.Component", "visible");
1407
1408 // This property throws an exception if accessed when there is no child.
1409 removeProperty("java.awt.ScrollPane", "scrollPosition");
1410
1411 // 4917458 this should be removed for XAWT since it may throw
1412 // an unsupported exception if there isn't any input methods.
1413 // This shouldn't be a problem since these are added behind
1414 // the scenes automatically.
1415 removeProperty("java.awt.im.InputContext", "compositionEnabled");
1416
1417 // swing
1418
1419 // The size properties in JComponent need special treatment, see above.
1420 removeProperty("javax.swing.JComponent", "minimumSize");
1421 removeProperty("javax.swing.JComponent", "preferredSize");
1422 removeProperty("javax.swing.JComponent", "maximumSize");
1423
1424 // These properties have platform specific implementations
1425 // and should not appear in archives.
1426 removeProperty("javax.swing.ImageIcon", "image");
1427 removeProperty("javax.swing.ImageIcon", "imageObserver");
1428
1429 // This property unconditionally throws a "not implemented" exception.
1430 removeProperty("javax.swing.JMenuBar", "helpMenu");
1431
1432 // The scrollBars in a JScrollPane are dynamic and should not
1433 // be archived. The row and columns headers are changed by
1434 // components like JTable on "addNotify".
1435 removeProperty("javax.swing.JScrollPane", "verticalScrollBar");
1436 removeProperty("javax.swing.JScrollPane", "horizontalScrollBar");
1437 removeProperty("javax.swing.JScrollPane", "rowHeader");
1438 removeProperty("javax.swing.JScrollPane", "columnHeader");
1439
1440 removeProperty("javax.swing.JViewport", "extentSize");
1441
1442 // Renderers need special treatment, since their properties
1443 // change during rendering.
1444 removeProperty("javax.swing.table.JTableHeader", "defaultRenderer");
1445 removeProperty("javax.swing.JList", "cellRenderer");
1446
1447 removeProperty("javax.swing.JList", "selectedIndices");
1448
1449 // The lead and anchor selection indexes are best ignored.
1450 // Selection is rarely something that should persist from
1451 // development to deployment.
1452 removeProperty("javax.swing.DefaultListSelectionModel", "leadSelectionIndex");
1453 removeProperty("javax.swing.DefaultListSelectionModel", "anchorSelectionIndex");
1454
1455 // The selection must come after the text itself.
1456 removeProperty("javax.swing.JComboBox", "selectedIndex");
1457
1458 // All selection information should come after the JTabbedPane is built
1459 removeProperty("javax.swing.JTabbedPane", "selectedIndex");
1460 removeProperty("javax.swing.JTabbedPane", "selectedComponent");
1461
1462 // PENDING: The "disabledIcon" property is often computed from the icon property.
1463 removeProperty("javax.swing.AbstractButton", "disabledIcon");
1464 removeProperty("javax.swing.JLabel", "disabledIcon");
1465
1466 // The caret property throws errors when it it set beyond
1467 // the extent of the text. We could just set it after the
1468 // text, but this is probably not something we want to archive anyway.
1469 removeProperty("javax.swing.text.JTextComponent", "caret");
1470 removeProperty("javax.swing.text.JTextComponent", "caretPosition");
1471 // The selectionStart must come after the text itself.
1472 removeProperty("javax.swing.text.JTextComponent", "selectionStart");
1473 removeProperty("javax.swing.text.JTextComponent", "selectionEnd");
1474 }
1475
1476 /*pp*/ static boolean equals(Object o1, Object o2) {
1477 return (o1 == null) ? (o2 == null) : o1.equals(o2);
1478 }
1479
1480 public synchronized static PersistenceDelegate getPersistenceDelegate(Class type) {
1481 if (type == null) {
1482 return nullPersistenceDelegate;
1483 }
1484 if (Enum.class.isAssignableFrom(type)) {
1485 return enumPersistenceDelegate;
1486 }
1487 if (ReflectionUtils.isPrimitive(type)) {
1488 return primitivePersistenceDelegate;
1489 }
1490 // The persistence delegate for arrays is non-trivial; instantiate it lazily.
1491 if (type.isArray()) {
1492 if (arrayPersistenceDelegate == null) {
1493 arrayPersistenceDelegate = new ArrayPersistenceDelegate();
1494 }
1495 return arrayPersistenceDelegate;
1496 }
1497 // Handle proxies lazily for backward compatibility with 1.2.
1498 try {
1499 if (java.lang.reflect.Proxy.isProxyClass(type)) {
1500 if (proxyPersistenceDelegate == null) {
1501 proxyPersistenceDelegate = new ProxyPersistenceDelegate();
1502 }
1503 return proxyPersistenceDelegate;
1504 }
1505 }
1506 catch(Exception e) {}
1507 // else if (type.getDeclaringClass() != null) {
1508 // return new DefaultPersistenceDelegate(new String[]{"this$0"});
1509 // }
1510
1511 String typeName = type.getName();
1512
1513 // Check to see if there are properties that have been lazily registered for removal.
1514 if (getBeanAttribute(type, "transient_init") == null) {
1515 Vector tp = (Vector)transientProperties.get(typeName);
1516 if (tp != null) {
1517 for(int i = 0; i < tp.size(); i++) {
1518 setPropertyAttribute(type, (String)tp.get(i), "transient", Boolean.TRUE);
1519 }
1520 }
1521 setBeanAttribute(type, "transient_init", Boolean.TRUE);
1522 }
1523
1524 PersistenceDelegate pd = (PersistenceDelegate)getBeanAttribute(type, "persistenceDelegate");
1525 if (pd == null) {
1526 pd = (PersistenceDelegate)internalPersistenceDelegates.get(typeName);
1527 if (pd != null) {
1528 return pd;
1529 }
1530 internalPersistenceDelegates.put(typeName, defaultPersistenceDelegate);
1531 try {
1532 String name = type.getName();
1533 Class c = Class.forName("java.beans." + name.replace('.', '_')
1534 + "_PersistenceDelegate");
1535 pd = (PersistenceDelegate)c.newInstance();
1536 internalPersistenceDelegates.put(typeName, pd);
1537 }
1538 catch (ClassNotFoundException e) {
1539 String[] properties = getConstructorProperties(type);
1540 if (properties != null) {
1541 pd = new DefaultPersistenceDelegate(properties);
1542 internalPersistenceDelegates.put(typeName, pd);
1543 }
1544 }
1545 catch (Exception e) {
1546 System.err.println("Internal error: " + e);
1547 }
1548 }
1549
1550 return (pd != null) ? pd : defaultPersistenceDelegate;
1551 }
1552
1553 private static String[] getConstructorProperties(Class type) {
1554 String[] names = null;
1555 int length = 0;
1556 for (Constructor constructor : type.getConstructors()) {
1557 String[] value = getAnnotationValue(constructor);
1558 if ((value != null) && (length < value.length) && isValid(constructor, value)) {
1559 names = value;
1560 length = value.length;
1561 }
1562 }
1563 return names;
1564 }
1565
1566 private static String[] getAnnotationValue(Constructor constructor) {
1567 ConstructorProperties annotation = constructor.getAnnotation(ConstructorProperties.class);
1568 return (annotation != null)
1569 ? annotation.value()
1570 : null;
1571 }
1572
1573 private static boolean isValid(Constructor constructor, String[] names) {
1574 Class[] parameters = constructor.getParameterTypes();
1575 if (names.length != parameters.length) {
1576 return false;
1577 }
1578 for (String name : names) {
1579 if (name == null) {
1580 return false;
1581 }
1582 }
1583 return true;
1584 }
1585
1586 // Wrapper for Introspector.getBeanInfo to handle exception handling.
1587 // Note: this relys on new 1.4 Introspector semantics which cache the BeanInfos
1588 public static BeanInfo getBeanInfo(Class type) {
1589 BeanInfo info = null;
1590 try {
1591 info = Introspector.getBeanInfo(type);
1592 } catch (Throwable e) {
1593 e.printStackTrace();
1594 }
1595
1596 return info;
1597 }
1598
1599 private static PropertyDescriptor getPropertyDescriptor(Class type, String propertyName) {
1600 BeanInfo info = getBeanInfo(type);
1601 PropertyDescriptor[] propertyDescriptors = info.getPropertyDescriptors();
1602 // System.out.println("Searching for: " + propertyName + " in " + type);
1603 for(int i = 0; i < propertyDescriptors.length; i++) {
1604 PropertyDescriptor pd = propertyDescriptors[i];
1605 if (propertyName.equals(pd.getName())) {
1606 return pd;
1607 }
1608 }
1609 return null;
1610 }
1611
1612 private static void setPropertyAttribute(Class type, String property, String attribute, Object value) {
1613 PropertyDescriptor pd = getPropertyDescriptor(type, property);
1614 if (pd == null) {
1615 System.err.println("Warning: property " + property + " is not defined on " + type);
1616 return;
1617 }
1618 pd.setValue(attribute, value);
1619 }
1620
1621 private static void setBeanAttribute(Class type, String attribute, Object value) {
1622 getBeanInfo(type).getBeanDescriptor().setValue(attribute, value);
1623 }
1624
1625 private static Object getBeanAttribute(Class type, String attribute) {
1626 return getBeanInfo(type).getBeanDescriptor().getValue(attribute);
1627 }
1628
1629 private static void removeProperty(String typeName, String property) {
1630 Vector tp = (Vector)transientProperties.get(typeName);
1631 if (tp == null) {
1632 tp = new Vector();
1633 transientProperties.put(typeName, tp);
1634 }
1635 tp.add(property);
1636 }
1637}