/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * ident "%Z%%M% %I% %E% SMI" */ package org.opensolaris.os.dtrace; import java.util.*; import java.io.*; import java.beans.*; /** * A single key-value pair in a DTrace aggregation. *

* Immutable. Supports persistence using {@link java.beans.XMLEncoder}. * * @see Aggregation * @author Tom Erickson */ public final class AggregationRecord implements Record, Serializable { static final long serialVersionUID = -4367614268579702616L; static { try { BeanInfo info = Introspector.getBeanInfo(AggregationRecord.class); PersistenceDelegate persistenceDelegate = new DefaultPersistenceDelegate( new String[] {"tuple", "value", "ordinal"}) { /* * Need to prevent DefaultPersistenceDelegate from using * overridden equals() method, resulting in a * StackOverFlowError. Revert to PersistenceDelegate * implementation. See * http://forum.java.sun.com/thread.jspa?threadID= * 477019&tstart=135 */ protected boolean mutatesTo(Object oldInstance, Object newInstance) { return (newInstance != null && oldInstance != null && oldInstance.getClass() == newInstance.getClass()); } }; BeanDescriptor d = info.getBeanDescriptor(); d.setValue("persistenceDelegate", persistenceDelegate); } catch (IntrospectionException e) { System.out.println(e); } } /** @serial */ private Tuple tuple; /** @serial */ private AggregationValue value; /** @serial */ private int ordinal; /** * Creates an aggregation record with the given key and value. * Supports XML persistence. * * @see #AggregationRecord(Tuple tupleKey, AggregationValue * recordValue, int n) */ public AggregationRecord(Tuple tupleKey, AggregationValue recordValue) { // // Called by native code, but public to support backwardly // compatible XML encoding. // tuple = tupleKey; value = recordValue; validate(); } /** * Creates an aggregation record with the given key, value, and * ordinal. Supports XML persistence. * * @param tupleKey aggregation tuple, may be empty (see {@link * Tuple#EMPTY}) to indicate that this record's value belongs to an * unkeyed aggregation declared without square brackets, for * example:

		{@code @a = count();}
* @param recordValue aggregated value associated with the given * tuple * @param n ordinal from zero (first) to n-1 (last) within the * {@link Aggregate} containing this record * @throws NullPointerException if the given key or value is * {@code null} * @throws IllegalArgumentException if the given ordinal is negative */ public AggregationRecord(Tuple tupleKey, AggregationValue recordValue, int n) { tuple = tupleKey; value = recordValue; ordinal = n; validate(); } private final void validate() { if (tuple == null) { throw new NullPointerException("key is null"); } if (value == null) { throw new NullPointerException("value is null"); } if (ordinal < 0) { throw new IllegalArgumentException("ordinal is negative"); } } /** * Gets the multi-element key associated with {@link * #getValue()}. * * @return non-null, possibly empty tuple * @see Aggregation#getRecord(Tuple key) */ public Tuple getTuple() { return tuple; } /** * Gets the value associated with {@link #getTuple()}. Values * generated by the DTrace actions {@code count()}, {@code sum()}, * {@code avg()}, {@code min()}, and {@code max()} are of type * {@link Long}. Values generated by the DTrace actions {@code * quantize(}) and {@code lquantize()} are of type {@link * Distribution}. * * @return non-null value keyed to {@link #getTuple()} */ public AggregationValue getValue() { return value; } /** * Gets the ordinal generated when this AggregationRecord was added * to its containing {@link Aggregate} by the native DTrace library, * from zero (first) to n-1 (last). The sequence described by an * aggregate's record ordinals reflects the setting of the {@link * Option#aggsortkey aggsortkey}, {@link Option#aggsortkeypos * aggsortkeypos}, {@link Option#aggsortpos aggsortpos}, and {@link * Option#aggsortrev aggsortrev} DTrace options and matches the way * that the records would be ordered by {@code dtrace(1M)}. * * @return non-negative ordinal from zero (first) to n-1 (last) * within the {@code Aggregate} containing this record * @see Aggregate#getOrderedRecords() */ public int getOrdinal() { return ordinal; } /** * Package level access; called by Aggregate */ void setOrdinal(int n) { if (n < 0) { throw new IllegalArgumentException("ordinal is negative"); } ordinal = n; } /** * Compares the specified object with this aggregation record for * equality. Defines equality as having the same tuple and value. * * @return {@code true} if and only if the specified object is an * {@code AggregationRecord} and both records have equal tuples as * defined by {@link Tuple#equals(Object o)} and equal values as * defined by the implementation of {@link AggregationValue} */ public boolean equals(Object o) { if (o instanceof AggregationRecord) { AggregationRecord r = (AggregationRecord)o; return (tuple.equals(r.tuple) && value.equals(r.value)); } return false; } /** * Overridden to ensure that equal records have equal hash codes. */ @Override public int hashCode() { int hash = 17; hash = (37 * hash) + tuple.hashCode(); hash = (37 * hash) + value.hashCode(); return hash; } private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); // Check class invariants try { validate(); } catch (Exception e) { InvalidObjectException x = new InvalidObjectException( e.getMessage()); x.initCause(e); throw x; } } /** * Gets a string representation of this aggregation record useful * for logging and not intended for display. The exact details of * the representation are unspecified and subject to change, but the * following format may be regarded as typical: *

     * class-name[property1 = value1, property2 = value2]
     * 
*/ @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(AggregationRecord.class.getName()); buf.append("[tuple = "); buf.append(tuple); buf.append(", value = "); buf.append(value); buf.append(']'); return buf.toString(); } }