1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * ident	"%Z%%M%	%I%	%E% SMI"
27  */
28 package org.opensolaris.os.dtrace;
29 
30 import java.io.*;
31 import java.beans.*;
32 import java.util.*;
33 
34 /**
35  * A formatted string generated by the DTrace {@code printf()} action.
36  * <p>
37  * Immutable.  Supports persistence using {@link java.beans.XMLEncoder}.
38  *
39  * @author Tom Erickson
40  */
41 public final class PrintfRecord implements Record, Serializable {
42     static final long serialVersionUID = 727237355963977675L;
43 
44     static {
45 	try {
46 	    BeanInfo info = Introspector.getBeanInfo(PrintfRecord.class);
47 	    PersistenceDelegate persistenceDelegate =
48 		    new DefaultPersistenceDelegate(
49 		    new String[] {"records", "formattedString"});
50 	    BeanDescriptor d = info.getBeanDescriptor();
51 	    d.setValue("persistenceDelegate", persistenceDelegate);
52 	} catch (IntrospectionException e) {
53 	    System.out.println(e);
54 	}
55     }
56 
57     /** @serial */
58     private List <ValueRecord> records;
59     /** @serial */
60     private String formattedString;
61 
62     // package-level access, called by ProbeData
63     PrintfRecord()
64     {
65 	records = new ArrayList <ValueRecord> ();
66     }
67 
68     /**
69      * Creates a record with the unformatted elements passed to the
70      * DTrace {@code printf()} action and the resulting formatted
71      * output.  Supports XML persistence.
72      *
73      * @param v variable number of unformatted elements passed to the
74      * DTrace {@code printf()} action
75      * @param s formatted {@code printf()} output
76      * @throws NullPointerException if the given list or any of its
77      * elements is {@code null}, or if the given formatted string is
78      * {@code null}
79      */
80     public
81     PrintfRecord(List <ValueRecord> v, String s)
82     {
83 	formattedString = s;
84 	records = new ArrayList <ValueRecord> (v.size());
85 	records.addAll(v);
86 	validate();
87     }
88 
89     private void
90     validate()
91     {
92 	if (formattedString == null) {
93 	    throw new NullPointerException("formatted string is null");
94 	}
95 	if (records == null) {
96 	    throw new NullPointerException("list of format args is null");
97 	}
98 	for (ValueRecord r : records) {
99 	    if (r == null) {
100 		throw new NullPointerException("format arg is null");
101 	    }
102 	}
103     }
104 
105     /**
106      * Called by ProbeData code to populate record list.
107      *
108      * @throws NullPointerException if o is null
109      */
110     void
111     addUnformattedElement(ScalarRecord rec)
112     {
113 	records.add(rec);
114     }
115 
116     /**
117      * Gets the formatted string output of the DTrace {@code printf()}
118      * action.
119      *
120      * @return non-null formatted string output of the DTrace {@code
121      * printf()} action
122      */
123     public String
124     getFormattedString()
125     {
126 	return formattedString;
127     }
128 
129     /**
130      * Package level access; called by ProbeData
131      */
132     void
133     setFormattedString(String s)
134     {
135 	if (s == null) {
136 	    throw new NullPointerException("formatted string is null");
137 	}
138 	formattedString = s;
139     }
140 
141     /**
142      * Gets the unfomatted elements passed to the DTrace {@code
143      * printf()} action after the format string.
144      *
145      * @return non-null, unmodifiable list of unformatted elements
146      * passed to the DTrace {@code printf()} action that generated this
147      * record, in the order they appear in the argument list after the
148      * format string
149      */
150     public List <ValueRecord>
151     getRecords()
152     {
153 	return Collections.unmodifiableList(records);
154     }
155 
156     /**
157      * Gets the number of DTrace {@code printf()} unformatted elements
158      * (arguments following the format string).  For example, the
159      * following action
160      * <pre><code>
161      *    printf("%s %d\n", "cat", 9);
162      * </code></pre>
163      * generates a {@code PrintfRecord} with a record count of two.
164      *
165      * @return the number of unformatted elements passed to the DTrace
166      * {@code printf()} action that generated this record.
167      */
168     public int
169     getRecordCount()
170     {
171 	return records.size();
172     }
173 
174     /**
175      * Gets the unformatted element passed to the DTrace {@code
176      * printf()} action at the given offset in the {@code printf()}
177      * argument list after the format string, starting at offset zero
178      * for the first unformatted element.
179      *
180      * @return non-null record representing the unformatted {@code
181      * printf()} element at the given index (using the same order that
182      * they appear in the {@code printf()} argument list)
183      * @throws ArrayIndexOutOfBoundsException if the given index is
184      * out of range (index < 0 || index >= getRecordCount())
185      */
186     public ValueRecord
187     getRecord(int i)
188     {
189 	return records.get(i);
190     }
191 
192     private void
193     readObject(ObjectInputStream s)
194             throws IOException, ClassNotFoundException
195     {
196 	s.defaultReadObject();
197 	// Defensively copy record list before validating
198 	if (records == null) {
199 	    throw new InvalidObjectException("record list is null");
200 	}
201 	List <ValueRecord> copy = new ArrayList <ValueRecord> (records.size());
202 	copy.addAll(records);
203 	records = copy;
204 	// check invariants
205 	try {
206 	    validate();
207 	} catch (Exception e) {
208 	    throw new InvalidObjectException(e.getMessage());
209 	}
210     }
211 
212     /**
213      * Gets the formatted string output of the DTrace {@code printf()}
214      * action.
215      */
216     public String
217     toString()
218     {
219 	return formattedString;
220     }
221 }
222