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