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 2008 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 
32 /**
33  * Identifies a compiled D program.  This identifier is valid only on
34  * the {@link LocalConsumer} from which it was obtained.  Some {@code
35  * Consumer} methods attach additional {@link ProgramInfo} to this
36  * identifier.
37  * <p>
38  * Not intended for persistence, since it identifies nothing after its
39  * source {@code LocalConsumer} closes.
40  *
41  * @see Consumer#compile(String program, String[] macroArgs)
42  * @see Consumer#compile(java.io.File program, String[] macroArgs)
43  * @see Consumer#enable(Program program)
44  * @see Consumer#getProgramInfo(Program program)
45  * @see Consumer#listProgramProbes(Program program)
46  * @see Consumer#listProgramProbeDetail(Program program)
47  *
48  * @author Tom Erickson
49  */
50 public class Program implements Serializable {
51     static final long serialVersionUID = 364989786308628466L;
52 
53     /**
54      * Identifies this program among all of a consumer's programs.  Set
55      * by native code.
56      *
57      * @serial
58      */
59     private int id = -1;
60 
61     // Set by LocalConsumer.compile()
62     /** @serial */
63     LocalConsumer.Identifier consumerID;
64     /** @serial */
65     String contents;
66 
67     /** @serial */
68     private ProgramInfo info;
69 
70     /**
71      * Called by native code
72      */
Program()73     private Program()
74     {
75     }
76 
77     // Called by LocalConsumer.compile() to ensure that only valid
78     // instances are made accessible to users.  Similarly called by
79     // readObject to ensure that only valid instances are deserialized.
80     final void
validate()81     validate()
82     {
83 	if (id < 0) {
84 	    throw new IllegalArgumentException("id is negative");
85 	}
86 	if (consumerID == null) {
87 	    throw new NullPointerException("consumer ID is null");
88 	}
89     }
90 
91     /**
92      * Gets the full pre-compiled text of the identified program.
93      *
94      * @return the {@code String} passed to {@link
95      * Consumer#compile(String program, String[] macroArgs)}, or the
96      * contents of the {@code File} passed to {@link
97      * Consumer#compile(java.io.File program, String[] macroArgs)}
98      */
99     public String
getContents()100     getContents()
101     {
102 	return contents;
103     }
104 
105     /**
106      * Gets information about this compiled program provided by {@link
107      * Consumer#getProgramInfo(Program program)} or {@link
108      * Consumer#enable(Program program)}.
109      *
110      * @return information about this compiled program, or {@code null}
111      * if this {@code Program} has not been passed to {@link
112      * Consumer#getProgramInfo(Program program)} or {@link
113      * Consumer#enable(Program program)}
114      */
115     public ProgramInfo
getInfo()116     getInfo()
117     {
118 	return info;
119     }
120 
121     /**
122      * Sets additional information about this compiled program,
123      * including program stability and matching probe count.  Several
124      * {@code Consumer} methods attach such information to a given
125      * {@code Program} argument.  The method is {@code public} to
126      * support implementations of the {@code Consumer} interface other
127      * than {@link LocalConsumer}.  Although a {@code Program} can only
128      * be obtained from a {@code LocalConsumer}, other {@code Consumer}
129      * implemenations may provide a helpful layer of abstraction while
130      * using a {@code LocalConsumer} internally to compile DTrace
131      * programs.  Users of the API are not otherwise expected to call
132      * the {@code setInfo()} method directly.
133      *
134      * @param programInfo optional additional information about this
135      * compiled program
136      * @see #getInfo()
137      * @see Consumer#enable(Program program)
138      * @see Consumer#getProgramInfo(Program program)
139      */
140     public void
setInfo(ProgramInfo programInfo)141     setInfo(ProgramInfo programInfo)
142     {
143 	info = programInfo;
144     }
145 
146     private void
readObject(ObjectInputStream s)147     readObject(ObjectInputStream s)
148 	    throws IOException, ClassNotFoundException
149     {
150 	s.defaultReadObject();
151 	// check class invariants
152 	try {
153 	    validate();
154 	} catch (Exception e) {
155 	    InvalidObjectException x = new InvalidObjectException(
156 		    e.getMessage());
157 	    x.initCause(e);
158 	    throw x;
159 	}
160     }
161 
162     /**
163      * Gets the contents of the given file as a string.
164      *
165      * @return non-null contents of the given file as a string
166      * @throws IOException if the method fails to read the contents of
167      * the given file
168      */
169     static String
getProgramString(java.io.File programFile)170     getProgramString(java.io.File programFile) throws IOException
171     {
172 	if (programFile == null) {
173 	    return null;
174 	}
175 
176 	StringBuilder buf = new StringBuilder();
177 	InputStream in;
178 	in = new BufferedInputStream(new FileInputStream(programFile));
179 	int i = in.read();
180 	while (i >= 0) {
181 	    buf.append((char)i);
182 	    i = in.read();
183 	}
184 
185 	String s = buf.toString();
186 	return s;
187     }
188 
189     /**
190      * Gets a string representation of this {@code Program} instance
191      * useful for logging and not intended for display.  The exact
192      * details of the representation are unspecified and subject to
193      * change, but the following format may be regarded as typical:
194      * <pre><code>
195      * class-name[property1 = value1, property2 = value2]
196      * </code></pre>
197      */
198     public String
toString()199     toString()
200     {
201 	StringBuilder buf = new StringBuilder();
202 	buf.append(Program.class.getName());
203 	buf.append("[contents = ");
204 	buf.append(contents);
205 	buf.append(", info = ");
206 	buf.append(info);
207 	buf.append(']');
208 	return buf.toString();
209     }
210 
211     /**
212      * Identifies a compiled D program, specifically one that has been
213      * compiled from a file.
214      */
215     public static final class File extends Program {
216 	static final long serialVersionUID = 6217493430514165300L;
217 
218 	// Set by LocalConsumer.compile()
219 	/** @serial */
220 	java.io.File file;
221 
222 	private
File()223 	File()
224 	{
225 	}
226 
227 	// Called by LocalConsumer.compile() to ensure that only valid
228 	// instances are made accessible to users.  Similarly called by
229 	// readObject to ensure that only valid instances are deserialized.
230 	final void
validateFile()231 	validateFile()
232 	{
233 	    if (file == null) {
234 		throw new NullPointerException("file is null");
235 	    }
236 	}
237 
238 	/**
239 	 * Gets the program file.
240 	 *
241 	 * @return the {@code File} passed to {@link
242 	 * Consumer#compile(java.io.File program, String[] macroArgs)}
243 	 */
244 	public java.io.File
getFile()245 	getFile()
246 	{
247 	    return file;
248 	}
249 
250 	private void
readObject(ObjectInputStream s)251 	readObject(ObjectInputStream s)
252 		throws IOException, ClassNotFoundException
253 	{
254 	    s.defaultReadObject();
255 	    // check class invariants
256 	    try {
257 		validateFile();
258 	    } catch (Exception e) {
259 		InvalidObjectException x = new InvalidObjectException(
260 			e.getMessage());
261 		x.initCause(e);
262 		throw x;
263 	    }
264 	}
265 
266 	public String
toString()267 	toString()
268 	{
269 	    StringBuilder buf = new StringBuilder();
270 	    buf.append(Program.File.class.getName());
271 	    buf.append("[super = ");
272 	    buf.append(super.toString());
273 	    buf.append(", file = ");
274 	    buf.append(file);
275 	    buf.append(']');
276 	    return buf.toString();
277 	}
278     }
279 }
280