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