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