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.util.*;
31 import java.io.*;
32 import java.beans.*;
33 
34 /**
35  * Probe stability information.  Does not identify a probe, but gives
36  * information about a single probe identified by a {@link
37  * ProbeDescription}.  A {@code ProbeDescription} can match multiple
38  * probes using pattern syntax (globbing) and wildcarding (field
39  * omission), but it does not normally make sense to associate a {@code
40  * ProbeInfo} with a {@code ProbeDescription} unless that description
41  * matches exactly one probe on the system.  A {@link Probe} pairs a
42  * {@code ProbeDescription} with information about the DTrace probe it
43  * identifies.
44  * <p>
45  * Immutable.  Supports persistence using {@link java.beans.XMLEncoder}.
46  *
47  * @see Consumer#listProbeDetail(ProbeDescription filter)
48  * @see Consumer#listProgramProbeDetail(Program program)
49  *
50  * @author Tom Erickson
51  */
52 public final class ProbeInfo implements Serializable {
53     static final long serialVersionUID = 1057402669978245904L;
54 
55     static {
56 	try {
57 	    BeanInfo info = Introspector.getBeanInfo(ProbeInfo.class);
58 	    PersistenceDelegate persistenceDelegate =
59 		    new DefaultPersistenceDelegate(
60 		    new String[] {"probeAttributes",
61 		    "argumentAttributes"})
62 	    {
63 		/*
64 		 * Need to prevent DefaultPersistenceDelegate from using
65 		 * overridden equals() method, resulting in a
66 		 * StackOverFlowError.  Revert to PersistenceDelegate
67 		 * implementation.  See
68 		 * http://forum.java.sun.com/thread.jspa?threadID=
69 		 * 477019&tstart=135
70 		 */
71 		protected boolean
72 		mutatesTo(Object oldInstance, Object newInstance)
73 		{
74 		    return (newInstance != null && oldInstance != null &&
75 			    oldInstance.getClass() == newInstance.getClass());
76 		}
77 	    };
78 	    BeanDescriptor d = info.getBeanDescriptor();
79 	    d.setValue("persistenceDelegate", persistenceDelegate);
80 	} catch (IntrospectionException e) {
81 	    System.out.println(e);
82 	}
83     }
84 
85     /** @serial */
86     private final InterfaceAttributes probeAttributes;
87     /** @serial */
88     private final InterfaceAttributes argumentAttributes;
89 
90     /**
91      * Creates a {@code ProbeInfo} instance from the given attributes.
92      * Supports XML persistence.
93      *
94      * @throws NullPointerException if any parameter is null
95      */
96     public
ProbeInfo(InterfaceAttributes singleProbeAttributes, InterfaceAttributes argAttributes)97     ProbeInfo(InterfaceAttributes singleProbeAttributes,
98 	    InterfaceAttributes argAttributes)
99     {
100 	probeAttributes = singleProbeAttributes;
101 	argumentAttributes = argAttributes;
102 	validate();
103     }
104 
105     private final void
validate()106     validate()
107     {
108 	if (probeAttributes == null) {
109 	    throw new NullPointerException("probeAttributes is null");
110 	}
111 	if (argumentAttributes == null) {
112 	    throw new NullPointerException("argumentAttributes is null");
113 	}
114     }
115 
116     /**
117      * Gets the interface attributes of a probe.
118      *
119      * @return non-null attributes including stability levels and
120      * dependency class
121      */
122     public InterfaceAttributes
getProbeAttributes()123     getProbeAttributes()
124     {
125 	return probeAttributes;
126     }
127 
128     /**
129      * Gets the interface attributes of the arguments to a probe.
130      *
131      * @return non-null attributes including stability levels and
132      * dependency class of the arguments to a probe
133      */
134     public InterfaceAttributes
getArgumentAttributes()135     getArgumentAttributes()
136     {
137 	return argumentAttributes;
138     }
139 
140     /**
141      * Compares the specified object with this {@code ProbeInfo}
142      * instance for equality.  Defines equality as having equal probe
143      * attributes and equal argument attributes.
144      *
145      * @return {@code true} if and only if the specified object is also
146      * a {@code ProbeInfo} and both instances have the same attributes
147      */
148     @Override
149     public boolean
equals(Object o)150     equals(Object o)
151     {
152 	if (o instanceof ProbeInfo) {
153 	    ProbeInfo i = (ProbeInfo)o;
154 	    return (probeAttributes.equals(i.probeAttributes) &&
155 		    argumentAttributes.equals(i.argumentAttributes));
156 	}
157 	return false;
158     }
159 
160     /**
161      * Overridden to ensure that equal instances have equal hash codes.
162      */
163     @Override
164     public int
hashCode()165     hashCode()
166     {
167 	int hash = 17;
168 	hash = (37 * hash) + probeAttributes.hashCode();
169 	hash = (37 * hash) + argumentAttributes.hashCode();
170 	return hash;
171     }
172 
173     private void
readObject(ObjectInputStream s)174     readObject(ObjectInputStream s)
175             throws IOException, ClassNotFoundException
176     {
177 	s.defaultReadObject();
178 	// Must copy before checking class invariants
179 	try {
180 	    validate();
181 	} catch (Exception e) {
182 	    InvalidObjectException x = new InvalidObjectException(
183 		    e.getMessage());
184 	    x.initCause(e);
185 	    throw x;
186 	}
187     }
188 
189     /**
190      * Gets a string representation of this {@code ProbeInfo} useful for
191      * logging and not intended for display.  The exact details of the
192      * representation are unspecified and subject to change, but the
193      * 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(ProbeInfo.class.getName());
203 	buf.append("[probeAttributes = ");
204 	buf.append(probeAttributes);
205 	buf.append(", argumentAttributes = ");
206 	buf.append(argumentAttributes);
207 	buf.append(']');
208 	return buf.toString();
209     }
210 }
211