1178476Sjb/*
2178476Sjb * CDDL HEADER START
3178476Sjb *
4178476Sjb * The contents of this file are subject to the terms of the
5178476Sjb * Common Development and Distribution License (the "License").
6178476Sjb * You may not use this file except in compliance with the License.
7178476Sjb *
8178476Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9178476Sjb * or http://www.opensolaris.org/os/licensing.
10178476Sjb * See the License for the specific language governing permissions
11178476Sjb * and limitations under the License.
12178476Sjb *
13178476Sjb * When distributing Covered Code, include this CDDL HEADER in each
14178476Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15178476Sjb * If applicable, add the following below this CDDL HEADER, with the
16178476Sjb * fields enclosed by brackets "[]" replaced with your own identifying
17178476Sjb * information: Portions Copyright [yyyy] [name of copyright owner]
18178476Sjb *
19178476Sjb * CDDL HEADER END
20178476Sjb */
21178476Sjb
22178476Sjb/*
23178476Sjb * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24178476Sjb * Use is subject to license terms.
25178476Sjb *
26178476Sjb * ident	"%Z%%M%	%I%	%E% SMI"
27178476Sjb */
28178476Sjb
29178476Sjbimport org.opensolaris.os.dtrace.*;
30178476Sjbimport java.util.*;
31178476Sjbimport java.io.*;
32178476Sjbimport java.beans.*;
33178476Sjbimport java.lang.reflect.*;
34178476Sjb
35178476Sjb/**
36178476Sjb * Regression test for serialization and XML encoding/decoding.  Tests
37178476Sjb * every Serializable class in the Java DTrace API by creating a dummy
38178476Sjb * instance, writing it to a file, then reading it back in and comparing
39178476Sjb * the string values of the object before and after, as well as
40178476Sjb * verifying object equality before and after if the class overrides the
41178476Sjb * equals() method.
42178476Sjb */
43178476Sjbpublic class TestBean {
44178476Sjb    public static final String[] TESTS = new String[] {
45178476Sjb	"ExitRecord",
46178476Sjb	"AggregationRecord",
47178476Sjb	"Aggregation",
48178476Sjb	"Tuple",
49178476Sjb	"ScalarRecord",
50178476Sjb	"KernelStackRecord",
51178476Sjb	"LogDistribution",
52178476Sjb	"LinearDistribution",
53178476Sjb	"Option",
54178476Sjb	"ProcessState",
55178476Sjb	"ProbeDescription",
56178476Sjb	"PrintaRecord",
57178476Sjb	"PrintfRecord",
58178476Sjb	"ProbeData",
59178476Sjb	"Aggregate",
60178476Sjb	"UserStackRecord",
61178476Sjb	"AvgValue",
62178476Sjb	"CountValue",
63178476Sjb	"SumValue",
64178476Sjb	"MinValue",
65178476Sjb	"MaxValue",
66178476Sjb	"Error",
67178476Sjb	"Drop",
68178476Sjb	"InterfaceAttributes",
69178476Sjb	"ProgramInfo",
70178476Sjb	"ProbeInfo",
71178476Sjb	"Probe",
72178476Sjb	"Flow",
73178476Sjb	"KernelSymbolRecord",
74178476Sjb	"UserSymbolRecord",
75178476Sjb	"UserSymbolRecord$Value",
76178476Sjb	"Program",
77178476Sjb	"Program$File",
78178476Sjb	"StddevValue"
79178476Sjb    };
80178476Sjb
81178476Sjb    static File file;
82178476Sjb
83178476Sjb    static void
84178476Sjb    exit(int status)
85178476Sjb    {
86178476Sjb	System.out.flush();
87178476Sjb	System.err.flush();
88178476Sjb	System.exit(status);
89178476Sjb    }
90178476Sjb
91178476Sjb    public static XMLEncoder
92178476Sjb    getXMLEncoder(File file)
93178476Sjb    {
94178476Sjb        XMLEncoder encoder = null;
95178476Sjb        try {
96178476Sjb            OutputStream out = new BufferedOutputStream
97178476Sjb                    (new FileOutputStream(file));
98178476Sjb            encoder = new XMLEncoder(out);
99178476Sjb        } catch (Exception e) {
100178476Sjb	    e.printStackTrace();
101178476Sjb	    exit(1);
102178476Sjb        }
103178476Sjb        return encoder;
104178476Sjb    }
105178476Sjb
106178476Sjb    public static XMLDecoder
107178476Sjb    getXMLDecoder(File file)
108178476Sjb    {
109178476Sjb        return getXMLDecoder(file, null);
110178476Sjb    }
111178476Sjb
112178476Sjb    public static XMLDecoder
113178476Sjb    getXMLDecoder(File file, ExceptionListener exceptionListener)
114178476Sjb    {
115178476Sjb        XMLDecoder decoder = null;
116178476Sjb        try {
117178476Sjb            InputStream in = new BufferedInputStream
118178476Sjb                    (new FileInputStream(file));
119178476Sjb            decoder = new XMLDecoder(in, null, exceptionListener);
120178476Sjb        } catch (Exception e) {
121178476Sjb	    e.printStackTrace();
122178476Sjb	    exit(1);
123178476Sjb        }
124178476Sjb        return decoder;
125178476Sjb    }
126178476Sjb
127178476Sjb    public static ExitRecord
128178476Sjb    getExitRecord()
129178476Sjb    {
130178476Sjb	ExitRecord r = new ExitRecord(1);
131178476Sjb	return r;
132178476Sjb    }
133178476Sjb
134178476Sjb    public static AggregationRecord
135178476Sjb    getAggregationRecord()
136178476Sjb    {
137178476Sjb	Tuple tuple = getTuple();
138178476Sjb	AggregationValue value = new CountValue(7);
139178476Sjb	AggregationRecord r = new AggregationRecord(tuple, value);
140178476Sjb	return r;
141178476Sjb    }
142178476Sjb
143178476Sjb    public static Aggregation
144178476Sjb    getAggregation()
145178476Sjb    {
146178476Sjb	List < AggregationRecord > list =
147178476Sjb	    new ArrayList < AggregationRecord > ();
148178476Sjb	AggregationRecord r;
149178476Sjb	r = getAggregationRecord();
150178476Sjb	list.add(r);
151178476Sjb
152178476Sjb	ValueRecord v1 = new ScalarRecord(new byte[] {(byte)1, (byte)2,
153178476Sjb	    (byte)3}, 3);
154178476Sjb	ValueRecord v2 = new ScalarRecord("shebang!", 256);
155178476Sjb	Tuple tuple = new Tuple(v1, v2);
156178476Sjb	AggregationValue value = getLinearDistribution();
157178476Sjb	r = new AggregationRecord(tuple, value);
158178476Sjb	list.add(r);
159178476Sjb
160178476Sjb	Aggregation a = new Aggregation("counts", 2, list);
161178476Sjb	return a;
162178476Sjb    }
163178476Sjb
164178476Sjb    public static Tuple
165178476Sjb    getTuple()
166178476Sjb    {
167178476Sjb	ValueRecord r1 = new ScalarRecord("cat", 256);
168178476Sjb	ValueRecord r2 = new ScalarRecord(new Integer(9), 2);
169178476Sjb	ValueRecord r3 = new KernelStackRecord(
170178476Sjb		new StackFrame[] {
171178476Sjb		    new StackFrame("has"),
172178476Sjb		    new StackFrame("nine"),
173178476Sjb		    new StackFrame("lives")},
174178476Sjb		new byte[] { (byte)0, (byte)1, (byte)2 });
175178476Sjb	ValueRecord r4 = new ScalarRecord(new byte[] {(byte)1, (byte)2,
176178476Sjb	    (byte)3}, 3);
177178476Sjb
178178476Sjb	Tuple tuple = new Tuple(r1, r2, r3, r4);
179178476Sjb	return tuple;
180178476Sjb    }
181178476Sjb
182178476Sjb    public static ScalarRecord
183178476Sjb    getScalarRecord()
184178476Sjb    {
185178476Sjb	Object v = new byte[] {(byte)1, (byte)2, (byte)3};
186178476Sjb	ScalarRecord r = new ScalarRecord(v, 3);
187178476Sjb	return r;
188178476Sjb    }
189178476Sjb
190178476Sjb    public static KernelStackRecord
191178476Sjb    getKernelStackRecord()
192178476Sjb    {
193178476Sjb	StackFrame[] stackFrames = new StackFrame[] {
194178476Sjb	    new StackFrame("Frame 1"),
195178476Sjb	    new StackFrame("Frame 2"),
196178476Sjb	    new StackFrame("Frame 3")
197178476Sjb	};
198178476Sjb	KernelStackRecord r = new KernelStackRecord(stackFrames,
199178476Sjb		new byte[] { (byte)0, (byte)1, (byte)2 });
200178476Sjb	return r;
201178476Sjb    }
202178476Sjb
203178476Sjb    public static LogDistribution
204178476Sjb    getLogDistribution()
205178476Sjb    {
206178476Sjb	List < Distribution.Bucket > buckets =
207178476Sjb		new ArrayList < Distribution.Bucket > ();
208178476Sjb	Distribution.Bucket bucket;
209178476Sjb	int n = 0;
210178476Sjb	long base = 0;
211178476Sjb	long i;
212178476Sjb	long sign;
213178476Sjb	long nextSign;
214178476Sjb	long power;
215178476Sjb	long nextPower;
216178476Sjb	long lowerBound;
217178476Sjb	long upperBound;
218178476Sjb	for (i = -62; i <= 62; ++i) {
219178476Sjb	    if (i == 0) {
220178476Sjb		bucket = new Distribution.Bucket(-1, -1, n++);
221178476Sjb		buckets.add(bucket);
222178476Sjb		bucket = new Distribution.Bucket(0, 0, n++);
223178476Sjb		buckets.add(bucket);
224178476Sjb		bucket = new Distribution.Bucket(1, 1, n++);
225178476Sjb		buckets.add(bucket);
226178476Sjb		continue;
227178476Sjb	    }
228178476Sjb	    sign = ((i < 0) ? -1L : 1L);
229178476Sjb	    power = (sign * i);
230178476Sjb	    nextSign = (((i + 1) < 0) ? -1L : 1L);
231178476Sjb	    nextPower = (nextSign * (i + 1));
232178476Sjb	    lowerBound = sign * ((long) Math.pow(2L, power));
233178476Sjb	    upperBound = (nextPower == 0 ? -2L :
234178476Sjb		    (nextSign * ((long) Math.pow(2L, nextPower))) - 1);
235178476Sjb	    if ((upperBound > 0) && ((upperBound * 2L) < 0)) {
236178476Sjb		upperBound = Long.MAX_VALUE;
237178476Sjb	    }
238178476Sjb	    bucket = new Distribution.Bucket(lowerBound, upperBound, n++);
239178476Sjb	    buckets.add(bucket);
240178476Sjb	}
241178476Sjb	LogDistribution d = new LogDistribution(buckets);
242178476Sjb	return d;
243178476Sjb    }
244178476Sjb
245178476Sjb    public static LinearDistribution
246178476Sjb    getLinearDistribution()
247178476Sjb    {
248178476Sjb	List < Distribution.Bucket > buckets =
249178476Sjb		new ArrayList < Distribution.Bucket > ();
250178476Sjb	Distribution.Bucket bucket;
251178476Sjb	int n = 10; // number of buckets
252178476Sjb	int base = 1;
253178476Sjb	int step = 10;
254178476Sjb	bucket = new Distribution.Bucket(Long.MIN_VALUE, (base - 1), 0);
255178476Sjb	buckets.add(bucket);
256178476Sjb	for (int i = base; i < (n * step); i += step) {
257178476Sjb	    bucket = new Distribution.Bucket(i, (i + (step - 1)),
258178476Sjb		    ((i - 1) / step));
259178476Sjb	    buckets.add(bucket);
260178476Sjb	}
261178476Sjb	bucket = new Distribution.Bucket((n * step) + 1, Long.MAX_VALUE, 0);
262178476Sjb	buckets.add(bucket);
263178476Sjb	LinearDistribution d = new LinearDistribution(base, step, buckets);
264178476Sjb	return d;
265178476Sjb    }
266178476Sjb
267178476Sjb    public static Option
268178476Sjb    getOption()
269178476Sjb    {
270178476Sjb	Option option = new Option("aggrate", "1s");
271178476Sjb	return option;
272178476Sjb    }
273178476Sjb
274178476Sjb    public static ProcessState
275178476Sjb    getProcessState()
276178476Sjb    {
277178476Sjb	ProcessState p = new ProcessState(123456, "UNDEAD",
278178476Sjb		3, "SIGSTOP",
279178476Sjb		-2, "Process stopped on dime");
280178476Sjb	return p;
281178476Sjb    }
282178476Sjb
283178476Sjb    public static ProbeDescription
284178476Sjb    getProbeDescription()
285178476Sjb    {
286178476Sjb	ProbeDescription d = new ProbeDescription(256, "syscall", null,
287178476Sjb	    "malloc", "entry");
288178476Sjb	return d;
289178476Sjb    }
290178476Sjb
291178476Sjb    public static PrintaRecord
292178476Sjb    getPrintaRecord()
293178476Sjb    {
294178476Sjb	List < Aggregation > aggregations = new ArrayList < Aggregation > ();
295178476Sjb	Aggregation a = getAggregation();
296178476Sjb	aggregations.add(a);
297178476Sjb	aggregations.add(a);
298178476Sjb	Map < Tuple, String > formattedOutput =
299178476Sjb		new HashMap < Tuple, String > ();
300178476Sjb	for (Tuple t : a.asMap().keySet()) {
301178476Sjb	    formattedOutput.put(t, "cat");
302178476Sjb	}
303178476Sjb	List < Tuple > tuples = new ArrayList < Tuple > ();
304178476Sjb	for (Tuple t : a.asMap().keySet()) {
305178476Sjb	    tuples.add(t);
306178476Sjb	}
307178476Sjb	Collections.sort(tuples);
308178476Sjb	PrintaRecord r = new PrintaRecord(1234567890L,
309178476Sjb	    aggregations, formattedOutput, tuples,
310178476Sjb	    "Yes, this is the formatted printa() output");
311178476Sjb	return r;
312178476Sjb    }
313178476Sjb
314178476Sjb    public static PrintfRecord
315178476Sjb    getPrintfRecord()
316178476Sjb    {
317178476Sjb	List < ValueRecord > list = new ArrayList < ValueRecord > ();
318178476Sjb	ValueRecord v1 = getScalarRecord();
319178476Sjb	ValueRecord v2 = new ScalarRecord(new Integer(7), 4);
320178476Sjb	list.add(v1);
321178476Sjb	list.add(v2);
322178476Sjb	PrintfRecord r = new PrintfRecord(list,
323178476Sjb		"long formatted string");
324178476Sjb	return r;
325178476Sjb    }
326178476Sjb
327178476Sjb    public static ProbeData
328178476Sjb    getProbeData()
329178476Sjb    {
330178476Sjb	List < Record > list = new ArrayList < Record > ();
331178476Sjb	list.add(getPrintaRecord());
332178476Sjb	list.add(getPrintfRecord());
333178476Sjb	list.add(getScalarRecord());
334178476Sjb	list.add(getUserSymbolRecord());
335178476Sjb	list.add(getUserStackRecord());
336178476Sjb	list.add(getExitRecord());
337178476Sjb	ProbeData d = new ProbeData(7, 1, getProbeDescription(),
338178476Sjb	    getFlow(), list);
339178476Sjb	return d;
340178476Sjb    }
341178476Sjb
342178476Sjb    public static Aggregate
343178476Sjb    getAggregate()
344178476Sjb    {
345178476Sjb	List < Aggregation > list = new ArrayList < Aggregation > ();
346178476Sjb	list.add(getAggregation());
347178476Sjb
348178476Sjb	List < AggregationRecord > reclist =
349178476Sjb	    new ArrayList < AggregationRecord > ();
350178476Sjb	AggregationRecord r;
351178476Sjb	ValueRecord v1 = new ScalarRecord("cat", 256);
352178476Sjb	ValueRecord v2 = new ScalarRecord("dog", 256);
353178476Sjb	ValueRecord v3 = new ScalarRecord("mouse", 256);
354178476Sjb	ValueRecord v4 = new ScalarRecord("mouse", 256);
355178476Sjb	ValueRecord v5 = new ScalarRecord(new Byte((byte) 'C'), 1);
356178476Sjb	ValueRecord v6 = new ScalarRecord(new Short((short) 7), 2);
357178476Sjb	Tuple tuple = new Tuple(v1, v2, v3, v4, v5, v6);
358178476Sjb	AggregationValue value = getCountValue();
359178476Sjb	r = new AggregationRecord(tuple, value);
360178476Sjb	reclist.add(r);
361178476Sjb	list.add(new Aggregation("times", 1, reclist));
362178476Sjb
363178476Sjb        Aggregate a = new Aggregate(1234567890L, list);
364178476Sjb	return a;
365178476Sjb    }
366178476Sjb
367178476Sjb    public static UserStackRecord
368178476Sjb    getUserStackRecord()
369178476Sjb    {
370178476Sjb	StackFrame[] frames = new StackFrame[] {
371178476Sjb	    new StackFrame("User Stack Frame 1"),
372178476Sjb	    new StackFrame("User Stack Frame 2"),
373178476Sjb	    new StackFrame("User Stack Frame 3")
374178476Sjb	};
375178476Sjb	UserStackRecord r = new UserStackRecord(123456, frames,
376178476Sjb		new byte[] { (byte)0, (byte)1, (byte)2 });
377178476Sjb	return r;
378178476Sjb    }
379178476Sjb
380178476Sjb    public static AvgValue
381178476Sjb    getAvgValue()
382178476Sjb    {
383178476Sjb	AvgValue v = new AvgValue(5, 20, 4);
384178476Sjb	return v;
385178476Sjb    }
386178476Sjb
387178476Sjb    public static CountValue
388178476Sjb    getCountValue()
389178476Sjb    {
390178476Sjb	CountValue v = new CountValue(9);
391178476Sjb	return v;
392178476Sjb    }
393178476Sjb
394178476Sjb    public static MinValue
395178476Sjb    getMinValue()
396178476Sjb    {
397178476Sjb	MinValue v = new MinValue(101);
398178476Sjb	return v;
399178476Sjb    }
400178476Sjb
401178476Sjb    public static MaxValue
402178476Sjb    getMaxValue()
403178476Sjb    {
404178476Sjb	MaxValue v = new MaxValue(101);
405178476Sjb	return v;
406178476Sjb    }
407178476Sjb
408178476Sjb    public static SumValue
409178476Sjb    getSumValue()
410178476Sjb    {
411178476Sjb	SumValue v = new SumValue(25);
412178476Sjb	return v;
413178476Sjb    }
414178476Sjb
415178476Sjb    public static org.opensolaris.os.dtrace.Error
416178476Sjb    getError()
417178476Sjb    {
418178476Sjb	ProbeDescription probe = getProbeDescription();
419178476Sjb	org.opensolaris.os.dtrace.Error e =
420178476Sjb	    new org.opensolaris.os.dtrace.Error(probe, 8, 3,
421178476Sjb	    1, 20, "DTRACEFLT_BADALIGN", -1, "error on enabled probe ID 8 " +
422178476Sjb	    "(ID " + probe.getID() + ": " + probe + "): Bad alignment " +
423178476Sjb	    "(0x33ef) in action #1 at DIF offset 20");
424178476Sjb	return e;
425178476Sjb    }
426178476Sjb
427178476Sjb    public static Drop
428178476Sjb    getDrop()
429178476Sjb    {
430178476Sjb	Drop drop = new Drop(2, "SPECBUSY", 72, 1041,
431178476Sjb	    "Guess we dropped stuff all over the place.");
432178476Sjb	return drop;
433178476Sjb    }
434178476Sjb
435178476Sjb    public static InterfaceAttributes
436178476Sjb    getInterfaceAttributes()
437178476Sjb    {
438178476Sjb	InterfaceAttributes a = new InterfaceAttributes(
439178476Sjb                InterfaceAttributes.Stability.UNSTABLE,
440178476Sjb                InterfaceAttributes.Stability.EVOLVING,
441178476Sjb                InterfaceAttributes.DependencyClass.ISA);
442178476Sjb	return a;
443178476Sjb    }
444178476Sjb
445178476Sjb    public static ProgramInfo
446178476Sjb    getProgramInfo()
447178476Sjb    {
448178476Sjb	ProgramInfo info = new ProgramInfo(getInterfaceAttributes(),
449178476Sjb		getInterfaceAttributes(), 256);
450178476Sjb	return info;
451178476Sjb    }
452178476Sjb
453178476Sjb    public static ProbeInfo
454178476Sjb    getProbeInfo()
455178476Sjb    {
456178476Sjb	ProbeInfo info = new ProbeInfo(getInterfaceAttributes(),
457178476Sjb		getInterfaceAttributes());
458178476Sjb	return info;
459178476Sjb    }
460178476Sjb
461178476Sjb    public static Probe
462178476Sjb    getProbe()
463178476Sjb    {
464178476Sjb	Probe p = new Probe(getProbeDescription(), getProbeInfo());
465178476Sjb	return p;
466178476Sjb    }
467178476Sjb
468178476Sjb    public static Flow
469178476Sjb    getFlow()
470178476Sjb    {
471178476Sjb	Flow f = new Flow(Flow.Kind.RETURN.name(), 3);
472178476Sjb	return f;
473178476Sjb    }
474178476Sjb
475178476Sjb    public static KernelSymbolRecord
476178476Sjb    getKernelSymbolRecord()
477178476Sjb    {
478178476Sjb	KernelSymbolRecord r = new KernelSymbolRecord("mod`func+0x4", -1L);
479178476Sjb	return r;
480178476Sjb    }
481178476Sjb
482178476Sjb    public static UserSymbolRecord
483178476Sjb    getUserSymbolRecord()
484178476Sjb    {
485178476Sjb	UserSymbolRecord r = new UserSymbolRecord(7, "mod`func+0x4", -1L);
486178476Sjb	return r;
487178476Sjb    }
488178476Sjb
489178476Sjb    public static UserSymbolRecord.Value
490178476Sjb    getUserSymbolRecord$Value()
491178476Sjb    {
492178476Sjb	UserSymbolRecord.Value v = new UserSymbolRecord.Value(7, -1L);
493178476Sjb	return v;
494178476Sjb    }
495178476Sjb
496178476Sjb    public static Program
497178476Sjb    getProgram()
498178476Sjb    {
499178476Sjb	final String PROGRAM = "syscall:::entry { @[execname] = count(); }";
500178476Sjb	Consumer consumer = new LocalConsumer();
501178476Sjb	Program p;
502178476Sjb	try {
503178476Sjb	    consumer.open();
504178476Sjb	    p = consumer.compile(PROGRAM);
505178476Sjb	    consumer.close();
506178476Sjb	} catch (DTraceException e) {
507178476Sjb	    e.printStackTrace();
508178476Sjb	    p = null;
509178476Sjb	}
510178476Sjb	return p;
511178476Sjb    }
512178476Sjb
513178476Sjb    public static Program.File
514178476Sjb    getProgram$File()
515178476Sjb    {
516178476Sjb	final String PROGRAM = "syscall:::entry { @[execname] = count(); }";
517178476Sjb	Consumer consumer = new LocalConsumer();
518178476Sjb	Program p;
519178476Sjb	try {
520178476Sjb            OutputStream out = new FileOutputStream(file);
521178476Sjb	    out.write(PROGRAM.getBytes(), 0, PROGRAM.length());
522178476Sjb	    out.flush();
523178476Sjb	    out.close();
524178476Sjb	    consumer.open();
525178476Sjb	    p = consumer.compile(file);
526178476Sjb	    consumer.close();
527178476Sjb	} catch (Exception e) {
528178476Sjb	    e.printStackTrace();
529178476Sjb	    p = null;
530178476Sjb	}
531178476Sjb	return Program.File.class.cast(p);
532178476Sjb    }
533178476Sjb
534178476Sjb    public static StddevValue
535178476Sjb    getStddevValue()
536178476Sjb    {
537178476Sjb	StddevValue v = new StddevValue(37, 114, 5, Integer.toString(9544));
538178476Sjb	return v;
539178476Sjb    }
540178476Sjb
541178476Sjb    @SuppressWarnings("unchecked")
542178476Sjb    static String
543178476Sjb    getString(Object o)
544178476Sjb    {
545178476Sjb	String s;
546178476Sjb	if (o instanceof ScalarRecord) {
547178476Sjb	    o = ((ScalarRecord)o).getValue();
548178476Sjb	}
549178476Sjb
550178476Sjb	if (o instanceof byte[]) {
551178476Sjb	    s = Arrays.toString((byte[])o);
552178476Sjb	} else if (o instanceof Object[]) {
553178476Sjb	    s = Arrays.toString((Object[])o);
554178476Sjb	} else {
555178476Sjb	    Class c = o.getClass();
556178476Sjb	    try {
557178476Sjb		Method m = c.getDeclaredMethod("toLogString");
558178476Sjb		s = (String)m.invoke(o);
559178476Sjb	    } catch (Exception e) {
560178476Sjb		s = o.toString();
561178476Sjb	    }
562178476Sjb	}
563178476Sjb	return s;
564178476Sjb    }
565178476Sjb
566178476Sjb    static void
567178476Sjb    checkEquality(Object obj, Object newobj)
568178476Sjb    {
569178476Sjb	// If the class overrides equals(), make sure the re-created
570178476Sjb	// object still equals the original object
571178476Sjb	try {
572178476Sjb	    Method eq = obj.getClass().getDeclaredMethod("equals",
573178476Sjb		    Object.class);
574178476Sjb	    Boolean ret = (Boolean) eq.invoke(obj, newobj);
575178476Sjb	    if (ret != true) {
576178476Sjb		System.err.println("serialization failed: " +
577178476Sjb			obj.getClass().getName());
578178476Sjb		exit(1);
579178476Sjb	    }
580178476Sjb	} catch (Exception e) {
581178476Sjb	    // Does not override equals(), although a super-class might.
582178476Sjb	    // A better test would check for any superclass other than
583178476Sjb	    // Object.class.
584178476Sjb	}
585178476Sjb    }
586178476Sjb
587178476Sjb    static void
588178476Sjb    performSerializationTest(File file, String classname)
589178476Sjb            throws IOException, ClassNotFoundException
590178476Sjb    {
591178476Sjb	String methodName = "get" + classname;
592178476Sjb	Object obj = null;
593178476Sjb	Object newobj = null;
594178476Sjb	try {
595178476Sjb	    Method method = TestBean.class.getDeclaredMethod(methodName);
596178476Sjb	    obj = method.invoke(null);
597178476Sjb	} catch (Exception e) {
598178476Sjb	    e.printStackTrace();
599178476Sjb	    exit(1);
600178476Sjb	}
601178476Sjb
602178476Sjb	System.out.println(classname + ":");
603178476Sjb	String serialized = getString(obj);
604178476Sjb	System.out.println("  serialized: " + serialized);
605178476Sjb	FileOutputStream fos = new FileOutputStream(file);
606178476Sjb	ObjectOutputStream out = new ObjectOutputStream(fos);
607178476Sjb	out.writeObject(obj);
608178476Sjb	out.close();
609178476Sjb	FileInputStream fis = new FileInputStream(file);
610178476Sjb	ObjectInputStream in = new ObjectInputStream(fis);
611178476Sjb	newobj = in.readObject();
612178476Sjb	in.close();
613178476Sjb	String deserialized = getString(newobj);
614178476Sjb	System.out.println("  deserialized: " + deserialized);
615178476Sjb
616178476Sjb	if (!serialized.equals(deserialized)) {
617178476Sjb	    System.err.println("serialization failed: " + classname);
618178476Sjb	    exit(1);
619178476Sjb	}
620178476Sjb	checkEquality(obj, newobj);
621178476Sjb    }
622178476Sjb
623178476Sjb    static void
624178476Sjb    performBeanTest(File file, String classname)
625178476Sjb    {
626178476Sjb	String methodName = "get" + classname;
627178476Sjb	Object obj = null;
628178476Sjb	Object newobj = null;
629178476Sjb	try {
630178476Sjb	    Method method = TestBean.class.getDeclaredMethod(methodName);
631178476Sjb	    obj = method.invoke(null);
632178476Sjb	} catch (Exception e) {
633178476Sjb	    e.printStackTrace();
634178476Sjb	    exit(1);
635178476Sjb	}
636178476Sjb
637178476Sjb	Class c = obj.getClass();
638178476Sjb	if (c.getConstructors().length == 0) {
639178476Sjb	    return;
640178476Sjb	}
641178476Sjb
642178476Sjb	System.out.println(classname + ":");
643178476Sjb	XMLEncoder encoder = getXMLEncoder(file);
644178476Sjb	String encoded = getString(obj);
645178476Sjb	System.out.println("  encoded: " + encoded);
646178476Sjb	encoder.writeObject(obj);
647178476Sjb	encoder.close();
648178476Sjb	XMLDecoder decoder = getXMLDecoder(file);
649178476Sjb	newobj = decoder.readObject();
650178476Sjb	String decoded = getString(newobj);
651178476Sjb	System.out.println("  decoded: " + decoded);
652178476Sjb	decoder.close();
653178476Sjb
654178476Sjb	if (!encoded.equals(decoded)) {
655178476Sjb	    System.err.println("bean persistence failed: " + classname);
656178476Sjb	    exit(1);
657178476Sjb	}
658178476Sjb	checkEquality(obj, newobj);
659178476Sjb    }
660178476Sjb
661178476Sjb    public static void
662178476Sjb    main(String[] args)
663178476Sjb    {
664178476Sjb	if ((args.length != 1) && (args.length != 2)) {
665178476Sjb	    System.err.println("usage: java TestBean < filename > " +
666178476Sjb		    "[ < classname > ]");
667178476Sjb	    exit(1);
668178476Sjb	}
669178476Sjb
670178476Sjb	String filename = args[0];
671178476Sjb	String classname = null;
672178476Sjb	if (args.length >= 2) {
673178476Sjb	    classname = args[1];
674178476Sjb	}
675178476Sjb
676178476Sjb	file = new File(filename);
677178476Sjb	try {
678178476Sjb	    if (!file.canRead()) {
679178476Sjb		try {
680178476Sjb		    file.createNewFile();
681178476Sjb		} catch (Exception e) {
682178476Sjb		    System.err.println("failed to create " + filename);
683178476Sjb		    exit(1);
684178476Sjb		}
685178476Sjb	    }
686178476Sjb	} catch (SecurityException e) {
687178476Sjb	    System.err.println("failed to open " + filename);
688178476Sjb	    exit(1);
689178476Sjb	}
690178476Sjb
691178476Sjb	String[] tests = (classname == null ? TESTS:
692178476Sjb		new String[] { classname });
693178476Sjb	try {
694178476Sjb	    for (int i = 0; i < tests.length; ++i) {
695178476Sjb		performSerializationTest(file, tests[i]);
696178476Sjb		performBeanTest(file, tests[i]);
697178476Sjb	    }
698178476Sjb	} catch (IOException e) {
699178476Sjb	    e.printStackTrace();
700178476Sjb	    exit(1);
701178476Sjb	} catch (ClassNotFoundException e) {
702178476Sjb	    e.printStackTrace();
703178476Sjb	    exit(1);
704178476Sjb	}
705178476Sjb    }
706178476Sjb}
707