1fb3fb4f3Stomee /*
2fb3fb4f3Stomee  * CDDL HEADER START
3fb3fb4f3Stomee  *
4fb3fb4f3Stomee  * The contents of this file are subject to the terms of the
5fb3fb4f3Stomee  * Common Development and Distribution License (the "License").
6fb3fb4f3Stomee  * You may not use this file except in compliance with the License.
7fb3fb4f3Stomee  *
8fb3fb4f3Stomee  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fb3fb4f3Stomee  * or http://www.opensolaris.org/os/licensing.
10fb3fb4f3Stomee  * See the License for the specific language governing permissions
11fb3fb4f3Stomee  * and limitations under the License.
12fb3fb4f3Stomee  *
13fb3fb4f3Stomee  * When distributing Covered Code, include this CDDL HEADER in each
14fb3fb4f3Stomee  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fb3fb4f3Stomee  * If applicable, add the following below this CDDL HEADER, with the
16fb3fb4f3Stomee  * fields enclosed by brackets "[]" replaced with your own identifying
17fb3fb4f3Stomee  * information: Portions Copyright [yyyy] [name of copyright owner]
18fb3fb4f3Stomee  *
19fb3fb4f3Stomee  * CDDL HEADER END
20fb3fb4f3Stomee  */
21fb3fb4f3Stomee 
22fb3fb4f3Stomee /*
234ae67516Stomee  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24fb3fb4f3Stomee  * Use is subject to license terms.
25fb3fb4f3Stomee  */
26fb3fb4f3Stomee package org.opensolaris.os.dtrace;
27fb3fb4f3Stomee 
28fb3fb4f3Stomee import java.io.*;
29fb3fb4f3Stomee import java.beans.*;
30fb3fb4f3Stomee 
31fb3fb4f3Stomee /**
32fb3fb4f3Stomee  * Description of control flow across function boundaries including
33fb3fb4f3Stomee  * direction (entry or return) and depth in the call stack.  This
34fb3fb4f3Stomee  * information is added to {@link ProbeData} instances only when the
35fb3fb4f3Stomee  * {@link Option#flowindent flowindent} option is used:
36fb3fb4f3Stomee  * <pre><code>
37fb3fb4f3Stomee  *     Consumer consumer = new LocalConsumer();
38fb3fb4f3Stomee  *     consumer.open();
39fb3fb4f3Stomee  *     consumer.setOption(Option.flowindent);
40fb3fb4f3Stomee  *     ...
41fb3fb4f3Stomee  * </code></pre>
42fb3fb4f3Stomee  * See the <a
43*3a931819SPeter Tribble  * href="http://dtrace.org/guide/chp-fbt.html#chp-fbt-10">
44fb3fb4f3Stomee  * <b>Examples</b></a> section of the <b>{@code fbt}
45*3a931819SPeter Tribble  * Provider</b> chapter of the <i>Dynamic Tracing Guide</i>.
46fb3fb4f3Stomee  * <p>
47fb3fb4f3Stomee  * Immutable.  Supports persistence using {@link java.beans.XMLEncoder}.
48fb3fb4f3Stomee  *
49fb3fb4f3Stomee  * @see Consumer#setOption(String option)
50fb3fb4f3Stomee  * @see Option#flowindent
51fb3fb4f3Stomee  *
52fb3fb4f3Stomee  * @author Tom Erickson
53fb3fb4f3Stomee  */
54fb3fb4f3Stomee public final class Flow implements Serializable {
55fb3fb4f3Stomee     static final long serialVersionUID = -9178272444872063901L;
56fb3fb4f3Stomee 
57fb3fb4f3Stomee     /**
58fb3fb4f3Stomee      * Indicates direction of flow across a boundary, such as entering
59fb3fb4f3Stomee      * or returing from a function.
60fb3fb4f3Stomee      */
61fb3fb4f3Stomee     public enum Kind {
62fb3fb4f3Stomee 	/** Entry into a function. */
63fb3fb4f3Stomee 	ENTRY,
64fb3fb4f3Stomee 	/** Return from a function. */
65fb3fb4f3Stomee 	RETURN,
66fb3fb4f3Stomee 	/** No function boundary crossed. */
67fb3fb4f3Stomee 	NONE
68fb3fb4f3Stomee     }
69fb3fb4f3Stomee 
70fb3fb4f3Stomee     static {
71fb3fb4f3Stomee 	try {
72fb3fb4f3Stomee 	    BeanInfo info = Introspector.getBeanInfo(Flow.class);
73fb3fb4f3Stomee 	    PersistenceDelegate persistenceDelegate =
74fb3fb4f3Stomee 		    new DefaultPersistenceDelegate(
75fb3fb4f3Stomee 		    new String[] {"kind", "depth"})
76fb3fb4f3Stomee 	    {
77fb3fb4f3Stomee 		/*
78fb3fb4f3Stomee 		 * Need to prevent DefaultPersistenceDelegate from using
79fb3fb4f3Stomee 		 * overridden equals() method, resulting in a
80fb3fb4f3Stomee 		 * StackOverFlowError.  Revert to PersistenceDelegate
81fb3fb4f3Stomee 		 * implementation.  See
82fb3fb4f3Stomee 		 * http://forum.java.sun.com/thread.jspa?threadID=
83fb3fb4f3Stomee 		 * 477019&tstart=135
84fb3fb4f3Stomee 		 */
85fb3fb4f3Stomee 		protected boolean
86fb3fb4f3Stomee 		mutatesTo(Object oldInstance, Object newInstance)
87fb3fb4f3Stomee 		{
88fb3fb4f3Stomee 		    return (newInstance != null && oldInstance != null &&
89fb3fb4f3Stomee 			    oldInstance.getClass() == newInstance.getClass());
90fb3fb4f3Stomee 		}
91fb3fb4f3Stomee 
92fb3fb4f3Stomee 		protected Expression
93fb3fb4f3Stomee 		instantiate(Object oldInstance, Encoder out)
94fb3fb4f3Stomee 		{
95fb3fb4f3Stomee 		    Flow flow = (Flow)oldInstance;
96fb3fb4f3Stomee 		    return new Expression(oldInstance, oldInstance.getClass(),
97fb3fb4f3Stomee 			    "new", new Object[] { flow.getKind().name(),
98fb3fb4f3Stomee 			    flow.getDepth() });
99fb3fb4f3Stomee 		}
100fb3fb4f3Stomee 	    };
101fb3fb4f3Stomee 	    BeanDescriptor d = info.getBeanDescriptor();
102fb3fb4f3Stomee 	    d.setValue("persistenceDelegate", persistenceDelegate);
103fb3fb4f3Stomee 	} catch (IntrospectionException e) {
104fb3fb4f3Stomee 	    e.printStackTrace();
105fb3fb4f3Stomee 	}
106fb3fb4f3Stomee     }
107fb3fb4f3Stomee 
108fb3fb4f3Stomee     /** @serial */
109fb3fb4f3Stomee     private final Kind kind;
110fb3fb4f3Stomee     /** @serial */
111fb3fb4f3Stomee     private final int depth;
112fb3fb4f3Stomee 
113fb3fb4f3Stomee     /**
114fb3fb4f3Stomee      * Creates a {@code Flow} instance with the given flow kind and
115fb3fb4f3Stomee      * depth.  Supports XML persistence.
116fb3fb4f3Stomee      *
117fb3fb4f3Stomee      * @param flowKindName name of enumeration value indicating the
118fb3fb4f3Stomee      * direction of flow
119fb3fb4f3Stomee      * @param flowDepth current depth in the call stack
120fb3fb4f3Stomee      * @throws IllegalArgumentException if there is no {@code Flow.Kind}
121fb3fb4f3Stomee      * value with the given name or if the given {@code flowDepth} is
122fb3fb4f3Stomee      * negative
123fb3fb4f3Stomee      * @throws NullPointerException if the given {@code Flow.Kind} name
124fb3fb4f3Stomee      * is {@code null}
125fb3fb4f3Stomee      */
126fb3fb4f3Stomee     public
Flow(String flowKindName, int flowDepth)127fb3fb4f3Stomee     Flow(String flowKindName, int flowDepth)
128fb3fb4f3Stomee     {
129fb3fb4f3Stomee 	kind = Enum.valueOf(Kind.class, flowKindName);
130fb3fb4f3Stomee 	depth = flowDepth;
131fb3fb4f3Stomee 	if (depth < 0) {
132fb3fb4f3Stomee 	    throw new IllegalArgumentException("depth is negative");
133fb3fb4f3Stomee 	}
134fb3fb4f3Stomee     }
135fb3fb4f3Stomee 
136fb3fb4f3Stomee     /**
137fb3fb4f3Stomee      * Gets the direction of the flow of control (entry or return)
138fb3fb4f3Stomee      * across a function boundary.
139fb3fb4f3Stomee      *
140fb3fb4f3Stomee      * @return non-null flow kind indicating direction of flow (entry or
141fb3fb4f3Stomee      * return) across a function boundary
142fb3fb4f3Stomee      */
143fb3fb4f3Stomee     public Kind
getKind()144fb3fb4f3Stomee     getKind()
145fb3fb4f3Stomee     {
146fb3fb4f3Stomee 	return kind;
147fb3fb4f3Stomee     }
148fb3fb4f3Stomee 
149fb3fb4f3Stomee     /**
150fb3fb4f3Stomee      * Gets the current depth in the call stack.
151fb3fb4f3Stomee      *
152fb3fb4f3Stomee      * @return A non-negative sum of the function entries minus the
153fb3fb4f3Stomee      * function returns up until the moment described by this control
154fb3fb4f3Stomee      * flow instance.  For example, if the traced flow of control
155fb3fb4f3Stomee      * entered two functions but only returned from one, the depth is
156fb3fb4f3Stomee      * one (2 entries minus 1 return).
157fb3fb4f3Stomee      */
158fb3fb4f3Stomee     public int
getDepth()159fb3fb4f3Stomee     getDepth()
160fb3fb4f3Stomee     {
161fb3fb4f3Stomee 	return depth;
162fb3fb4f3Stomee     }
163fb3fb4f3Stomee 
164fb3fb4f3Stomee     /**
165fb3fb4f3Stomee      * Compares the specified object with this {@code Flow} instance for
166fb3fb4f3Stomee      * equality.  Defines equality as having the same flow kind and
167fb3fb4f3Stomee      * depth.
168fb3fb4f3Stomee      *
169fb3fb4f3Stomee      * @return {@code true} if and only if the specified object is of
170fb3fb4f3Stomee      * type {@code Flow} and both instances have equal flow kind and
171fb3fb4f3Stomee      * depth.
172fb3fb4f3Stomee      */
173fb3fb4f3Stomee     @Override
174fb3fb4f3Stomee     public boolean
equals(Object o)175fb3fb4f3Stomee     equals(Object o)
176fb3fb4f3Stomee     {
177fb3fb4f3Stomee 	if (o instanceof Flow) {
178fb3fb4f3Stomee 	    Flow f = (Flow)o;
179fb3fb4f3Stomee 	    return ((kind == f.kind) && (depth == f.depth));
180fb3fb4f3Stomee 	}
181fb3fb4f3Stomee 	return false;
182fb3fb4f3Stomee     }
183fb3fb4f3Stomee 
184fb3fb4f3Stomee     /**
185fb3fb4f3Stomee      * Overridden to ensure that equal instances have equal hash codes.
186fb3fb4f3Stomee      */
187fb3fb4f3Stomee     @Override
188fb3fb4f3Stomee     public int
hashCode()189fb3fb4f3Stomee     hashCode()
190fb3fb4f3Stomee     {
191fb3fb4f3Stomee 	int hash = 17;
192fb3fb4f3Stomee 	hash = (37 * hash) + kind.hashCode();
193fb3fb4f3Stomee 	hash = (37 * hash) + depth;
194fb3fb4f3Stomee 	return hash;
195fb3fb4f3Stomee     }
196fb3fb4f3Stomee 
197fb3fb4f3Stomee     private void
readObject(ObjectInputStream s)198fb3fb4f3Stomee     readObject(ObjectInputStream s)
199fb3fb4f3Stomee 	    throws IOException, ClassNotFoundException
200fb3fb4f3Stomee     {
201fb3fb4f3Stomee 	s.defaultReadObject();
202fb3fb4f3Stomee 	// check class invariants
203fb3fb4f3Stomee 	if (kind == null) {
204fb3fb4f3Stomee 	    throw new InvalidObjectException("kind is null");
205fb3fb4f3Stomee 	}
206fb3fb4f3Stomee 	if (depth < 0) {
207fb3fb4f3Stomee 	    throw new InvalidObjectException("depth is negative");
208fb3fb4f3Stomee 	}
209fb3fb4f3Stomee     }
210fb3fb4f3Stomee 
211fb3fb4f3Stomee     /**
212fb3fb4f3Stomee      * Gets a string representation of this {@code Flow} instance useful
213fb3fb4f3Stomee      * for logging and not intended for display.  The exact details of
214fb3fb4f3Stomee      * the representation are unspecified and subject to change, but the
215fb3fb4f3Stomee      * following format may be regarded as typical:
216fb3fb4f3Stomee      * <pre><code>
217fb3fb4f3Stomee      * class-name[property1 = value1, property2 = value2]
218fb3fb4f3Stomee      * </code></pre>
219fb3fb4f3Stomee      */
220fb3fb4f3Stomee     public String
toString()221fb3fb4f3Stomee     toString()
222fb3fb4f3Stomee     {
2234ae67516Stomee 	StringBuilder buf = new StringBuilder();
224fb3fb4f3Stomee 	buf.append(Flow.class.getName());
225fb3fb4f3Stomee 	buf.append("[kind = ");
226fb3fb4f3Stomee 	buf.append(kind);
227fb3fb4f3Stomee 	buf.append(", depth = ");
228fb3fb4f3Stomee 	buf.append(depth);
229fb3fb4f3Stomee 	buf.append(']');
230fb3fb4f3Stomee 	return buf.toString();
231fb3fb4f3Stomee     }
232fb3fb4f3Stomee }
233