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 /*
23e77b06d2Stomee  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24fb3fb4f3Stomee  * Use is subject to license terms.
25fb3fb4f3Stomee  */
26fb3fb4f3Stomee package org.opensolaris.os.dtrace;
27fb3fb4f3Stomee 
28fb3fb4f3Stomee import java.util.*;
29fb3fb4f3Stomee import java.io.*;
30fb3fb4f3Stomee import java.beans.*;
31fb3fb4f3Stomee 
32fb3fb4f3Stomee /**
33fb3fb4f3Stomee  * A single key-value pair in a DTrace aggregation.
34fb3fb4f3Stomee  * <p>
35fb3fb4f3Stomee  * Immutable.  Supports persistence using {@link java.beans.XMLEncoder}.
36fb3fb4f3Stomee  *
37fb3fb4f3Stomee  * @see Aggregation
38fb3fb4f3Stomee  * @author Tom Erickson
39fb3fb4f3Stomee  */
40fb3fb4f3Stomee public final class AggregationRecord implements Record, Serializable {
41e77b06d2Stomee     static final long serialVersionUID = -4367614268579702616L;
42fb3fb4f3Stomee 
43fb3fb4f3Stomee     static {
44fb3fb4f3Stomee 	try {
45fb3fb4f3Stomee 	    BeanInfo info = Introspector.getBeanInfo(AggregationRecord.class);
46fb3fb4f3Stomee 	    PersistenceDelegate persistenceDelegate =
47fb3fb4f3Stomee 		    new DefaultPersistenceDelegate(
48e77b06d2Stomee 		    new String[] {"tuple", "value", "ordinal"})
49fb3fb4f3Stomee 	    {
50fb3fb4f3Stomee 		/*
51fb3fb4f3Stomee 		 * Need to prevent DefaultPersistenceDelegate from using
52fb3fb4f3Stomee 		 * overridden equals() method, resulting in a
53fb3fb4f3Stomee 		 * StackOverFlowError.  Revert to PersistenceDelegate
54fb3fb4f3Stomee 		 * implementation.  See
55fb3fb4f3Stomee 		 * http://forum.java.sun.com/thread.jspa?threadID=
56fb3fb4f3Stomee 		 * 477019&tstart=135
57fb3fb4f3Stomee 		 */
58fb3fb4f3Stomee 		protected boolean
59fb3fb4f3Stomee 		mutatesTo(Object oldInstance, Object newInstance)
60fb3fb4f3Stomee 		{
61fb3fb4f3Stomee 		    return (newInstance != null && oldInstance != null &&
62fb3fb4f3Stomee 			    oldInstance.getClass() == newInstance.getClass());
63fb3fb4f3Stomee 		}
64fb3fb4f3Stomee 	    };
65fb3fb4f3Stomee 	    BeanDescriptor d = info.getBeanDescriptor();
66fb3fb4f3Stomee 	    d.setValue("persistenceDelegate", persistenceDelegate);
67fb3fb4f3Stomee 	} catch (IntrospectionException e) {
68fb3fb4f3Stomee 	    System.out.println(e);
69fb3fb4f3Stomee 	}
70fb3fb4f3Stomee     }
71fb3fb4f3Stomee 
72fb3fb4f3Stomee     /** @serial */
73fb3fb4f3Stomee     private Tuple tuple;
74fb3fb4f3Stomee     /** @serial */
75fb3fb4f3Stomee     private AggregationValue value;
76e77b06d2Stomee     /** @serial */
77e77b06d2Stomee     private int ordinal;
78e77b06d2Stomee 
79fb3fb4f3Stomee 
80fb3fb4f3Stomee     /**
81fb3fb4f3Stomee      * Creates an aggregation record with the given key and value.
82fb3fb4f3Stomee      * Supports XML persistence.
83fb3fb4f3Stomee      *
84e77b06d2Stomee      * @see #AggregationRecord(Tuple tupleKey, AggregationValue
85e77b06d2Stomee      * recordValue, int n)
86e77b06d2Stomee      */
87e77b06d2Stomee     public
AggregationRecord(Tuple tupleKey, AggregationValue recordValue)88e77b06d2Stomee     AggregationRecord(Tuple tupleKey, AggregationValue recordValue)
89e77b06d2Stomee     {
90e77b06d2Stomee     //
91e77b06d2Stomee     // Called by native code, but public to support backwardly
92e77b06d2Stomee     // compatible XML encoding.
93e77b06d2Stomee     //
94e77b06d2Stomee 	tuple = tupleKey;
95e77b06d2Stomee 	value = recordValue;
96e77b06d2Stomee 	validate();
97e77b06d2Stomee     }
98e77b06d2Stomee 
99e77b06d2Stomee     /**
100e77b06d2Stomee      * Creates an aggregation record with the given key, value, and
101e77b06d2Stomee      * ordinal. Supports XML persistence.
102e77b06d2Stomee      *
103fb3fb4f3Stomee      * @param tupleKey aggregation tuple, may be empty (see {@link
104fb3fb4f3Stomee      * Tuple#EMPTY}) to indicate that this record's value belongs to an
105fb3fb4f3Stomee      * unkeyed aggregation declared without square brackets, for
106fb3fb4f3Stomee      * example: <pre>		{@code @a = count();}</pre>
107fb3fb4f3Stomee      * @param recordValue aggregated value associated with the given
108fb3fb4f3Stomee      * tuple
109e77b06d2Stomee      * @param n ordinal from zero (first) to n-1 (last) within the
110e77b06d2Stomee      * {@link Aggregate} containing this record
111fb3fb4f3Stomee      * @throws NullPointerException if the given key or value is
112fb3fb4f3Stomee      * {@code null}
113e77b06d2Stomee      * @throws IllegalArgumentException if the given ordinal is negative
114fb3fb4f3Stomee      */
115fb3fb4f3Stomee     public
AggregationRecord(Tuple tupleKey, AggregationValue recordValue, int n)116e77b06d2Stomee     AggregationRecord(Tuple tupleKey, AggregationValue recordValue, int n)
117fb3fb4f3Stomee     {
118fb3fb4f3Stomee 	tuple = tupleKey;
119fb3fb4f3Stomee 	value = recordValue;
120e77b06d2Stomee 	ordinal = n;
121fb3fb4f3Stomee 	validate();
122fb3fb4f3Stomee     }
123fb3fb4f3Stomee 
12491cfa10aStomee     private final void
validate()125fb3fb4f3Stomee     validate()
126fb3fb4f3Stomee     {
127fb3fb4f3Stomee 	if (tuple == null) {
128fb3fb4f3Stomee 	    throw new NullPointerException("key is null");
129fb3fb4f3Stomee 	}
130fb3fb4f3Stomee 	if (value == null) {
131fb3fb4f3Stomee 	    throw new NullPointerException("value is null");
132fb3fb4f3Stomee 	}
133e77b06d2Stomee 	if (ordinal < 0) {
134e77b06d2Stomee 	    throw new IllegalArgumentException("ordinal is negative");
135e77b06d2Stomee 	}
136fb3fb4f3Stomee     }
137fb3fb4f3Stomee 
138fb3fb4f3Stomee     /**
139fb3fb4f3Stomee      * Gets the multi-element key associated with {@link
140fb3fb4f3Stomee      * #getValue()}.
141fb3fb4f3Stomee      *
142fb3fb4f3Stomee      * @return non-null, possibly empty tuple
143fb3fb4f3Stomee      * @see Aggregation#getRecord(Tuple key)
144fb3fb4f3Stomee      */
145fb3fb4f3Stomee     public Tuple
getTuple()146fb3fb4f3Stomee     getTuple()
147fb3fb4f3Stomee     {
148fb3fb4f3Stomee 	return tuple;
149fb3fb4f3Stomee     }
150fb3fb4f3Stomee 
151fb3fb4f3Stomee     /**
152fb3fb4f3Stomee      * Gets the value associated with {@link #getTuple()}.  Values
153fb3fb4f3Stomee      * generated by the DTrace actions {@code count()}, {@code sum()},
154fb3fb4f3Stomee      * {@code avg()}, {@code min()}, and {@code max()} are of type
155fb3fb4f3Stomee      * {@link Long}.  Values generated by the DTrace actions {@code
156fb3fb4f3Stomee      * quantize(}) and {@code lquantize()} are of type {@link
157fb3fb4f3Stomee      * Distribution}.
158fb3fb4f3Stomee      *
159fb3fb4f3Stomee      * @return non-null value keyed to {@link #getTuple()}
160fb3fb4f3Stomee      */
161fb3fb4f3Stomee     public AggregationValue
getValue()162fb3fb4f3Stomee     getValue()
163fb3fb4f3Stomee     {
164fb3fb4f3Stomee 	return value;
165fb3fb4f3Stomee     }
166fb3fb4f3Stomee 
167e77b06d2Stomee     /**
168e77b06d2Stomee      * Gets the ordinal generated when this AggregationRecord was added
169e77b06d2Stomee      * to its containing {@link Aggregate} by the native DTrace library,
170e77b06d2Stomee      * from zero (first) to n-1 (last). The sequence described by an
171e77b06d2Stomee      * aggregate's record ordinals reflects the setting of the {@link
172e77b06d2Stomee      * Option#aggsortkey aggsortkey}, {@link Option#aggsortkeypos
173e77b06d2Stomee      * aggsortkeypos}, {@link Option#aggsortpos aggsortpos}, and {@link
174e77b06d2Stomee      * Option#aggsortrev aggsortrev} DTrace options and matches the way
175*bbf21555SRichard Lowe      * that the records would be ordered by {@code dtrace(8)}.
176e77b06d2Stomee      *
177e77b06d2Stomee      * @return non-negative ordinal from zero (first) to n-1 (last)
178e77b06d2Stomee      * within the {@code Aggregate} containing this record
179e77b06d2Stomee      * @see Aggregate#getOrderedRecords()
180e77b06d2Stomee      */
181e77b06d2Stomee     public int
getOrdinal()182e77b06d2Stomee     getOrdinal()
183e77b06d2Stomee     {
184e77b06d2Stomee 	return ordinal;
185e77b06d2Stomee     }
186e77b06d2Stomee 
187e77b06d2Stomee     /**
188e77b06d2Stomee      * Package level access; called by Aggregate
189e77b06d2Stomee      */
190e77b06d2Stomee     void
setOrdinal(int n)191e77b06d2Stomee     setOrdinal(int n)
192e77b06d2Stomee     {
193e77b06d2Stomee 	if (n < 0) {
194e77b06d2Stomee 	    throw new IllegalArgumentException("ordinal is negative");
195e77b06d2Stomee 	}
196e77b06d2Stomee 	ordinal = n;
197e77b06d2Stomee     }
198e77b06d2Stomee 
199fb3fb4f3Stomee     /**
200fb3fb4f3Stomee      * Compares the specified object with this aggregation record for
201fb3fb4f3Stomee      * equality.  Defines equality as having the same tuple and value.
202fb3fb4f3Stomee      *
203fb3fb4f3Stomee      * @return {@code true} if and only if the specified object is an
204fb3fb4f3Stomee      * {@code AggregationRecord} and both records have equal tuples as
205fb3fb4f3Stomee      * defined by {@link Tuple#equals(Object o)} and equal values as
206fb3fb4f3Stomee      * defined by the implementation of {@link AggregationValue}
207fb3fb4f3Stomee      */
208fb3fb4f3Stomee     public boolean
equals(Object o)209fb3fb4f3Stomee     equals(Object o)
210fb3fb4f3Stomee     {
211fb3fb4f3Stomee 	if (o instanceof AggregationRecord) {
212fb3fb4f3Stomee 	    AggregationRecord r = (AggregationRecord)o;
213fb3fb4f3Stomee 	    return (tuple.equals(r.tuple) &&
214fb3fb4f3Stomee 		    value.equals(r.value));
215fb3fb4f3Stomee 	}
216fb3fb4f3Stomee 	return false;
217fb3fb4f3Stomee     }
218fb3fb4f3Stomee 
219fb3fb4f3Stomee     /**
220fb3fb4f3Stomee      * Overridden to ensure that equal records have equal hash codes.
221fb3fb4f3Stomee      */
222fb3fb4f3Stomee     @Override
223fb3fb4f3Stomee     public int
hashCode()224fb3fb4f3Stomee     hashCode()
225fb3fb4f3Stomee     {
226fb3fb4f3Stomee 	int hash = 17;
227fb3fb4f3Stomee 	hash = (37 * hash) + tuple.hashCode();
228fb3fb4f3Stomee 	hash = (37 * hash) + value.hashCode();
229fb3fb4f3Stomee 	return hash;
230fb3fb4f3Stomee     }
231fb3fb4f3Stomee 
232fb3fb4f3Stomee     private void
readObject(ObjectInputStream s)233fb3fb4f3Stomee     readObject(ObjectInputStream s)
234fb3fb4f3Stomee             throws IOException, ClassNotFoundException
235fb3fb4f3Stomee     {
236fb3fb4f3Stomee 	s.defaultReadObject();
237fb3fb4f3Stomee 	// Check class invariants
238fb3fb4f3Stomee 	try {
239fb3fb4f3Stomee 	    validate();
240fb3fb4f3Stomee 	} catch (Exception e) {
2414ae67516Stomee 	    InvalidObjectException x = new InvalidObjectException(
2424ae67516Stomee 		    e.getMessage());
2434ae67516Stomee 	    x.initCause(e);
2444ae67516Stomee 	    throw x;
245fb3fb4f3Stomee 	}
246fb3fb4f3Stomee     }
247fb3fb4f3Stomee 
248fb3fb4f3Stomee     /**
249fb3fb4f3Stomee      * Gets a string representation of this aggregation record useful
250fb3fb4f3Stomee      * for logging and not intended for display.  The exact details of
251fb3fb4f3Stomee      * the representation are unspecified and subject to change, but the
252fb3fb4f3Stomee      * following format may be regarded as typical:
253fb3fb4f3Stomee      * <pre><code>
254fb3fb4f3Stomee      * class-name[property1 = value1, property2 = value2]
255fb3fb4f3Stomee      * </code></pre>
256fb3fb4f3Stomee      */
257fb3fb4f3Stomee     @Override
258fb3fb4f3Stomee     public String
toString()259fb3fb4f3Stomee     toString()
260fb3fb4f3Stomee     {
2614ae67516Stomee 	StringBuilder buf = new StringBuilder();
262fb3fb4f3Stomee 	buf.append(AggregationRecord.class.getName());
263fb3fb4f3Stomee 	buf.append("[tuple = ");
264fb3fb4f3Stomee 	buf.append(tuple);
265fb3fb4f3Stomee 	buf.append(", value = ");
266fb3fb4f3Stomee 	buf.append(value);
267fb3fb4f3Stomee 	buf.append(']');
268fb3fb4f3Stomee 	return buf.toString();
269fb3fb4f3Stomee     }
270fb3fb4f3Stomee }
271