PrintaRecord.java revision 91cfa10a8e55050a5103c4b2e83b0bf8d783a7cb
03831d35f7499c87d51205817c93e9a8d42c4baestevel/*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * CDDL HEADER START
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * The contents of this file are subject to the terms of the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Common Development and Distribution License (the "License").
03831d35f7499c87d51205817c93e9a8d42c4baestevel * You may not use this file except in compliance with the License.
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
03831d35f7499c87d51205817c93e9a8d42c4baestevel * or http://www.opensolaris.org/os/licensing.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * See the License for the specific language governing permissions
03831d35f7499c87d51205817c93e9a8d42c4baestevel * and limitations under the License.
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * When distributing Covered Code, include this CDDL HEADER in each
03831d35f7499c87d51205817c93e9a8d42c4baestevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * If applicable, add the following below this CDDL HEADER, with the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * fields enclosed by brackets "[]" replaced with your own identifying
03831d35f7499c87d51205817c93e9a8d42c4baestevel * information: Portions Copyright [yyyy] [name of copyright owner]
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * CDDL HEADER END
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Use is subject to license terms.
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * ident "%Z%%M% %I% %E% SMI"
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevelpackage org.opensolaris.os.dtrace;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelimport java.io.*;
03831d35f7499c87d51205817c93e9a8d42c4baestevelimport java.beans.*;
03831d35f7499c87d51205817c93e9a8d42c4baestevelimport java.util.*;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/**
03831d35f7499c87d51205817c93e9a8d42c4baestevel * A record generated by the DTrace {@code printa()} action. Lists the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * aggregations passed to {@code printa()} and records the formatted
03831d35f7499c87d51205817c93e9a8d42c4baestevel * output associated with each {@link Tuple}. If multiple aggregations
03831d35f7499c87d51205817c93e9a8d42c4baestevel * were passed to the {@code printa()} action that generated this
03831d35f7499c87d51205817c93e9a8d42c4baestevel * record, then the DTrace library tabulates the output, using a default
03831d35f7499c87d51205817c93e9a8d42c4baestevel * format if no format string was specified. By default, the output
03831d35f7499c87d51205817c93e9a8d42c4baestevel * string associated with a given {@code Tuple} includes a value from
03831d35f7499c87d51205817c93e9a8d42c4baestevel * each aggregation, or zero wherever an aggregation has no value
03831d35f7499c87d51205817c93e9a8d42c4baestevel * associated with that {@code Tuple}. For example, the D statements
03831d35f7499c87d51205817c93e9a8d42c4baestevel * <pre><code>
03831d35f7499c87d51205817c93e9a8d42c4baestevel * &#64;a[123] = sum(1);
03831d35f7499c87d51205817c93e9a8d42c4baestevel * &#64;b[456] = sum(2);
03831d35f7499c87d51205817c93e9a8d42c4baestevel * printa(&#64;a, &#64;b, &#64;c);
03831d35f7499c87d51205817c93e9a8d42c4baestevel * </code></pre>
03831d35f7499c87d51205817c93e9a8d42c4baestevel * produce output for the tuples "123" and "456" similar to the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * following:
03831d35f7499c87d51205817c93e9a8d42c4baestevel * <pre><code>
03831d35f7499c87d51205817c93e9a8d42c4baestevel * 123 1 0 0
03831d35f7499c87d51205817c93e9a8d42c4baestevel * 456 0 2 0
03831d35f7499c87d51205817c93e9a8d42c4baestevel * </code></pre>
03831d35f7499c87d51205817c93e9a8d42c4baestevel * The first column after the tuple contains values from {@code @a},
03831d35f7499c87d51205817c93e9a8d42c4baestevel * the next column contains values from {@code @b}, and the last
03831d35f7499c87d51205817c93e9a8d42c4baestevel * column contains zeros because {@code @c} has neither a value
03831d35f7499c87d51205817c93e9a8d42c4baestevel * associated with "123" nor a value associated with "456".
03831d35f7499c87d51205817c93e9a8d42c4baestevel * <p>
03831d35f7499c87d51205817c93e9a8d42c4baestevel * If a format string is passed to {@code printa()}, it may limit the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * aggregation data available in this record. For example, if the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * format string specifies a value placeholder for only one of two
03831d35f7499c87d51205817c93e9a8d42c4baestevel * aggregations passed to {@code printa()}, then the resulting {@code
03831d35f7499c87d51205817c93e9a8d42c4baestevel * PrintaRecord} will contain only one {@code Aggregation}. If no value
03831d35f7499c87d51205817c93e9a8d42c4baestevel * placeholder is specified, or if the aggregation tuple is not
03831d35f7499c87d51205817c93e9a8d42c4baestevel * completely specified, the resulting {@code PrintaRecord} will contain
03831d35f7499c87d51205817c93e9a8d42c4baestevel * no aggregation data. However, the formatted output generated by the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * DTrace library is available in all cases. For details about
03831d35f7499c87d51205817c93e9a8d42c4baestevel * {@code printa()} format strings, see the <a
03831d35f7499c87d51205817c93e9a8d42c4baestevel * href=http://docs.sun.com/app/docs/doc/817-6223/6mlkidli3?a=view>
03831d35f7499c87d51205817c93e9a8d42c4baestevel * <b>{@code printa()}</b></a> section of the <b>Output
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Formatting</b> chapter of the <i>Solaris Dynamic Tracing Guide</i>.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * <p>
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Immutable. Supports persistence using {@link java.beans.XMLEncoder}.
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * @author Tom Erickson
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevelpublic final class PrintaRecord implements Record, Serializable {
03831d35f7499c87d51205817c93e9a8d42c4baestevel static final long serialVersionUID = -4174277639915895694L;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel static {
03831d35f7499c87d51205817c93e9a8d42c4baestevel try {
03831d35f7499c87d51205817c93e9a8d42c4baestevel BeanInfo info = Introspector.getBeanInfo(PrintaRecord.class);
03831d35f7499c87d51205817c93e9a8d42c4baestevel PersistenceDelegate persistenceDelegate =
03831d35f7499c87d51205817c93e9a8d42c4baestevel new DefaultPersistenceDelegate(
03831d35f7499c87d51205817c93e9a8d42c4baestevel new String[] {"snaptime", "aggregations",
03831d35f7499c87d51205817c93e9a8d42c4baestevel "formattedStrings", "tuples", "output"});
03831d35f7499c87d51205817c93e9a8d42c4baestevel BeanDescriptor d = info.getBeanDescriptor();
03831d35f7499c87d51205817c93e9a8d42c4baestevel d.setValue("persistenceDelegate", persistenceDelegate);
03831d35f7499c87d51205817c93e9a8d42c4baestevel } catch (IntrospectionException e) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel System.out.println(e);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /** @serial */
03831d35f7499c87d51205817c93e9a8d42c4baestevel private final long snaptime;
03831d35f7499c87d51205817c93e9a8d42c4baestevel /** @serial */
03831d35f7499c87d51205817c93e9a8d42c4baestevel private List <Aggregation> aggregations;
03831d35f7499c87d51205817c93e9a8d42c4baestevel /** @serial */
03831d35f7499c87d51205817c93e9a8d42c4baestevel private Map <Tuple, String> formattedStrings;
03831d35f7499c87d51205817c93e9a8d42c4baestevel /** @serial */
03831d35f7499c87d51205817c93e9a8d42c4baestevel private List <Tuple> tuples;
03831d35f7499c87d51205817c93e9a8d42c4baestevel private transient StringBuffer outputBuffer;
03831d35f7499c87d51205817c93e9a8d42c4baestevel private transient String output;
03831d35f7499c87d51205817c93e9a8d42c4baestevel private transient boolean formatted;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /**
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Package level access, called by ProbeData.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel PrintaRecord(long snaptimeNanos, boolean isFormatString)
03831d35f7499c87d51205817c93e9a8d42c4baestevel {
03831d35f7499c87d51205817c93e9a8d42c4baestevel snaptime = snaptimeNanos;
03831d35f7499c87d51205817c93e9a8d42c4baestevel aggregations = new ArrayList <Aggregation> ();
03831d35f7499c87d51205817c93e9a8d42c4baestevel formattedStrings = new HashMap <Tuple, String> ();
03831d35f7499c87d51205817c93e9a8d42c4baestevel tuples = new ArrayList <Tuple> ();
03831d35f7499c87d51205817c93e9a8d42c4baestevel outputBuffer = new StringBuffer();
03831d35f7499c87d51205817c93e9a8d42c4baestevel formatted = isFormatString;
03831d35f7499c87d51205817c93e9a8d42c4baestevel validate();
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /**
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Creates a record with the given snaptime, aggregations, and
03831d35f7499c87d51205817c93e9a8d42c4baestevel * formatted output.
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * @param snaptimeNanos nanosecond timestamp of the snapshot used
03831d35f7499c87d51205817c93e9a8d42c4baestevel * to create this {@code printa()} record
03831d35f7499c87d51205817c93e9a8d42c4baestevel * @param aggs aggregations passed to the {@code printa()} action
03831d35f7499c87d51205817c93e9a8d42c4baestevel * that generated this record
03831d35f7499c87d51205817c93e9a8d42c4baestevel * @param formattedOutput the formatted output, if any, associated
03831d35f7499c87d51205817c93e9a8d42c4baestevel * with each {@code Tuple} occurring in the aggregations belonging
03831d35f7499c87d51205817c93e9a8d42c4baestevel * to this record, one formatted string per {@code Tuple}, or an
03831d35f7499c87d51205817c93e9a8d42c4baestevel * empty or {@code null} map if an incomplete {@code printa()}
03831d35f7499c87d51205817c93e9a8d42c4baestevel * format string caused aggregation tuples to be omitted from this
03831d35f7499c87d51205817c93e9a8d42c4baestevel * record
03831d35f7499c87d51205817c93e9a8d42c4baestevel * @param orderedTuples list of aggregation tuples in the same order
03831d35f7499c87d51205817c93e9a8d42c4baestevel * generated by the native DTrace library (determined by the various
03831d35f7499c87d51205817c93e9a8d42c4baestevel * "aggsort" options such as {@link Option#aggsortkey})
03831d35f7499c87d51205817c93e9a8d42c4baestevel * @param formattedOutputString {@code printa()} formatted string
03831d35f7499c87d51205817c93e9a8d42c4baestevel * output in the same order generated by the native DTrace library
03831d35f7499c87d51205817c93e9a8d42c4baestevel * (determined by the various "aggsort" options such as
03831d35f7499c87d51205817c93e9a8d42c4baestevel * {@link Option#aggsortkey})
03831d35f7499c87d51205817c93e9a8d42c4baestevel * @throws NullPointerException if the given collection of
03831d35f7499c87d51205817c93e9a8d42c4baestevel * aggregations is {@code null}, or if the given ordered lists of
03831d35f7499c87d51205817c93e9a8d42c4baestevel * tuples or formatted strings are {@code null}
03831d35f7499c87d51205817c93e9a8d42c4baestevel * @throws IllegalArgumentException if the given snaptime is
03831d35f7499c87d51205817c93e9a8d42c4baestevel * negative
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel public
03831d35f7499c87d51205817c93e9a8d42c4baestevel PrintaRecord(long snaptimeNanos, Collection <Aggregation> aggs,
03831d35f7499c87d51205817c93e9a8d42c4baestevel Map <Tuple, String> formattedOutput,
03831d35f7499c87d51205817c93e9a8d42c4baestevel List <Tuple> orderedTuples,
03831d35f7499c87d51205817c93e9a8d42c4baestevel String formattedOutputString)
03831d35f7499c87d51205817c93e9a8d42c4baestevel {
03831d35f7499c87d51205817c93e9a8d42c4baestevel snaptime = snaptimeNanos;
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (aggs != null) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel aggregations = new ArrayList <Aggregation> (aggs.size());
03831d35f7499c87d51205817c93e9a8d42c4baestevel aggregations.addAll(aggs);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (formattedOutput != null) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel formattedStrings = new HashMap <Tuple, String>
03831d35f7499c87d51205817c93e9a8d42c4baestevel (formattedOutput);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (orderedTuples != null) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel tuples = new ArrayList <Tuple> (orderedTuples.size());
03831d35f7499c87d51205817c93e9a8d42c4baestevel tuples.addAll(orderedTuples);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel output = formattedOutputString;
03831d35f7499c87d51205817c93e9a8d42c4baestevel validate();
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel private final void
03831d35f7499c87d51205817c93e9a8d42c4baestevel validate()
03831d35f7499c87d51205817c93e9a8d42c4baestevel {
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (snaptime < 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel throw new IllegalArgumentException("snaptime is negative");
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (aggregations == null) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel throw new NullPointerException("aggregations list is null");
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel Aggregation a;
03831d35f7499c87d51205817c93e9a8d42c4baestevel for (int i = 0, len = aggregations.size(); i < len; ++i) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel a = aggregations.get(i);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (a == null) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel throw new NullPointerException(
03831d35f7499c87d51205817c93e9a8d42c4baestevel "null aggregation at index " + i);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (tuples == null) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel throw new NullPointerException("ordered tuple list is null");
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (output == null && outputBuffer == null) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel throw new NullPointerException("formatted output is null");
}
}
/**
* Gets the nanosecond timestamp of the aggregate snapshot used to
* create this {@code printa()} record.
*
* @return nanosecond timestamp
*/
public long
getSnaptime()
{
return snaptime;
}
private Aggregation
getAggregationImpl(String name)
{
if (name == null) {
return null;
}
for (Aggregation a : aggregations) {
if (name.equals(a.getName())) {
return a;
}
}
return null;
}
/**
* Gets the named aggregation.
*
* @return the named aggregation passed to {@code printa()}, or
* {@code null} if the named aggregation is not passed to {@code
* printa()}, or if it is omitted due to an incomplete {@code
* printa()} format string, or if it is empty (a future release of
* this API may represent an empty DTrace aggregation as a non-null
* {@code Aggregation} with no records; users of this API should not
* rely on a non-null return value to indicate a non-zero record
* count)
*/
public Aggregation
getAggregation(String name)
{
name = Aggregate.filterUnnamedAggregationName(name);
return getAggregationImpl(name);
}
/**
* Gets a list of the aggregations passed to the {@code printa()}
* action that generated this record. The returned list is a copy,
* and modifying it has no effect on this record. Supports XML
* persistence.
*
* @return non-null, possibly empty list of aggregations belonging
* to this record (empty aggregations are excluded)
*/
public List <Aggregation>
getAggregations()
{
return new ArrayList <Aggregation> (aggregations);
}
/**
* Gets the formatted string, if any, associated with the given
* aggregation tuple.
*
* @param key aggregation tuple
* @return the formatted string associated with the given
* aggregation tuple, or {@code null} if the given tuple does not
* exist in the aggregations belonging to this record or if it
* is omitted from this record due to an incomplete {@code printa()}
* format string
* @see #getFormattedStrings()
* @see #getOutput()
*/
public String
getFormattedString(Tuple key)
{
if (formattedStrings == null) {
return null;
}
return formattedStrings.get(key);
}
/**
* Gets the formatted output, if any, associated with each {@code
* Tuple} occurring in the aggregations belonging to this record,
* one formatted string per {@code Tuple}. Gets an empty map if
* aggregation tuples are omitted from this record due to an
* incomplete {@code printa()} format string. The returned map is a
* copy and modifying it has no effect on this record. Supports XML
* persistence.
*
* @return a map of aggregation tuples and their associated
* formatted output strings, empty if aggregation tuples are omitted
* from this record due to an incomplete {@code printa(}) format
* string
* @see #getFormattedString(Tuple key)
* @see #getOutput()
*/
public Map <Tuple, String>
getFormattedStrings()
{
if (formattedStrings == null) {
return new HashMap <Tuple, String> ();
}
return new HashMap <Tuple, String> (formattedStrings);
}
/**
* Gets an ordered list of this record's aggregation tuples. The
* returned list is a copy, and modifying it has no effect on this
* record. Supports XML persistence.
*
* @return a non-null list of this record's aggregation tuples in
* the order they were generated by the native DTrace library, as
* determined by the {@link Option#aggsortkey}, {@link
* Option#aggsortrev}, {@link Option#aggsortpos}, and {@link
* Option#aggsortkeypos} options
*/
public List <Tuple>
getTuples()
{
return new ArrayList <Tuple> (tuples);
}
/**
* Gets this record's formatted output. Supports XML persistence.
*
* @return non-null formatted output in the order generated by the
* native DTrace library, as determined by the {@link
* Option#aggsortkey}, {@link Option#aggsortrev}, {@link
* Option#aggsortpos}, and {@link Option#aggsortkeypos} options
*/
public String
getOutput()
{
if (output == null) {
output = outputBuffer.toString();
outputBuffer = null;
if ((output.length() == 0) && !formatted) {
output = "\n";
}
}
return output;
}
/**
* Package level access, called by ProbeData.
*
* @throws NullPointerException if aggregationName is null
* @throws IllegalStateException if this PrintaRecord has an
* aggregation matching the given name and it already has an
* AggregationRecord with the same tuple key as the given record.
*/
void
addRecord(String aggregationName, long aggid, AggregationRecord record)
{
if (formattedStrings == null) {
// printa() format string does not completely specify tuple
return;
}
aggregationName = Aggregate.filterUnnamedAggregationName(
aggregationName);
Aggregation aggregation = getAggregationImpl(aggregationName);
if (aggregation == null) {
aggregation = new Aggregation(aggregationName, aggid);
aggregations.add(aggregation);
}
try {
aggregation.addRecord(record);
} catch (IllegalArgumentException e) {
Map <Tuple, AggregationRecord> map = aggregation.asMap();
AggregationRecord r = map.get(record.getTuple());
//
// The printa() format string may specify the value of the
// aggregating action multiple times. While that changes
// the resulting formatted string associated with the tuple,
// we ignore the attempt to add the redundant record to the
// aggregation.
//
if (!r.equals(record)) {
throw e;
}
}
}
//
// Called from native code when the tuple is not completely
// specified in the printa() format string.
//
void
invalidate()
{
formattedStrings = null;
aggregations.clear();
tuples.clear();
}
void
addFormattedString(Tuple tuple, String formattedString)
{
if (tuple != null && formattedStrings != null) {
if (formattedStrings.containsKey(tuple)) {
throw new IllegalArgumentException("A formatted string " +
"for tuple " + tuple + " already exists.");
} else {
formattedStrings.put(tuple, formattedString);
tuples.add(tuple);
}
}
outputBuffer.append(formattedString);
}
/**
* Serialize this {@code PrintaRecord} instance.
*
* @serialData Serialized fields are emitted, followed by the
* formatted output string.
*/
private void
writeObject(ObjectOutputStream s) throws IOException
{
s.defaultWriteObject();
if (output == null) {
s.writeObject(outputBuffer.toString());
} else {
s.writeObject(output);
}
}
private void
readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException
{
s.defaultReadObject();
output = (String)s.readObject();
// make defensive copy
if (aggregations != null) {
List <Aggregation> copy = new ArrayList <Aggregation>
(aggregations.size());
copy.addAll(aggregations);
aggregations = copy;
}
if (formattedStrings != null) {
formattedStrings = new HashMap <Tuple, String> (formattedStrings);
}
if (tuples != null) {
List <Tuple> copy = new ArrayList <Tuple> (tuples.size());
copy.addAll(tuples);
tuples = copy;
}
// check constructor invariants only after defensize copy
try {
validate();
} catch (Exception e) {
throw new InvalidObjectException(e.getMessage());
}
}
/**
* Gets a string representation of this instance 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:
* <pre><code>
* class-name[property1 = value1, property2 = value2]
* </code></pre>
*/
public String
toString()
{
StringBuffer buf = new StringBuffer();
buf.append(PrintaRecord.class.getName());
buf.append("[snaptime = ");
buf.append(snaptime);
buf.append(", aggregations = ");
buf.append(aggregations);
buf.append(", formattedStrings = ");
buf.append(formattedStrings);
buf.append(", tuples = ");
buf.append(tuples);
buf.append(", output = ");
buf.append(getOutput());
buf.append(']');
return buf.toString();
}
}