/* * 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. */ package org.opensolaris.os.dtrace; import java.io.*; import java.beans.*; import java.util.*; /** * A formatted string generated by the DTrace {@code printf()} action. *

* Immutable. Supports persistence using {@link java.beans.XMLEncoder}. * * @author Tom Erickson */ public final class PrintfRecord implements Record, Serializable, Comparable { static final long serialVersionUID = 727237355963977675L; static { try { BeanInfo info = Introspector.getBeanInfo(PrintfRecord.class); PersistenceDelegate persistenceDelegate = new DefaultPersistenceDelegate( new String[] {"records", "formattedString"}) { /* * 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 List records; /** @serial */ private String formattedString; // package-level access, called by ProbeData PrintfRecord() { records = new ArrayList (); } /** * Creates a record with the unformatted elements passed to the * DTrace {@code printf()} action and the resulting formatted * output. Supports XML persistence. * * @param v variable number of unformatted elements passed to the * DTrace {@code printf()} action * @param s formatted {@code printf()} output * @throws NullPointerException if the given list or any of its * elements is {@code null}, or if the given formatted string is * {@code null} */ public PrintfRecord(List v, String s) { formattedString = s; records = new ArrayList (v.size()); records.addAll(v); validate(); } private final void validate() { if (formattedString == null) { throw new NullPointerException("formatted string is null"); } if (records == null) { throw new NullPointerException("list of format args is null"); } for (ValueRecord r : records) { if (r == null) { throw new NullPointerException("format arg is null"); } } } /** * Called by ProbeData code to populate record list. * * @throws NullPointerException if o is null */ void addUnformattedElement(ScalarRecord rec) { records.add(rec); } /** * Gets the formatted string output of the DTrace {@code printf()} * action. * * @return non-null formatted string output of the DTrace {@code * printf()} action */ public String getFormattedString() { return formattedString; } /** * Package level access; called by ProbeData */ void setFormattedString(String s) { if (s == null) { throw new NullPointerException("formatted string is null"); } formattedString = s; } /** * Gets the unformatted elements passed to the DTrace {@code * printf()} action after the format string. * * @return non-null, unmodifiable list of unformatted elements * passed to the DTrace {@code printf()} action that generated this * record, in the order they appear in the argument list after the * format string */ public List getRecords() { return Collections. unmodifiableList(records); } /** * Gets the number of DTrace {@code printf()} unformatted elements * (arguments following the format string). For example, the * following action *


     *    printf("%s %d\n", "cat", 9);
     * 
* generates a {@code PrintfRecord} with a record count of two. * * @return the number of unformatted elements passed to the DTrace * {@code printf()} action that generated this record. */ public int getRecordCount() { return records.size(); } /** * Gets the unformatted element passed to the DTrace {@code * printf()} action at the given offset in the {@code printf()} * argument list after the format string, starting at offset zero * for the first unformatted element. * * @return non-null record representing the unformatted {@code * printf()} element at the given index (using the same order that * they appear in the {@code printf()} argument list) * @throws ArrayIndexOutOfBoundsException if the given index is * out of range (index < 0 || index >= getRecordCount()) */ public ValueRecord getRecord(int i) { return records.get(i); } /** * Compares the specified object with this {@code PrintfRecord} for * equality. Returns {@code true} if and only if the specified * object is also a {@code PrintfRecord} and both records have the * same formatted string and underlying data elements. * * @return {@code true} if and only if the specified object is also * a {@code PrintfRecord} and both the formatted strings and * the underlying data elements of both records are equal */ @Override public boolean equals(Object o) { if (o instanceof PrintfRecord) { PrintfRecord r = (PrintfRecord)o; return (records.equals(r.records) && formattedString.equals(r.formattedString)); } return false; } /** * Overridden to ensure that equal instances have equal hash codes. */ @Override public int hashCode() { int hash = 17; hash = (37 * hash) + records.hashCode(); hash = (37 * hash) + formattedString.hashCode(); return hash; } /** * Compares the formatted string value of this record with that of * the given record. Note that ordering {@code printf} records by * their string values is incompatible with {@link #equals(Object o) * equals()}, which also checks the underlying data elements for * equality. * * @return a negative number, 0, or a positive number as this * record's formatted string is lexicographically less than, equal * to, or greater than the given record's formatted string */ public int compareTo(PrintfRecord r) { return formattedString.compareTo(r.formattedString); } private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); // Defensively copy record list before validating if (records == null) { throw new InvalidObjectException("record list is null"); } List copy = new ArrayList (records.size()); copy.addAll(records); records = copy; // check invariants try { validate(); } catch (Exception e) { InvalidObjectException x = new InvalidObjectException( e.getMessage()); x.initCause(e); throw x; } } /** * Gets the formatted string output of the DTrace {@code printf()} * action. */ public String toString() { return formattedString; } }