/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved. * * This program and the accompanying materials are made available under * the terms of the Common Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/cpl-v10.html * * $Id: ClassDescriptor.java,v 1.1.1.1 2004/05/09 16:57:30 vlad_r Exp $ */ package com.vladium.emma.data; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.io.Serializable; import com.vladium.util.IConstants; import com.vladium.util.asserts.$assert; // ---------------------------------------------------------------------------- /** * @author Vlad Roubtsov, (C) 2003 */ public final class ClassDescriptor implements IConstants, Serializable { // public: ................................................................ public ClassDescriptor (final String packageVMName, final String name, final long stamp, final String srcFileName, final MethodDescriptor [] methods) { if (packageVMName == null) throw new IllegalArgumentException ("null input: packageVMName"); if (name == null) throw new IllegalArgumentException ("null input: name"); if (methods == null) throw new IllegalArgumentException ("null input: methods"); if ($assert.ENABLED) { for (int m = 0; m < methods.length; ++ m) { $assert.ASSERT (methods [m] != null, "methods [" + m + "] = null (length = " + methods.length + ")"); } } m_packageVMName = packageVMName; m_name = name; m_stamp = stamp; m_srcFileName = srcFileName; m_methods = methods; // TODO: defensive copy? boolean completeLineNumberInfo = true; for (int m = 0; m < m_methods.length; ++ m) { final MethodDescriptor method = methods [m]; if (((method.getStatus () & IMetadataConstants.METHOD_NO_BLOCK_DATA) == 0) && ! m_methods [m].hasLineNumberInfo ()) { completeLineNumberInfo = false; break; } } m_hasCompleteLineNumberInfo = completeLineNumberInfo; } // equality is defined based on <m_packageVMName, m_name> only (m_stamp not mixed in by design): public final boolean equals (final Object rhs) { if (! (rhs instanceof ClassDescriptor)) return false; final ClassDescriptor _rhs = (ClassDescriptor) rhs; if (hashCode () != _rhs.hashCode ()) return false; if (! m_name.equals (_rhs.m_name)) return false; if (! m_packageVMName.equals (_rhs.m_packageVMName)) return false; return true; } public final int hashCode () { if (m_hash == 0) { final int hash = m_name.hashCode () + 16661 * m_packageVMName.hashCode (); m_hash = hash; return hash; } return m_hash; } public final String getPackageVMName () { return m_packageVMName; } public final String getName () { return m_name; } public final long getStamp () { return m_stamp; } public final String getClassVMName () { // TODO: use Descriptors API? if (m_packageVMName.length () == 0) return m_name; else return new StringBuffer (m_packageVMName).append ("/").append (m_name).toString (); } public final String getSrcFileName () { return m_srcFileName; } public final MethodDescriptor [] getMethods () { return m_methods; // no defensive copy } public final boolean hasSrcFileInfo () { return m_srcFileName != null; } public final boolean hasCompleteLineNumberInfo () { return m_hasCompleteLineNumberInfo; } public String toString () { return toString (""); } public String toString (final String indent) { StringBuffer s = new StringBuffer (indent + "class [" + (m_packageVMName.length () > 0 ? m_packageVMName + "/" : "") + m_name + "] descriptor:"); for (int m = 0; m < m_methods.length; ++ m) { s.append (EOL); s.append (m_methods [m].toString (indent + INDENT_INCREMENT)); } return s.toString (); } // protected: ............................................................. // package: ............................................................... static ClassDescriptor readExternal (final DataInput in) throws IOException { final String packageVMName = in.readUTF (); final String name = in.readUTF (); final long stamp = in.readLong (); final byte srcFileNameFlag = in.readByte (); final String srcFileName = srcFileNameFlag != 0 ? in.readUTF () : null; final int length = in.readInt (); final MethodDescriptor [] methods = new MethodDescriptor [length]; for (int i = 0; i < length; ++ i) { methods [i] = MethodDescriptor.readExternal (in); } return new ClassDescriptor (packageVMName, name, stamp, srcFileName, methods); } static void writeExternal (final ClassDescriptor cls, final DataOutput out) throws IOException { out.writeUTF (cls.m_packageVMName); out.writeUTF (cls.m_name); out.writeLong (cls.m_stamp); if (cls.m_srcFileName != null) { out.writeByte (1); out.writeUTF (cls.m_srcFileName); } else { out.writeByte (0); } final MethodDescriptor [] methods = cls.m_methods; final int length = methods.length; out.writeInt (length); for (int i = 0; i < length; ++ i) { MethodDescriptor.writeExternal (methods [i], out); } // [m_hash and m_hasCompleteLineNumberInfo are transient data] } // private: ............................................................... private final String m_packageVMName; // in JVM format, no trailing '/' [never null] private final String m_name; // relative to (m_packageName + '/') [never null] private final long m_stamp; private final String m_srcFileName; // relative to (m_packageName + '/') [can be null] private final MethodDescriptor [] m_methods; // [never null, could be empty] private final boolean m_hasCompleteLineNumberInfo; private transient int m_hash; } // end of class // ----------------------------------------------------------------------------