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 package org.opensolaris.os.dtrace;
27 
28 import java.io.*;
29 import java.beans.*;
30 
31 /**
32  * Triplet of attributes consisting of two stability levels and a
33  * dependency class.  Attributes may vary independently.  They use
34  * labels described in the {@code attributes(7)} man page to help set
35  * expectations for what kinds of changes might occur in different kinds
36  * of future releases.  The D compiler includes features to dynamically
37  * compute the stability levels of D programs you create.  For more
38  * information, refer to the <a
39  * href=http://dtrace.org/guide/chp-stab.html>
40  * <b>Stability</b></a> chapter of the <i>Dynamic Tracing
41  * Guide</i>.
42  * <p>
43  * Immutable.  Supports persistence using {@link java.beans.XMLEncoder}.
44  *
45  * @see Consumer#getProgramInfo(Program program)
46  * @see Consumer#enable(Program program)
47  * @see Consumer#listProbes(ProbeDescription filter)
48  * @see Consumer#listProgramProbes(Program program)
49  *
50  * @author Tom Erickson
51  */
52 public final class InterfaceAttributes implements Serializable {
53     static final long serialVersionUID = -2814012588381562694L;
54 
55     static {
56 	try {
57 	    BeanInfo info = Introspector.getBeanInfo(InterfaceAttributes.class);
58 	    PersistenceDelegate persistenceDelegate =
59 		    new DefaultPersistenceDelegate(
60 		    new String[] {"nameStability", "dataStability",
61 		    "dependencyClass" })
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 		protected Expression
79 		instantiate(Object oldInstance, Encoder out)
80 		{
81 		    InterfaceAttributes attr = (InterfaceAttributes)
82 			    oldInstance;
83 		    return new Expression(oldInstance, oldInstance.getClass(),
84 			    "new", new Object[] {
85 			    attr.getNameStability().name(),
86 			    attr.getDataStability().name(),
87 			    attr.getDependencyClass().name() });
88 		}
89 	    };
90 	    BeanDescriptor d = info.getBeanDescriptor();
91 	    d.setValue("persistenceDelegate", persistenceDelegate);
92 	} catch (IntrospectionException e) {
93 	    e.printStackTrace();
94 	}
95     }
96 
97     /**
98      * Interface stability level.  Assists developers in making risk
99      * assessments when developing scripts and tools based on DTrace by
100      * indicating how likely an interface or DTrace entity is to change
101      * in a future release or patch.
102      */
103     public enum Stability {
104 	/**
105 	 * The interface is private to DTrace itself and represents an
106 	 * implementation detail of DTrace.  Internal interfaces might
107 	 * change in minor or micro releases.
108 	 */
109 	INTERNAL("Internal"),
110 	/**
111 	 * The interface is private to Sun and represents an interface
112 	 * developed for use by other Sun products that is not yet
113 	 * publicly documented for use by customers and ISVs.  Private
114 	 * interfaces might change in minor or micro releases.
115 	 */
116 	PRIVATE("Private"),
117 	/**
118 	 * The interface is supported in the current release but is
119 	 * scheduled to be removed, most likely in a future minor
120 	 * release.  When support of an interface is to be discontinued,
121 	 * Sun will attempt to provide notification before discontinuing
122 	 * the interface.  The D compiler might produce warning messages
123 	 * if you attempt to use an Obsolete interface.
124 	 */
125 	OBSOLETE("Obsolete"),
126 	/**
127 	 * The interface is controlled by an entity other than Sun.  At
128 	 * Sun's discretion, Sun can deliver updated and possibly
129 	 * incompatible versions as part of any release, subject to
130 	 * their availability from the controlling entity.  Sun makes no
131 	 * claims regarding either the source or binary compatibility
132 	 * for External interfaces between two releases.  Applications
133 	 * based on these interfaces might not work in future releases,
134 	 * including patches that contain External interfaces.
135 	 */
136 	EXTERNAL("External"),
137 	/**
138 	 * The interface is provided to give developers early access to
139 	 * new or rapidly changing technology or to an implementation
140 	 * artifact that is essential for observing or debugging system
141 	 * behavior for which a more stable solution is anticipated in
142 	 * the future.  Sun makes no claims about either source of
143 	 * binary compatibility for Unstable interfaces from one minor
144 	 * release to another.
145 	 */
146 	UNSTABLE("Unstable"),
147 	/**
148 	 * The interface might eventually become Standard or Stable but
149 	 * is still in transition.  Sun will make reasonable efforts to
150 	 * ensure compatibility with previous releases as it evolves.
151 	 * When non-upward compatible changes become necessary, they
152 	 * will occur in minor and major releases.  These changes will
153 	 * be avoided in micro releases whenever possible.  If such a
154 	 * change is necessary, it will be documented in the release
155 	 * notes for the affected release, and when feasible, Sun will
156 	 * provide migration aids for binary compatibility and continued
157 	 * D program development.
158 	 */
159 	EVOLVING("Evolving"),
160 	/**
161 	 * The interface is a mature interface under Sun's control.  Sun
162 	 * will try to avoid non-upward-compatible changes to these
163 	 * interfaces, especially in minor or micro releases.  If
164 	 * support of a Stable interface must be discontinued, Sun will
165 	 * attempt to provide notification and the stability level
166 	 * changes to Obsolete.
167 	 */
168 	STABLE("Stable"),
169 	/**
170 	 * The interface complies with an industry standard.  The
171 	 * corresponding documentation for the interface will describe
172 	 * the standard to which the interface conforms.  Standards are
173 	 * typically controlled by a standards development organization,
174 	 * and changes can be made to the interface in accordance with
175 	 * approved changes to the standard.  This stability level can
176 	 * also apply to interfaces that have been adopted (without a
177 	 * formal standard) by an industry convention.  Support is
178 	 * provided for only the specified versions of a standard;
179 	 * support for later versions is not guaranteed.  If the
180 	 * standards development organization approves a
181 	 * non-upward-compatible change to a Standard interface that Sun
182 	 * decides to support, Sun will announce a compatibility and
183 	 * migration strategy.
184 	 */
185 	STANDARD("Standard");
186 
187 	private String s;
188 
189 	private
Stability(String displayName)190 	Stability(String displayName)
191 	{
192 	    s = displayName;
193 	}
194 
195 	/**
196 	 * Overridden to get the default display value.  To
197 	 * internationalize the display value, use {@link
198 	 * java.lang.Enum#name()} instead as a lookup key.
199 	 */
200 	@Override
201 	public String
toString()202 	toString()
203 	{
204 	    return s;
205 	}
206     }
207 
208     /**
209      * Architectural dependency class.  Tells whether an interface is
210      * common to all platforms and processors, or whether the
211      * interface is associated with a particular architecture such as
212      * SPARC processors only.
213      */
214     public enum DependencyClass {
215 	// Note that the compareTo() method depends on the order in
216 	// which the instances are instantiated
217 
218 	/**
219 	 * The interface has an unknown set of architectural dependencies.
220 	 * DTrace does not necessarily know the architectural dependencies of
221 	 * all entities, such as data types defined in the operating system
222 	 * implementation.  The Unknown label is typically applied to interfaces
223 	 * of very low stability for which dependencies cannot be computed.  The
224 	 * interface might not be available when using DTrace on <i>any</i>
225 	 * architecture other than the one you are currently using.
226 	 */
227 	UNKNOWN("Unknown"),
228 	/**
229 	 * The interface is specific to the CPU model of the current
230 	 * system.  You can use the {@code psrinfo(8)} utility's {@code
231 	 * -v} option to display the current CPU model and
232 	 * implementation names.  Interfaces with CPU model dependencies
233 	 * might not be available on other CPU implementations, even if
234 	 * those CPUs export the same instruction set architecture
235 	 * (ISA).  For example, a CPU-dependent interface on an
236 	 * UltraSPARC-III+ microprocessor might not be available on an
237 	 * UltraSPARC-II microprocessor, even though both processors
238 	 * support the SPARC instruction set.
239 	 */
240 	CPU("CPU"),
241 	/**
242 	 * The interface is specific to the hardware platform of the current
243 	 * system.  A platform typically associates a set of system components
244 	 * and architectural characteristics such as a set of supported CPU
245 	 * models with a system name such as <code>SUNW,
246 	 * Ultra-Enterprise-10000</code>.  You can display the current
247 	 * platform name using the {@code uname(1)} {@code -i} option.
248 	 * The interface might not be available on other hardware
249 	 * platforms.
250 	 */
251 	PLATFORM("Platform"),
252 	/**
253 	 * The interface is specific to the hardware platform group of the
254 	 * current system.  A platform group typically associates a set of
255 	 * platforms with related characteristics together under a single name,
256 	 * such as {@code sun4u}.  You can display the current platform
257 	 * group name using the {@code uname(1)} {@code -m} option.  The
258 	 * interface is available on other platforms in the platform
259 	 * group, but might not be available on hardware platforms that
260 	 * are not members of the group.
261 	 */
262 	GROUP("Group"),
263 	/**
264 	 * The interface is specific to the instruction set architecture (ISA)
265 	 * supported by the microprocessor on this system.  The ISA describes a
266 	 * specification for software that can be executed on the
267 	 * microprocessor, including details such as assembly language
268 	 * instructions and registers.  You can display the native
269 	 * instruction sets supported by the system using the {@code
270 	 * isainfo(1)} utility.  The interface might not be supported on
271 	 * systems that do not export any of of the same instruction
272 	 * sets.  For example, an ISA-dependent interface on a
273 	 * SPARC system might not be supported on an x86 system.
274 	 */
275 	ISA("ISA"),
276 	/**
277 	 * The interface is common to all systems regardless of the
278 	 * underlying hardware.  DTrace programs and layered applications that
279 	 * depend only on Common interfaces can be executed and deployed on
280 	 * other systems with the same illumos and DTrace revisions.
281 	 * The majority of DTrace interfaces are Common, so you can use them
282 	 * wherever you use illumos.
283 	 */
284 	COMMON("Common");
285 
286 	private String s;
287 
288 	private
DependencyClass(String displayString)289 	DependencyClass(String displayString)
290 	{
291 	    s = displayString;
292 	}
293 
294 	/**
295 	 * Overridden to get the default display value.  To
296 	 * internationalize the display value, use {@link
297 	 * java.lang.Enum#name()} instead as a lookup key.
298 	 */
299 	@Override
300 	public String
toString()301 	toString()
302 	{
303 	    return s;
304 	}
305     }
306 
307     /** @serial */
308     private Stability nameStability;
309     /** @serial */
310     private Stability dataStability;
311     /** @serial */
312     private DependencyClass dependencyClass;
313 
314     /**
315      * Called by native code.
316      */
317     private
InterfaceAttributes()318     InterfaceAttributes()
319     {
320     }
321 
322     /**
323      * Creates an interface attribute triplet from the given attributes.
324      *
325      * @param nameStabilityAttribute the stability level of the
326      * interface associated with its name in a D program
327      * @param dataStabilityAttribute stability of the data format used
328      * by the interface and any associated data semantics
329      * @param dependencyClassAttribute describes whether the interface
330      * is specific to the current operating platform or microprocessor
331      * @throws NullPointerException if any parameter is {@code null}
332      */
333     public
InterfaceAttributes(Stability nameStabilityAttribute, Stability dataStabilityAttribute, DependencyClass dependencyClassAttribute)334     InterfaceAttributes(Stability nameStabilityAttribute,
335 	    Stability dataStabilityAttribute,
336 	    DependencyClass dependencyClassAttribute)
337     {
338 	nameStability = nameStabilityAttribute;
339 	dataStability = dataStabilityAttribute;
340 	dependencyClass = dependencyClassAttribute;
341 	validate();
342     }
343 
344     /**
345      * Creates an interface attribute triplet from the given attribute
346      * names.  Supports XML persistence.
347      *
348      * @throws NullPointerException if any parameter is {@code null}
349      * @throws IllegalArgumentException if any parameter fails to match
350      * an enumerated stability value
351      */
352     public
InterfaceAttributes(String nameStabilityAttributeName, String dataStabilityAttributeName, String dependencyClassAttributeName)353     InterfaceAttributes(String nameStabilityAttributeName,
354 	    String dataStabilityAttributeName,
355 	    String dependencyClassAttributeName)
356     {
357 	this(Enum.valueOf(Stability.class, nameStabilityAttributeName),
358 		Enum.valueOf(Stability.class, dataStabilityAttributeName),
359 		Enum.valueOf(DependencyClass.class,
360 		dependencyClassAttributeName));
361 	// validate() unnecessary because Enum.valueOf() has already
362 	// thrown the exception
363     }
364 
365     private final void
validate()366     validate()
367     {
368 	if (nameStability == null) {
369 	    throw new NullPointerException("nameStability is null");
370 	}
371 	if (dataStability == null) {
372 	    throw new NullPointerException("dataStability is null");
373 	}
374 	if (dependencyClass == null) {
375 	    throw new NullPointerException("dependencyClass is null");
376 	}
377     }
378 
379     /**
380      * Gets the stability level of an interface associated with its name
381      * as it appears in a D program.  For example, the {@code execname}
382      * D variable is a {@link Stability#STABLE STABLE} name: Sun
383      * guarantees this identifier will continue to be supported in D
384      * programs according to the rules described for Stable interfaces.
385      *
386      * @return the stability level of an interface associated with its
387      * name as it appears in a D program
388      */
389     public Stability
getNameStability()390     getNameStability()
391     {
392 	return nameStability;
393     }
394 
395     /**
396      * Called by native code.
397      */
398     private void
setNameStability(String s)399     setNameStability(String s)
400     {
401 	nameStability = Enum.valueOf(Stability.class, s);
402     }
403 
404     /**
405      * Gets the stability level of the data format used by an interface
406      * and any associated data semantics.  For example, the {@code pid}
407      * D variable is a {@link Stability#STABLE STABLE} interface:
408      * process IDs are a stable concept in illumos, and it is guaranteed
409      * that the {@code pid} variable will be of type {@code pid_t} with
410      * the semantic that it is set to the process ID corresponding to
411      * the thread that fired a given probe in accordance with the rules
412      * described for Stable interfaces.
413      *
414      * @return the stability level of the data format used by an
415      * interface and any associated data semantics.
416      */
417     public Stability
getDataStability()418     getDataStability()
419     {
420 	return dataStability;
421     }
422 
423     /**
424      * Called by native code.
425      */
426     private void
setDataStability(String s)427     setDataStability(String s)
428     {
429 	dataStability = Enum.valueOf(Stability.class, s);
430     }
431 
432     /**
433      * Gets the interface dependency class.
434      *
435      * @return the dependency class describing whether the interface is
436      * specific to the current operating platform or microprocessor
437      */
438     public DependencyClass
getDependencyClass()439     getDependencyClass()
440     {
441 	return dependencyClass;
442     }
443 
444     /**
445      * Called by native code.
446      */
447     private void
setDependencyClass(String s)448     setDependencyClass(String s)
449     {
450 	dependencyClass = Enum.valueOf(DependencyClass.class, s);
451     }
452 
453     /**
454      * Compares the specified object with this attribute triplet for
455      * equality.  Defines equality as having the same attributes.
456      *
457      * @return {@code true} if and only if the specified object is also
458      * an {@code InterfaceAttributes} instance and has all the same
459      * attributes as this instance.
460      */
461     @Override
462     public boolean
equals(Object o)463     equals(Object o)
464     {
465 	if (o == this) {
466 	    return true;
467 	}
468 	if (o instanceof InterfaceAttributes) {
469 	    InterfaceAttributes a = (InterfaceAttributes)o;
470 	    return ((nameStability == a.nameStability) &&
471 		    (dataStability == a.dataStability) &&
472 		    (dependencyClass == a.dependencyClass));
473 	}
474 	return false;
475     }
476 
477     /**
478      * Overridden to ensure that equal {@code InterfaceAttributes}
479      * instances have equal hashcodes.
480      */
481     @Override
482     public int
hashCode()483     hashCode()
484     {
485 	int hash = 17;
486 	hash = (37 * hash) + nameStability.hashCode();
487 	hash = (37 * hash) + dataStability.hashCode();
488 	hash = (37 * hash) + dependencyClass.hashCode();
489 	return hash;
490     }
491 
492     private void
readObject(ObjectInputStream s)493     readObject(ObjectInputStream s)
494             throws IOException, ClassNotFoundException
495     {
496 	s.defaultReadObject();
497 	// Check constructor invariants
498 	try {
499 	    validate();
500 	} catch (Exception e) {
501 	    InvalidObjectException x = new InvalidObjectException(
502 		    e.getMessage());
503 	    x.initCause(e);
504 	    throw x;
505 	}
506     }
507 
508     /**
509      * Gets the string representation of this triplet of interface
510      * attributes.  The format follows the convention described in the
511      * <a href=http://dtrace.org/guide/chp-stab.html#chp-stab-3>
512      * <b>Interface Attributes</b></a> section of the <b>Stability</b>
513      * chapter of the <i>Dynamic Tracing Guide</i>.  The
514      * attributes appear in the following order, separated by slashes:
515      * <pre><code>
516      * <i>name-stability / data-stability / dependency-class</i>
517      * </code></pre>
518      */
519     public String
toString()520     toString()
521     {
522 	StringBuilder buf = new StringBuilder();
523 	buf.append(nameStability);
524 	buf.append(" / ");
525 	buf.append(dataStability);
526 	buf.append(" / ");
527 	buf.append(dependencyClass);
528 	return buf.toString();
529     }
530 }
531