1/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
2 *
3 * This program and the accompanying materials are made available under
4 * the terms of the Common Public License v1.0 which accompanies this distribution,
5 * and is available at http://www.eclipse.org/legal/cpl-v10.html
6 *
7 * $Id: ClassDescriptor.java,v 1.1.1.1 2004/05/09 16:57:30 vlad_r Exp $
8 */
9package com.vladium.emma.data;
10
11import java.io.DataInput;
12import java.io.DataOutput;
13import java.io.IOException;
14import java.io.Serializable;
15
16import com.vladium.util.IConstants;
17import com.vladium.util.asserts.$assert;
18
19// ----------------------------------------------------------------------------
20/**
21 * @author Vlad Roubtsov, (C) 2003
22 */
23public
24final class ClassDescriptor implements IConstants, Serializable
25{
26    // public: ................................................................
27
28
29    public ClassDescriptor (final String packageVMName, final String name, final long stamp,
30                            final String srcFileName,
31                            final MethodDescriptor [] methods)
32    {
33        if (packageVMName == null)
34            throw new IllegalArgumentException ("null input: packageVMName");
35        if (name == null)
36            throw new IllegalArgumentException ("null input: name");
37        if (methods == null)
38            throw new IllegalArgumentException ("null input: methods");
39
40        if ($assert.ENABLED)
41        {
42            for (int m = 0; m < methods.length; ++ m)
43            {
44                $assert.ASSERT (methods [m] != null, "methods [" + m + "] = null (length = " + methods.length + ")");
45            }
46        }
47
48        m_packageVMName = packageVMName;
49        m_name = name;
50        m_stamp = stamp;
51        m_srcFileName = srcFileName;
52        m_methods = methods; // TODO: defensive copy?
53
54        boolean completeLineNumberInfo = true;
55        for (int m = 0; m < m_methods.length; ++ m)
56        {
57            final MethodDescriptor method = methods [m];
58
59            if (((method.getStatus () & IMetadataConstants.METHOD_NO_BLOCK_DATA) == 0) && ! m_methods [m].hasLineNumberInfo ())
60            {
61                completeLineNumberInfo = false;
62                break;
63            }
64        }
65
66        m_hasCompleteLineNumberInfo = completeLineNumberInfo;
67    }
68
69
70    // equality is defined based on <m_packageVMName, m_name> only (m_stamp not mixed in by design):
71
72    public final boolean equals (final Object rhs)
73    {
74        if (! (rhs instanceof ClassDescriptor)) return false;
75
76        final ClassDescriptor _rhs = (ClassDescriptor) rhs;
77
78        if (hashCode () != _rhs.hashCode ()) return false;
79
80        if (! m_name.equals (_rhs.m_name)) return false;
81        if (! m_packageVMName.equals (_rhs.m_packageVMName)) return false;
82
83        return true;
84    }
85
86    public final int hashCode ()
87    {
88        if (m_hash == 0)
89        {
90            final int hash = m_name.hashCode () + 16661 * m_packageVMName.hashCode ();
91            m_hash = hash;
92
93            return hash;
94        }
95
96        return m_hash;
97    }
98
99
100    public final String getPackageVMName ()
101    {
102        return m_packageVMName;
103    }
104
105    public final String getName ()
106    {
107        return m_name;
108    }
109
110    public final long getStamp ()
111    {
112        return m_stamp;
113    }
114
115    public final String getClassVMName ()
116    {
117        // TODO: use Descriptors API?
118        if (m_packageVMName.length () == 0)
119            return m_name;
120        else
121            return new StringBuffer (m_packageVMName).append ("/").append (m_name).toString ();
122    }
123
124    public final String getSrcFileName ()
125    {
126        return m_srcFileName;
127    }
128
129    public final MethodDescriptor [] getMethods ()
130    {
131        return m_methods; // no defensive copy
132    }
133
134    public final boolean hasSrcFileInfo ()
135    {
136        return m_srcFileName != null;
137    }
138
139    public final boolean hasCompleteLineNumberInfo ()
140    {
141        return m_hasCompleteLineNumberInfo;
142    }
143
144
145    public String toString ()
146    {
147        return toString ("");
148    }
149
150    public String toString (final String indent)
151    {
152        StringBuffer s = new StringBuffer (indent + "class [" + (m_packageVMName.length () > 0 ? m_packageVMName + "/" : "") + m_name + "] descriptor:");
153
154        for (int m = 0; m < m_methods.length; ++ m)
155        {
156            s.append (EOL);
157            s.append (m_methods [m].toString (indent + INDENT_INCREMENT));
158        }
159
160        return s.toString ();
161    }
162
163    // protected: .............................................................
164
165    // package: ...............................................................
166
167
168    static ClassDescriptor readExternal (final DataInput in)
169        throws IOException
170    {
171        final String packageVMName = in.readUTF ();
172        final String name = in.readUTF ();
173
174        final long stamp = in.readLong ();
175
176        final byte srcFileNameFlag = in.readByte ();
177        final String srcFileName = srcFileNameFlag != 0 ? in.readUTF () : null;
178
179        final int length = in.readInt ();
180        final MethodDescriptor [] methods = new MethodDescriptor [length];
181        for (int i = 0; i < length; ++ i)
182        {
183            methods [i] = MethodDescriptor.readExternal (in);
184        }
185
186        return new ClassDescriptor (packageVMName, name, stamp, srcFileName, methods);
187    }
188
189    static void writeExternal (final ClassDescriptor cls, final DataOutput out)
190        throws IOException
191    {
192        out.writeUTF (cls.m_packageVMName);
193        out.writeUTF (cls.m_name);
194
195        out.writeLong (cls.m_stamp);
196
197        if (cls.m_srcFileName != null)
198        {
199            out.writeByte (1);
200            out.writeUTF (cls.m_srcFileName);
201        }
202        else
203        {
204            out.writeByte (0);
205        }
206
207        final MethodDescriptor [] methods = cls.m_methods;
208        final int length = methods.length;
209        out.writeInt (length);
210        for (int i = 0; i < length; ++ i)
211        {
212            MethodDescriptor.writeExternal (methods [i], out);
213        }
214
215        // [m_hash and m_hasCompleteLineNumberInfo are transient data]
216    }
217
218    // private: ...............................................................
219
220
221    private final String m_packageVMName; // in JVM format, no trailing '/' [never null]
222    private final String m_name; // relative to (m_packageName + '/') [never null]
223    private final long m_stamp;
224    private final String m_srcFileName; // relative to (m_packageName + '/') [can be null]
225    private final MethodDescriptor [] m_methods; // [never null, could be empty]
226
227    private final boolean m_hasCompleteLineNumberInfo;
228    private transient int m_hash;
229
230} // end of class
231// ----------------------------------------------------------------------------
232