KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > iapi > services > classfile > ClassInvestigator


1 /*
2
3    Derby - Class org.apache.derby.iapi.services.classfile.ClassInvestigator
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.iapi.services.classfile;
23
24
25 import java.io.InputStream JavaDoc;
26 import java.util.Enumeration JavaDoc;
27
28 import java.io.IOException JavaDoc;
29 import java.util.Vector JavaDoc;
30
31 import org.apache.derby.iapi.services.classfile.VMDescriptor;
32 import org.apache.derby.iapi.services.classfile.VMDescriptor;
33 import java.util.HashSet JavaDoc;
34
35 import java.util.Hashtable JavaDoc;
36 import java.util.Vector JavaDoc;
37 import java.util.Enumeration JavaDoc;
38 import java.util.Collections JavaDoc;
39
40
41 /**
42 */

43
44 public class ClassInvestigator extends ClassHolder {
45
46     public static ClassInvestigator load(InputStream JavaDoc is)
47         throws IOException JavaDoc {
48
49         ClassInput classInput = new ClassInput(is);
50
51         // Check the header
52
checkHeader(classInput);
53
54         // Read in the Constant Pool
55
int constantPoolCount = classInput.getU2();
56
57         ClassInvestigator ci = new ClassInvestigator(constantPoolCount);
58         // Yes, index starts at 1, The '0'th constant pool entry
59
// is reserved for the JVM and is not present in the class file.
60
for (int i = 1; i < constantPoolCount; ) {
61             ConstantPoolEntry item = ClassInvestigator.getConstant(classInput);
62             i += ci.addEntry(item.getKey(), item);
63         }
64
65         // Read in access_flags and class indexes
66
ci.access_flags = classInput.getU2();
67         ci.this_class = classInput.getU2();
68         ci.super_class = classInput.getU2();
69
70         // interfaces is a simple int array
71
int interfaceCount = classInput.getU2();
72         if (interfaceCount != 0) {
73             ci.interfaces = new int[interfaceCount];
74             for (int i = 0; i < interfaceCount; i++)
75                 ci.interfaces[i] = classInput.getU2();
76         }
77
78         int fieldCount = classInput.getU2();
79         if (fieldCount != 0) {
80             ci.field_info = new MemberTable(fieldCount);
81             for (int i = 0; i < fieldCount; i++)
82             {
83                 ci.field_info.addEntry(readClassMember(ci, classInput));
84             }
85         }
86
87         int methodCount = classInput.getU2();
88         if (methodCount != 0) {
89             ci.method_info = new MemberTable(methodCount);
90             for (int i = 0; i < methodCount; i++)
91             {
92                 ci.method_info.addEntry(readClassMember(ci, classInput));
93             }
94         }
95
96         int attributeCount = classInput.getU2();
97         if (attributeCount != 0) {
98             ci.attribute_info = new Attributes(attributeCount);
99
100             for (int i = 0; i < attributeCount; i++)
101                 ci.attribute_info.addEntry(new AttributeEntry(classInput));
102         }
103         return ci;
104
105     }
106
107     private static ClassMember readClassMember(ClassInvestigator ci, ClassInput in)
108         throws IOException JavaDoc {
109
110         ClassMember member = new ClassMember(ci, in.getU2(), in.getU2(), in.getU2());
111
112         int attributeCount = in.getU2();
113         if (attributeCount != 0) {
114             member.attribute_info = new Attributes(attributeCount);
115             for (int i = 0; i < attributeCount; i++)
116                 member.attribute_info.addEntry(new AttributeEntry(in));
117         }
118             
119         return member;
120     }
121
122     /*
123     ** Constructors.
124     */

125
126     private ClassInvestigator(int constantPoolCount) {
127         super(constantPoolCount);
128     }
129
130     /*
131     ** Methods to investigate this class
132     */

133
134
135     public Enumeration JavaDoc implementedInterfaces()
136     {
137         int interfaceCount = interfaces == null ? 0 : interfaces.length;
138         Vector JavaDoc implemented = new Vector JavaDoc(interfaceCount);
139
140         for (int i = 0; i < interfaceCount; i++)
141         {
142             implemented.addElement(className(interfaces[i]));
143         }
144         return implemented.elements();
145     }
146     public Enumeration JavaDoc getFields() {
147         if (field_info == null)
148             return Collections.enumeration(Collections.EMPTY_LIST);
149
150         return field_info.entries.elements();
151     }
152
153     public Enumeration JavaDoc getMethods() {
154         if (method_info == null)
155             return Collections.enumeration(Collections.EMPTY_LIST);
156         return method_info.entries.elements();
157     }
158
159     public Enumeration JavaDoc referencedClasses() {
160         return getClasses(getMethods(), getFields() );
161     }
162
163     /**
164         Return an Enumeration of all referenced classes
165     */

166
167     private Enumeration JavaDoc getClasses(Enumeration JavaDoc methods, Enumeration JavaDoc fields)
168     {
169         return new ClassEnumeration(this, cptEntries.elements(), methods, fields);
170     }
171
172     public Enumeration JavaDoc getStrings() {
173         HashSet JavaDoc strings = new HashSet JavaDoc(30, 0.8f);
174         
175         int size = cptEntries.size();
176         for (int i = 1; i < size; i++) {
177             ConstantPoolEntry cpe = getEntry(i);
178
179             if ((cpe == null) || (cpe.getTag() != VMDescriptor.CONSTANT_String))
180                 continue;
181
182             CONSTANT_Index_info cii = (CONSTANT_Index_info) cpe;
183
184             strings.add(nameIndexToString(cii.getI1()));
185         }
186
187         return java.util.Collections.enumeration(strings);
188     }
189
190     public ClassMember getMember(String JavaDoc simpleName, String JavaDoc descriptor) {
191
192         if (descriptor.startsWith("(")) {
193             if (method_info == null)
194                 return null;
195             return method_info.find(simpleName, descriptor);
196         }
197         else {
198             if (field_info == null)
199                 return null;
200             return field_info.find(simpleName, descriptor);
201         }
202     }
203
204     /**
205         Return an Enumeration of all Member References
206     */

207 /*
208     Enumeration getMemberReferences() {
209         return new ReferenceEnumeration(this, elements());
210     }
211 */

212
213     /*
214     ** Methods to modify the class.
215     */

216     // remove all atttributes that are not essential
217
public void removeAttributes() throws IOException JavaDoc {
218
219         // Class level attributes
220
if (attribute_info != null) {
221             for (int i = attribute_info.size() - 1; i >= 0 ; i--) {
222
223                 AttributeEntry ae = (AttributeEntry) attribute_info.elementAt(i);
224                 String JavaDoc name = nameIndexToString(ae.getNameIndex());
225                 if (name.equals("SourceFile"))
226                     attribute_info.removeElementAt(i);
227                 else if (name.equals("InnerClasses"))
228                     ; // leave in
229
else
230                     System.err.println("WARNING - Unknown Class File attribute " + name);
231             }
232
233             if (attribute_info.size() == 0)
234                 attribute_info = null;
235         }
236         attribute_info = null;
237
238         // fields
239
for (Enumeration JavaDoc e = getFields(); e.hasMoreElements(); ) {
240             ClassMember member = (ClassMember) e.nextElement();
241
242             Attributes attrs = member.attribute_info;
243
244             if (attrs != null) {
245
246                 for (int i = attrs.size() - 1; i >= 0 ; i--) {
247
248                     AttributeEntry ae = (AttributeEntry) attrs.elementAt(i);
249                     String JavaDoc name = nameIndexToString(ae.getNameIndex());
250                     if (name.equals("ConstantValue"))
251                         ; // leave in
252
else if (name.equals("Synthetic"))
253                         ; // leave in
254
else
255                         System.err.println("WARNING - Unknown Field attribute " + name);
256                 }
257
258                 if (attrs.size() == 0)
259                     member.attribute_info = null;
260             }
261
262         }
263
264         // methods
265
for (Enumeration JavaDoc e = getMethods(); e.hasMoreElements(); ) {
266             ClassMember member = (ClassMember) e.nextElement();
267
268             Attributes attrs = member.attribute_info;
269
270             if (attrs != null) {
271
272                 for (int i = attrs.size() - 1; i >= 0 ; i--) {
273
274                     AttributeEntry ae = (AttributeEntry) attrs.elementAt(i);
275                     String JavaDoc name = nameIndexToString(ae.getNameIndex());
276                     if (name.equals("Code"))
277                         processCodeAttribute(member, ae);
278                     else if (name.equals("Exceptions"))
279                         ; // leave in
280
else if (name.equals("Deprecated"))
281                         ; // leave in
282
else if (name.equals("Synthetic"))
283                         ; // leave in
284
else
285                         System.err.println("WARNING - Unknown method attribute " + name);
286                 }
287
288                 if (attrs.size() == 0)
289                     member.attribute_info = null;
290             }
291
292         }
293     }
294
295     private void processCodeAttribute(ClassMember member, AttributeEntry ae) throws IOException JavaDoc {
296
297         ClassInput ci = new ClassInput(new java.io.ByteArrayInputStream JavaDoc(ae.infoIn));
298
299
300         ci.skipBytes(4); // puts us at code_length
301
int len = ci.getU4();
302         ci.skipBytes(len); // puts us at exception_table_length
303
int count = ci.getU2();
304         if (count != 0)
305             ci.skipBytes(8 * count);
306
307         int nonAttrLength = 4 + 4 + len + 2 + (8 * count);
308
309         // now at attributes
310

311         count = ci.getU2();
312         if (count == 0)
313             return;
314
315         int newCount = count;
316         for (int i = 0; i < count; i++) {
317
318             int nameIndex = ci.getU2();
319             String JavaDoc name = nameIndexToString(nameIndex);
320             if (name.equals("LineNumberTable") || name.equals("LocalVariableTable"))
321                 newCount--;
322             else
323                 System.err.println("ERROR - Unknown code attribute " + name);
324
325             len = ci.getU4();
326             ci.skipBytes(len);
327         }
328
329         if (newCount != 0) {
330             System.err.println("ERROR - expecting all code attributes to be removed");
331             System.exit(1);
332         }
333
334         // this is only coded for all attributes within a Code attribute being removed.
335

336         byte[] newInfo = new byte[nonAttrLength + 2];
337         System.arraycopy(ae.infoIn, 0, newInfo, 0, nonAttrLength);
338         // last two bytes are left at 0 which means 0 attributes
339
ae.infoIn = newInfo;
340     }
341
342     public void renameClassElements(Hashtable JavaDoc classNameMap, Hashtable JavaDoc memberNameMap) {
343
344         // this & super class
345
renameString(classNameMap, (CONSTANT_Index_info) getEntry(this_class));
346         renameString(classNameMap, (CONSTANT_Index_info) getEntry(super_class));
347
348         // implemented interfaces
349
// handled by Class entries below
350

351         // classes & Strings
352
// descriptors
353
int size = cptEntries.size();
354         for (int i = 1; i < size; i++) {
355             ConstantPoolEntry cpe = getEntry(i);
356
357             if (cpe == null)
358                 continue;
359
360             switch (cpe.getTag()) {
361             case VMDescriptor.CONSTANT_String:
362             case VMDescriptor.CONSTANT_Class:
363                 {
364                 CONSTANT_Index_info cii = (CONSTANT_Index_info) cpe;
365                 renameString(classNameMap, cii);
366                 break;
367                 }
368             case VMDescriptor.CONSTANT_NameAndType:
369                 {
370                 CONSTANT_Index_info cii = (CONSTANT_Index_info) cpe;
371                 String JavaDoc newDescriptor = newDescriptor(classNameMap, nameIndexToString(cii.getI2()));
372                 if (newDescriptor != null) {
373                     doRenameString(cii.getI2(), newDescriptor);
374                 }
375                 break;
376                 }
377
378             default:
379                 continue;
380             }
381
382         }
383
384         //System.out.println("Starting Fields");
385

386         // now the methods & fields, only descriptors at this time
387
renameMembers(getFields(), classNameMap, memberNameMap);
388
389         renameMembers(getMethods(), classNameMap, memberNameMap);
390     }
391
392     private void renameMembers(Enumeration JavaDoc e, Hashtable JavaDoc classNameMap, Hashtable JavaDoc memberNameMap) {
393
394         for (; e.hasMoreElements(); ) {
395             ClassMember member = (ClassMember) e.nextElement();
396
397             String JavaDoc oldMemberName = nameIndexToString(member.name_index);
398             String JavaDoc newMemberName = (String JavaDoc) memberNameMap.get(oldMemberName);
399             if (newMemberName != null)
400                 doRenameString(member.name_index, newMemberName);
401
402             String JavaDoc newDescriptor = newDescriptor(classNameMap, nameIndexToString(member.descriptor_index));
403             if (newDescriptor != null) {
404                 doRenameString(member.descriptor_index, newDescriptor);
405             }
406         }
407
408     }
409
410     private void renameString(Hashtable JavaDoc classNameMap, CONSTANT_Index_info cii) {
411
412         int index = cii.getI1();
413
414         String JavaDoc name = nameIndexToString(index);
415         String JavaDoc newName = (String JavaDoc) classNameMap.get(name);
416         if (newName != null) {
417
418             doRenameString(index, newName);
419
420             return;
421         }
422
423         // have to look for arrays
424
if (cii.getTag() == VMDescriptor.CONSTANT_Class) {
425
426             if (name.charAt(0) == '[') {
427                 int classOffset = name.indexOf('L') + 1;
428
429                 String JavaDoc baseClassName = name.substring(classOffset, name.length() - 1);
430
431
432                 newName = (String JavaDoc) classNameMap.get(baseClassName);
433
434                 if (newName != null) {
435
436                     String JavaDoc newArrayClassName = name.substring(0, classOffset) + newName + ";";
437
438                     doRenameString(index, newArrayClassName);
439
440                 }
441
442             }
443         }
444     }
445
446     private void doRenameString(int index, String JavaDoc newName) {
447         ConstantPoolEntry cpe = getEntry(index);
448         if (cpe.getTag() != VMDescriptor.CONSTANT_Utf8)
449             throw new RuntimeException JavaDoc("unexpected type " + cpe);
450
451         CONSTANT_Utf8_info newCpe = new CONSTANT_Utf8_info(newName);
452
453         cptHashTable.remove(cpe.getKey());
454         cptHashTable.put(cpe.getKey(), cpe);
455
456         newCpe.index = index;
457
458         cptEntries.setElementAt(newCpe, index);
459     }
460
461     /*
462     **
463     */

464     static private void checkHeader(ClassInput in) throws IOException JavaDoc {
465         int magic = in.getU4();
466         int minor_version = in.getU2();
467         int major_version = in.getU2();
468
469
470         if (magic != VMDescriptor.JAVA_CLASS_FORMAT_MAGIC)
471                throw new ClassFormatError JavaDoc();
472     }
473     private static ConstantPoolEntry getConstant(ClassInput in)
474         throws IOException JavaDoc {
475
476         ConstantPoolEntry item;
477         int tag;
478         tag = in.readUnsignedByte();
479
480         switch (tag) {
481         case VMDescriptor.CONSTANT_Class:
482         case VMDescriptor.CONSTANT_String:
483             item = new CONSTANT_Index_info(tag, in.getU2(), 0);
484             break;
485
486         case VMDescriptor.CONSTANT_NameAndType:
487         case VMDescriptor.CONSTANT_Fieldref:
488         case VMDescriptor.CONSTANT_Methodref:
489         case VMDescriptor.CONSTANT_InterfaceMethodref:
490             item = new CONSTANT_Index_info(tag, in.getU2(), in.getU2());
491             break;
492
493         case VMDescriptor.CONSTANT_Integer:
494             item = new CONSTANT_Integer_info(in.getU4());
495             break;
496
497         case VMDescriptor.CONSTANT_Float:
498             item = new CONSTANT_Float_info(in.readFloat());
499             break;
500
501         case VMDescriptor.CONSTANT_Long:
502             item = new CONSTANT_Long_info(in.readLong());
503             break;
504
505         case VMDescriptor.CONSTANT_Double:
506             item = new CONSTANT_Double_info(in.readDouble());
507             break;
508
509         case VMDescriptor.CONSTANT_Utf8:
510             item = new CONSTANT_Utf8_info(in.readUTF());
511             break;
512         default:
513             throw new ClassFormatError JavaDoc();
514         }
515
516         return item;
517     }
518     public static String JavaDoc newDescriptor(Hashtable JavaDoc classNameMap, String JavaDoc descriptor) {
519
520         String JavaDoc newDescriptor = null;
521
522         int dlen = descriptor.length();
523         for (int offset = 0; offset < dlen; ) {
524             char c = descriptor.charAt(offset);
525             switch (c) {
526             case VMDescriptor.C_VOID :
527             case VMDescriptor.C_BOOLEAN:
528             case VMDescriptor.C_BYTE:
529             case VMDescriptor.C_CHAR:
530             case VMDescriptor.C_SHORT:
531             case VMDescriptor.C_INT:
532             case VMDescriptor.C_LONG:
533             case VMDescriptor.C_FLOAT:
534             case VMDescriptor.C_DOUBLE:
535             case VMDescriptor.C_ARRAY:
536             case VMDescriptor.C_METHOD:
537             case VMDescriptor.C_ENDMETHOD:
538             default:
539                 offset++;
540                 continue;
541
542             case VMDescriptor.C_CLASS:
543                 {
544                 int startOffset = offset;
545                 while (descriptor.charAt(offset++) != VMDescriptor.C_ENDCLASS)
546                     ;
547                 int endOffset = offset;
548
549                 // name includes L and ;
550
String JavaDoc name = descriptor.substring(startOffset, endOffset);
551                 String JavaDoc newName = (String JavaDoc) classNameMap.get(name);
552                 if (newName != null) {
553                     if (newDescriptor == null)
554                         newDescriptor = descriptor;
555
556                     // we just replace the first occurance of it,
557
// the loop will hit any next occurance.
558
int startPos = newDescriptor.indexOf(name);
559
560                     String JavaDoc tmp;
561                     if (startPos == 0)
562                         tmp = newName;
563                     else
564                         tmp = newDescriptor.substring(0, startPos) +
565                                 newName;
566
567                     int endPos = startPos + name.length();
568
569                     if (endPos < newDescriptor.length()) {
570
571                         tmp += newDescriptor.substring(endPos , newDescriptor.length());
572                     }
573
574
575                     newDescriptor = tmp;
576                 }
577                 }
578             }
579
580
581         }
582         //if (newDescriptor != null) {
583
// System.out.println("O - " + descriptor);
584
// System.out.println("N - " + newDescriptor);
585
//}
586
return newDescriptor;
587     }
588 }
589
Popular Tags