blob: d2595b6f84d551f4db0f4c45bc18607d87f08d6a [file] [log] [blame]
/* 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
// ----------------------------------------------------------------------------