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