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 2007 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 
33 /**
34  * Information about a {@link Program} including stability and matching
35  * probe count.
36  * <p>
37  * Immutable.  Supports persistence using {@link java.beans.XMLEncoder}.
38  *
39  * @see Consumer#getProgramInfo(Program program)
40  * @see Consumer#enable(Program program)
41  *
42  * @author Tom Erickson
43  */
44 public final class ProgramInfo implements Serializable {
45     static final long serialVersionUID = 663862981171935056L;
46 
47     static {
48 	try {
49 	    BeanInfo info = Introspector.getBeanInfo(ProgramInfo.class);
50 	    PersistenceDelegate persistenceDelegate =
51 		    new DefaultPersistenceDelegate(
52 		    new String[] { "minimumProbeAttributes",
53 		    "minimumStatementAttributes",
54 		    "matchingProbeCount" })
55 	    {
56 		/*
57 		 * Need to prevent DefaultPersistenceDelegate from using
58 		 * overridden equals() method, resulting in a
59 		 * StackOverFlowError.  Revert to PersistenceDelegate
60 		 * implementation.  See
61 		 * http://forum.java.sun.com/thread.jspa?threadID=
62 		 * 477019&tstart=135
63 		 */
64 		protected boolean
65 		mutatesTo(Object oldInstance, Object newInstance)
66 		{
67 		    return (newInstance != null && oldInstance != null &&
68 			    oldInstance.getClass() == newInstance.getClass());
69 		}
70 	    };
71 	    BeanDescriptor d = info.getBeanDescriptor();
72 	    d.setValue("persistenceDelegate", persistenceDelegate);
73 	} catch (IntrospectionException e) {
74 	    e.printStackTrace();
75 	}
76     }
77 
78     /** @serial */
79     private final InterfaceAttributes minimumProbeAttributes;
80     /** @serial */
81     private final InterfaceAttributes minimumStatementAttributes;
82     /** @serial */
83     private final int matchingProbeCount;
84 
85     /**
86      * Creates a {@code ProgamInfo} instance with the given properties.
87      * Supports XML persistence.
88      *
89      * @param minProbeAttr minimum stability levels of the
90      * program probe descriptions
91      * @param minStatementAttr minimum stability levels of the
92      * program action statements (including D variables)
93      * @param matchingProbes non-negative count of probes matching the
94      * program probe description
95      * @throws NullPointerException if {@code minProbeAttr} or {@code
96      * minStatementAttr} is {@code null}
97      * @throws IllegalArgumentException if {@code matchingProbes} is
98      * negative
99      */
100     public
ProgramInfo(InterfaceAttributes minProbeAttr, InterfaceAttributes minStatementAttr, int matchingProbes)101     ProgramInfo(InterfaceAttributes minProbeAttr,
102 	    InterfaceAttributes minStatementAttr,
103 	    int matchingProbes)
104     {
105 	// Called by native code.  Any change to this constructor requires a
106 	// similar change in the native invocation.
107 	minimumProbeAttributes = minProbeAttr;
108 	minimumStatementAttributes = minStatementAttr;
109 	matchingProbeCount = matchingProbes;
110 	validate();
111     }
112 
113     private final void
validate()114     validate()
115     {
116 	if (minimumProbeAttributes == null) {
117 	    throw new NullPointerException("minimumProbeAttributes is null");
118 	}
119 	if (minimumStatementAttributes == null) {
120 	    throw new NullPointerException(
121 		    "minimumStatementAttributes is null");
122 	}
123 	if (matchingProbeCount < 0) {
124 	    throw new IllegalArgumentException(
125 		    "matchingProbeCount is negative");
126 	}
127     }
128 
129     /**
130      * Gets the minimum stability levels of the probe descriptions used
131      * in a compiled {@link Program}.
132      *
133      * @return non-null interface attributes describing the minimum
134      * stability of the probe descriptions in a D program
135      */
136     public InterfaceAttributes
getMinimumProbeAttributes()137     getMinimumProbeAttributes()
138     {
139 	return minimumProbeAttributes;
140     }
141 
142     /**
143      * Gets the minimum stability levels of the action statements
144      * including D variables used in a compiled {@link Program}.
145      *
146      * @return non-null interface attributes describing the minimum
147      * stability of the action statements (including D variables) in a D
148      * program
149      */
150     public InterfaceAttributes
getMinimumStatementAttributes()151     getMinimumStatementAttributes()
152     {
153 	return minimumStatementAttributes;
154     }
155 
156     /**
157      * Gets the number of DTrace probes that match the probe
158      * descriptions in a compiled {@link Program}.  This count may be
159      * very high for programs that use {@link ProbeDescription}
160      * wildcarding (field omission) and globbing (pattern matching
161      * syntax).
162      *
163      * @return non-negative count of probes on the system matching the
164      * program descriptions in a compiled D program
165      */
166     public int
getMatchingProbeCount()167     getMatchingProbeCount()
168     {
169 	return matchingProbeCount;
170     }
171 
172     /**
173      * Compares the specified object with this program information for
174      * equality.  Defines equality as having the same information,
175      * including stability attributes and matching probe counts.
176      * Different D programs may have equal program information.
177      *
178      * @return {@code true} if and only if the specified object is also
179      * a {@code ProgramInfo} instance and has all the same information
180      * as this instance
181      */
182     @Override
183     public boolean
equals(Object o)184     equals(Object o)
185     {
186 	if (o == this) {
187 	    return true;
188 	}
189 	if (o instanceof ProgramInfo) {
190 	    ProgramInfo i = (ProgramInfo)o;
191 	    return (minimumProbeAttributes.equals(
192 		    i.minimumProbeAttributes) &&
193 		    minimumStatementAttributes.equals(
194 		    i.minimumStatementAttributes) &&
195 		    (matchingProbeCount == i.matchingProbeCount));
196 	}
197 	return false;
198     }
199 
200     /**
201      * Overridden to ensure that equal {@code ProgramInfo} instances
202      * have equal hashcodes.
203      */
204     @Override
205     public int
hashCode()206     hashCode()
207     {
208         int hash = 17;
209 	hash = (37 * hash) + minimumProbeAttributes.hashCode();
210 	hash = (37 * hash) + minimumStatementAttributes.hashCode();
211 	hash = (37 * hash) + matchingProbeCount;
212 	return hash;
213     }
214 
215     private void
readObject(ObjectInputStream s)216     readObject(ObjectInputStream s)
217             throws IOException, ClassNotFoundException
218     {
219 	s.defaultReadObject();
220 	// Check constructor invariants
221 	try {
222 	    validate();
223 	} catch (Exception e) {
224 	    InvalidObjectException x = new InvalidObjectException(
225 		    e.getMessage());
226 	    x.initCause(e);
227 	    throw x;
228 	}
229     }
230 
231     /**
232      * Gets a string representation of this {@code ProgramInfo} useful
233      * for logging and not intended for display.  The exact details of
234      * the representation are unspecified and subject to change, but the
235      * following format may be regarded as typical:
236      * <pre><code>
237      * class-name[property1 = value1, property2 = value2]
238      * </code></pre>
239      */
240     @Override
241     public String
toString()242     toString()
243     {
244 	StringBuilder buf = new StringBuilder();
245 	buf.append(ProgramInfo.class.getName());
246 	buf.append("[minimumProbeAttributes = ");
247 	buf.append(minimumProbeAttributes);
248 	buf.append(", minimumStatementAttributes = ");
249 	buf.append(minimumStatementAttributes);
250 	buf.append(", matchingProbeCount = ");
251 	buf.append(matchingProbeCount);
252 	buf.append(']');
253 	return buf.toString();
254     }
255 }
256