View Javadoc

1   /***************************************************************************************
2    * Copyright (c) Jonas Bonér, Alexandre Vasseur. All rights reserved.                 *
3    * http://aspectwerkz.codehaus.org                                                    *
4    * ---------------------------------------------------------------------------------- *
5    * The software in this package is published under the terms of the LGPL license      *
6    * a copy of which has been included with this distribution in the license.txt file.  *
7    **************************************************************************************/
8   package org.codehaus.aspectwerkz.transform.delegation;
9   
10  import org.codehaus.aspectwerkz.MethodComparator;
11  import org.codehaus.aspectwerkz.annotation.instrumentation.AttributeEnhancer;
12  import org.codehaus.aspectwerkz.definition.SystemDefinition;
13  import org.codehaus.aspectwerkz.transform.Context;
14  import org.codehaus.aspectwerkz.transform.TransformationUtil;
15  import org.codehaus.aspectwerkz.transform.TransformationConstants;
16  import org.codehaus.aspectwerkz.transform.TransformationConstants;
17  
18  import java.io.ByteArrayOutputStream;
19  import java.io.DataOutputStream;
20  import java.io.IOException;
21  import java.security.MessageDigest;
22  import java.security.NoSuchAlgorithmException;
23  import java.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.Collections;
26  import java.util.Comparator;
27  import java.util.Iterator;
28  import java.util.List;
29  
30  import javassist.CannotCompileException;
31  import javassist.ClassPool;
32  import javassist.CtClass;
33  import javassist.CtConstructor;
34  import javassist.CtField;
35  import javassist.CtMethod;
36  import javassist.CtNewMethod;
37  import javassist.Modifier;
38  import javassist.NotFoundException;
39  import javassist.CtBehavior;
40  import javassist.bytecode.AttributeInfo;
41  import javassist.bytecode.ClassFile;
42  import javassist.bytecode.Descriptor;
43  import javassist.bytecode.AnnotationsAttribute;
44  
45  /***
46   * Helper class with utility methods for Javassist.
47   * 
48   * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
49   * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
50   */
51  public class JavassistHelper {
52      /***
53       * Helper method for bogus CtMethod.make in Javassist for static methods
54       * 
55       * @param returnType
56       * @param name
57       * @param parameters
58       * @param exceptions
59       * @param body
60       * @param declaring
61       * @return new method
62       * @throws CannotCompileException
63       */
64      public static CtMethod makeStatic(
65          final CtClass returnType,
66          final String name,
67          final CtClass[] parameters,
68          final CtClass[] exceptions,
69          final String body,
70          final CtClass declaring) throws CannotCompileException {
71          try {
72              CtMethod cm = new CtMethod(returnType, name, parameters, declaring);
73              cm.setModifiers(cm.getModifiers() | Modifier.STATIC);
74              cm.setExceptionTypes(exceptions);
75              cm.setBody(body);
76              return cm;
77          } catch (NotFoundException e) {
78              throw new CannotCompileException(e);
79          }
80      }
81  
82      /***
83       * Gets the default value for primitive types
84       * 
85       * @param type
86       * @return
87       */
88      public static String getDefaultPrimitiveValue(CtClass type) {
89          if (type == CtClass.booleanType) {
90              return "false";
91          } else if (type == CtClass.intType) {
92              return "0";
93          } else if (type == CtClass.longType) {
94              return "0L";
95          } else if (type == CtClass.floatType) {
96              return "0.0f";
97          } else if (type == CtClass.shortType) {
98              return "(short)0";
99          } else if (type == CtClass.byteType) {
100             return "(byte)0";
101         } else if (type == CtClass.charType) {
102             return "'//u0000'";
103         } else if (type == CtClass.doubleType) {
104             return "(double)0";
105         } else {
106             return "null";
107         }
108     }
109 
110     /***
111      * Checks if the given Class as already a method methodName Does not take into account the signature
112      * 
113      * @param klass
114      * @param methodName
115      * @return true if klass has methodName
116      */
117     public static boolean hasMethod(CtClass klass, String methodName) {
118         try {
119             klass.getDeclaredMethod(methodName);
120             return true;
121         } catch (NotFoundException e) {
122             return false;
123         }
124     }
125 
126     /***
127      * Checks if the given Class as already a ctor with given signature
128      * 
129      * @param klass
130      * @param args
131      * @return true if klass has ctor
132      */
133     public static boolean hasConstructor(CtClass klass, CtClass[] args) {
134         try {
135             klass.getDeclaredConstructor(args);
136             return true;
137         } catch (NotFoundException e) {
138             return false;
139         }
140     }
141 
142     /***
143      * Checks if the given Class as already a method methodName Does not take into account the signature
144      * 
145      * @param klass
146      * @param fieldName
147      * @return true if klass has methodName
148      */
149     public static boolean hasField(CtClass klass, String fieldName) {
150         try {
151             klass.getDeclaredField(fieldName);
152             return true;
153         } catch (NotFoundException e) {
154             return false;
155         }
156     }
157 
158     /***
159      * Checks if the given Class as already a method methodName.
160      * 
161      * @param klass
162      * @param methodName
163      * @return true if klass has methodName
164      */
165     public static boolean hasMethod(CtClass klass, String methodName, CtClass[] args) {
166         try {
167             klass.getDeclaredMethod(methodName, args);
168             return true;
169         } catch (NotFoundException e) {
170             return false;
171         }
172     }
173 
174     /***
175      * Swapp bodies of the two given methods of the same declaring class
176      * 
177      * @param methodA
178      * @param methodB
179      * @TODO: add support for annotations
180      */
181     public static void swapBodies(CtMethod methodA, CtMethod methodB) {
182         String nameA = methodA.getName();
183         int modifiersA = methodA.getModifiers();
184         methodA.setName(methodB.getName());
185         methodA.setModifiers(methodB.getModifiers());
186         methodB.setName(nameA);
187         methodB.setModifiers(modifiersA);
188     }
189 
190     /***
191      * Converts a Javassist type signature to a reflect type signature. <p/>Since <b>sucky </b> Javassist does not use
192      * the standard.
193      * 
194      * @param typeName
195      * @return @TODO does not support multi dimensional arrays, needs to be fixed
196      */
197     public static String convertJavassistTypeSignatureToReflectTypeSignature(String typeName) {
198         int index = typeName.indexOf("[]");
199         if (index >= 0) {
200             typeName = typeName.substring(0, index);
201             if (typeName.equals("short")) {
202                 typeName = "[S";
203             } else if (typeName.equals("int")) {
204                 typeName = "[I";
205             } else if (typeName.equals("long")) {
206                 typeName = "[J";
207             } else if (typeName.equals("float")) {
208                 typeName = "[F";
209             } else if (typeName.equals("double")) {
210                 typeName = "[D";
211             } else if (typeName.equals("char")) {
212                 typeName = "[C";
213             } else if (typeName.equals("byte")) {
214                 typeName = "[B";
215             } else if (typeName.equals("boolean")) {
216                 typeName = "[Z";
217             } else {
218                 typeName = "[L" + typeName + ';';
219             }
220         }
221         return typeName;
222     }
223 
224     /***
225      * Checks if a method is marked as an empty wrapper (runtime weaving)
226      * 
227      * @param method
228      * @return true if empty wrapper
229      */
230     public static boolean isAnnotatedEmpty(CtMethod method) {
231         byte[] emptyBytes = method.getAttribute(TransformationConstants.EMPTY_WRAPPER_ATTRIBUTE);
232         return ((emptyBytes != null) && (emptyBytes[0] == TransformationConstants.EMPTY_WRAPPER_ATTRIBUTE_VALUE_EMPTY));
233     }
234 
235     /***
236      * Checks if a method is marked as a non empty wrapper (runtime unweaving)
237      * 
238      * @param method
239      * @return true if non empty wrapper
240      */
241     public static boolean isAnnotatedNotEmpty(CtMethod method) {
242         byte[] emptyBytes = method.getAttribute(TransformationConstants.EMPTY_WRAPPER_ATTRIBUTE);
243         return ((emptyBytes == null) || (emptyBytes[0] == TransformationConstants.EMPTY_WRAPPER_ATTRIBUTE_VALUE_NOTEMPTY));
244     }
245 
246     /***
247      * Sets a method as beeing an empty wrapper
248      * 
249      * @param method
250      */
251     public static void setAnnotatedEmpty(CtMethod method) {
252         method.setAttribute(TransformationConstants.EMPTY_WRAPPER_ATTRIBUTE, new byte[] {
253             TransformationConstants.EMPTY_WRAPPER_ATTRIBUTE_VALUE_EMPTY
254         });
255     }
256 
257     /***
258      * Sets a method as beeing a non empty wrapper
259      * 
260      * @param method
261      */
262     public static void setAnnotatedNotEmpty(CtMethod method) {
263         method.setAttribute(TransformationConstants.EMPTY_WRAPPER_ATTRIBUTE, new byte[] {
264             TransformationConstants.EMPTY_WRAPPER_ATTRIBUTE_VALUE_NOTEMPTY
265         });
266     }
267 
268     /***
269      * Creates an empty wrapper method to allow HotSwap without schema change <p/>TODO refactor PrepareTransformer
270      * CAUTION: does not check the wrapped method already exists while PrepareTransformer version does
271      * 
272      * @param ctClass the ClassGen
273      * @param originalMethod the current method
274      * @param methodSequence the method hash
275      * @return the wrapper method
276      */
277     public static CtMethod createEmptyWrapperMethod(
278         final CtClass ctClass,
279         final CtMethod originalMethod,
280         final int methodSequence) throws NotFoundException, CannotCompileException {
281         String wrapperMethodName = TransformationUtil.getPrefixedOriginalMethodName(
282             originalMethod.getName(),
283             methodSequence,
284             ctClass.getName().replace('/', '.'));
285 
286         // determine the method access flags (should always be set to protected)
287         int accessFlags = originalMethod.getModifiers();
288         if ((accessFlags & Modifier.PROTECTED) == 0) {
289             // set the protected flag
290             accessFlags |= Modifier.PROTECTED;
291         }
292         if ((accessFlags & Modifier.PRIVATE) != 0) {
293             // clear the private flag
294             accessFlags &= ~Modifier.PRIVATE;
295         }
296         if ((accessFlags & Modifier.PUBLIC) != 0) {
297             // clear the public flag
298             accessFlags &= ~Modifier.PUBLIC;
299         }
300 
301         // add an empty body
302         StringBuffer body = new StringBuffer();
303         if (originalMethod.getReturnType() == CtClass.voidType) {
304             // special handling for void return type leads to cleaner bytecode
305             // generation with Javassist
306             body.append("{}");
307         } else if (!originalMethod.getReturnType().isPrimitive()) {
308             body.append("{ return null;}");
309         } else {
310             body.append("{ return ");
311             body.append(JavassistHelper.getDefaultPrimitiveValue(originalMethod.getReturnType()));
312             body.append("; }");
313         }
314         CtMethod method = null;
315         if (Modifier.isStatic(originalMethod.getModifiers())) {
316             method = JavassistHelper.makeStatic(originalMethod.getReturnType(), wrapperMethodName, originalMethod
317                     .getParameterTypes(), originalMethod.getExceptionTypes(), body.toString(), ctClass);
318         } else {
319             method = CtNewMethod.make(originalMethod.getReturnType(), wrapperMethodName, originalMethod
320                     .getParameterTypes(), originalMethod.getExceptionTypes(), body.toString(), ctClass);
321             method.setModifiers(accessFlags);
322         }
323         JavassistHelper.copyCustomAttributes(method, originalMethod);
324 
325         // add a method level attribute so that we remember it is an empty
326         // method
327         JavassistHelper.setAnnotatedEmpty(method);
328         return method;
329     }
330 
331     /***
332      * Copy pasted from Javassist since it is a private method
333      * 
334      * @param clazz
335      * @return @throws CannotCompileException
336      */
337     public static long calculateSerialVerUid(CtClass clazz) throws CannotCompileException {
338         try {
339             ByteArrayOutputStream bout = new ByteArrayOutputStream();
340             DataOutputStream out = new DataOutputStream(bout);
341             ClassFile classFile = clazz.getClassFile();
342 
343             // class name.
344             String javaName = javaName(clazz);
345             out.writeUTF(javaName);
346 
347             // class modifiers.
348             out.writeInt(clazz.getModifiers()
349                 & (Modifier.PUBLIC | Modifier.FINAL | Modifier.INTERFACE | Modifier.ABSTRACT));
350 
351             // interfaces.
352             String[] interfaces = classFile.getInterfaces();
353             for (int i = 0; i < interfaces.length; i++) {
354                 interfaces[i] = javaName(interfaces[i]);
355             }
356             Arrays.sort(interfaces);
357             for (int i = 0; i < interfaces.length; i++) {
358                 out.writeUTF(interfaces[i]);
359             }
360 
361             // fields.
362             CtField[] fields = clazz.getDeclaredFields();
363             Arrays.sort(fields, new Comparator() {
364                 public int compare(Object o1, Object o2) {
365                     CtField field1 = (CtField) o1;
366                     CtField field2 = (CtField) o2;
367                     return field1.getName().compareTo(field2.getName());
368                 }
369             });
370             for (int i = 0; i < fields.length; i++) {
371                 CtField field = (CtField) fields[i];
372                 int mods = field.getModifiers();
373                 if (((mods & Modifier.PRIVATE) == 0) || ((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0)) {
374                     out.writeUTF(field.getName());
375                     out.writeInt(mods & filterFieldModifiers());
376                     out.writeUTF(field.getFieldInfo2().getDescriptor());
377                 }
378             }
379 
380             // static initializer.
381             if (classFile.getStaticInitializer() != null) {
382                 out.writeUTF("<clinit>");
383                 out.writeInt(Modifier.STATIC);
384                 out.writeUTF("()V");
385             }
386 
387             // constructors.
388             CtConstructor[] constructors = clazz.getDeclaredConstructors();
389             Arrays.sort(constructors, new Comparator() {
390                 public int compare(Object o1, Object o2) {
391                     CtConstructor c1 = (CtConstructor) o1;
392                     CtConstructor c2 = (CtConstructor) o2;
393                     return c1.getMethodInfo2().getDescriptor().compareTo(c2.getMethodInfo2().getDescriptor());
394                 }
395             });
396             for (int i = 0; i < constructors.length; i++) {
397                 CtConstructor constructor = constructors[i];
398                 int mods = constructor.getModifiers();
399                 if ((mods & Modifier.PRIVATE) == 0) {
400                     out.writeUTF("<init>");
401                     out.writeInt(mods & filterConstructorModifiers());
402                     out.writeUTF(constructor.getMethodInfo2().getDescriptor().replace('/', '.'));
403                 }
404             }
405 
406             // methods.
407             CtMethod[] methods = clazz.getDeclaredMethods();
408             Arrays.sort(methods, new Comparator() {
409                 public int compare(Object o1, Object o2) {
410                     CtMethod m1 = (CtMethod) o1;
411                     CtMethod m2 = (CtMethod) o2;
412                     int value = m1.getName().compareTo(m2.getName());
413                     if (value == 0) {
414                         value = m1.getMethodInfo2().getDescriptor().compareTo(m2.getMethodInfo2().getDescriptor());
415                     }
416                     return value;
417                 }
418             });
419             for (int i = 0; i < methods.length; i++) {
420                 CtMethod method = methods[i];
421                 int mods = method.getModifiers();
422                 if ((mods & Modifier.PRIVATE) == 0) {
423                     out.writeUTF(method.getName());
424                     out.writeInt(mods & filterMethodModifiers());
425                     out.writeUTF(method.getMethodInfo2().getDescriptor().replace('/', '.'));
426                 }
427             }
428 
429             // calculate hash.
430             out.flush();
431             MessageDigest digest = MessageDigest.getInstance("SHA");
432             byte[] digested = digest.digest(bout.toByteArray());
433             long hash = 0;
434             for (int i = Math.min(digested.length, 8) - 1; i >= 0; i--) {
435                 hash = (hash << 8) | (digested[i] & 0xFF);
436             }
437             return hash;
438         } catch (IOException e) {
439             throw new CannotCompileException(e);
440         } catch (NoSuchAlgorithmException e) {
441             throw new CannotCompileException(e);
442         }
443     }
444 
445     private static int filterFieldModifiers(){
446        return (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED
447             | Modifier.STATIC | Modifier.FINAL | Modifier.TRANSIENT | Modifier.VOLATILE);
448     }
449 
450     private static int filterConstructorModifiers(){
451        return (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED);
452     }
453 
454     private static int filterMethodModifiers(){
455        return (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED
456             | Modifier.STATIC | Modifier.FINAL | Modifier.SYNCHRONIZED
457             | Modifier.NATIVE | Modifier.ABSTRACT | Modifier.STRICT);
458     }
459 
460     private static String javaName(CtClass clazz) {
461         return Descriptor.toJavaName(Descriptor.toJvmName(clazz));
462     }
463 
464     private static String javaName(String name) {
465         return Descriptor.toJavaName(Descriptor.toJvmName(name));
466     }
467 
468     public static void setSerialVersionUID(CtClass clazz, long serialVerUid) throws CannotCompileException {
469         // add field with default value.
470         CtField field = new CtField(CtClass.longType, "serialVersionUID", clazz);
471         field.setModifiers(Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL);
472         clazz.addField(field, serialVerUid + "L");
473     }
474 
475     /***
476      * Does the class implement Serializable?
477      */
478     private static boolean isSerializable(CtClass clazz) throws NotFoundException {
479         ClassPool pool = clazz.getClassPool();
480         return clazz.subtypeOf(pool.get("java.io.Serializable"));
481     }
482 
483     public static boolean isSerialVerUidNeeded(CtClass clazz) throws NotFoundException {
484         // check for pre-existing field.
485         try {
486             clazz.getDeclaredField("serialVersionUID");
487             return false;
488         } catch (NotFoundException e) {
489         }
490 
491         // check if the class is serializable.
492         if (!isSerializable(clazz)) {
493             return false;
494         }
495         return true;
496     }
497 
498     /***
499      * Adds a new <code>AspectManager</code> field to the advised class.
500      * 
501      * @param ctClass
502      * @param definition
503      */
504     public static void addAspectManagerField(
505         final CtClass ctClass,
506         final SystemDefinition definition,
507         final Context context) throws NotFoundException, CannotCompileException {
508         if (!hasField(ctClass, TransformationConstants.ASPECT_MANAGER_FIELD)) {
509             CtField field = new CtField(
510                 ctClass.getClassPool().get(TransformationConstants.ASPECT_MANAGER_CLASS),
511                 TransformationConstants.ASPECT_MANAGER_FIELD,
512                 ctClass);
513             field.setModifiers(Modifier.STATIC | Modifier.PRIVATE | Modifier.FINAL);
514             StringBuffer body = new StringBuffer();
515             body.append(TransformationConstants.SYSTEM_LOADER_CLASS);
516             body.append("#getSystem(");
517             body.append(TransformationConstants.STATIC_CLASS_FIELD);
518             body.append('.');
519             body.append("getClassLoader())");
520             body.append('.');
521             body.append(TransformationConstants.GET_ASPECT_MANAGER_METHOD);
522             body.append("(\"");
523             body.append(definition.getUuid());
524             body.append("\");");
525 
526             //TODO ALEX AVAOPC
527             /*
528              * what about having several field to access the AspectManager whose system is introducing methods ? should
529              * we have a simpler TF model and hardcode the AspectManager index ?? [problem for undeploy of a system]
530              */
531             ctClass.addField(field, body.toString());
532             context.markAsAdvised();
533         }
534     }
535 
536     /***
537      * Creates a new static class field.
538      * 
539      * @param ctClass the class
540      */
541     public static void addStaticClassField(final CtClass ctClass, final Context context) throws NotFoundException,
542             CannotCompileException {
543         if (!hasField(ctClass, TransformationConstants.STATIC_CLASS_FIELD)) {
544             CtField field = new CtField(
545                 ctClass.getClassPool().get("java.lang.Class"),
546                 TransformationConstants.STATIC_CLASS_FIELD,
547                 ctClass);
548             field.setModifiers(Modifier.STATIC | Modifier.PRIVATE | Modifier.FINAL);
549             ctClass.addField(field, "java.lang.Class#forName(\"" + ctClass.getName().replace('/', '.') + "\")");
550             context.markAsAdvised();
551         }
552     }
553 
554     /***
555      * Adds a new <code>JoinPointManager</code> field to the advised class.
556      * 
557      * @param ctClass
558      * @param definition
559      */
560     public static void addJoinPointManagerField(
561         final CtClass ctClass,
562         final SystemDefinition definition,
563         final Context context) throws NotFoundException, CannotCompileException {
564         if (!hasField(ctClass, TransformationConstants.JOIN_POINT_MANAGER_FIELD)) {
565             CtField field = new CtField(
566                 ctClass.getClassPool().get(TransformationConstants.JOIN_POINT_MANAGER_CLASS),
567                 TransformationConstants.JOIN_POINT_MANAGER_FIELD,
568                 ctClass);
569             field.setModifiers(Modifier.STATIC | Modifier.PRIVATE);
570             StringBuffer body = new StringBuffer();
571             body.append(TransformationConstants.JOIN_POINT_MANAGER_CLASS);
572             body.append('#');
573             body.append(TransformationConstants.GET_JOIN_POINT_MANAGER);
574             body.append('(');
575             body.append(TransformationConstants.STATIC_CLASS_FIELD);
576             body.append(", \"");
577             body.append(definition.getUuid());
578             body.append("\")");
579             ctClass.addField(field, body.toString());
580             context.markAsAdvised();
581         }
582     }
583 
584     /***
585      * Copies the custom attributes from one class to another.
586      * 
587      * @param copyTo
588      * @param copyFrom
589      */
590     public static void copyCustomAttributes(final CtBehavior copyTo, final CtBehavior copyFrom) {
591         List attributes = copyFrom.getMethodInfo().getAttributes();
592         for (Iterator iterator = attributes.iterator(); iterator.hasNext();) {
593             AttributeInfo attributeInfo = (AttributeInfo) iterator.next();
594             // AW-273
595             // Note: this is very crappy for Java 5 but anyway for now.
596             if (attributeInfo.getName().startsWith("RuntimeInvisibleAnnotations")
597                 || attributeInfo.getName().startsWith("RuntimeVisibleAnnotations")) {
598                 copyTo.setAttribute(attributeInfo.getName(), ((AnnotationsAttribute)attributeInfo).get());
599             }
600         }
601     }
602 
603     /***
604      * Calculate the hash for a javassist field.
605      * 
606      * @param field the field
607      * @return the hash
608      */
609     public static int calculateHash(final CtField field) throws NotFoundException {
610         int hash = 17;
611         hash = (37 * hash) + field.getName().hashCode();
612         String name = convertJavassistTypeSignatureToReflectTypeSignature(field.getType().getName().replace('/', '.'));
613         hash = (37 * hash) + name.hashCode();
614         return hash;
615     }
616 
617     /***
618      * Calculate the hash for a javassist constructor.
619      * 
620      * @param constructor the constructor
621      * @return the hash
622      */
623     public static int calculateHash(final CtConstructor constructor) throws NotFoundException {
624         int hash = 17;
625         hash = (37 * hash) + TransformationConstants.INIT_METHOD_NAME.hashCode();
626         for (int i = 0; i < constructor.getParameterTypes().length; i++) {
627             CtClass type = constructor.getParameterTypes()[i];
628             String name = convertJavassistTypeSignatureToReflectTypeSignature(type.getName().replace('/', '.'));
629             hash = (37 * hash) + name.hashCode();
630         }
631         return hash;
632     }
633 
634     /***
635      * Calculate the hash for a javassist method.
636      * 
637      * @param method the method
638      * @return the hash
639      */
640     public static int calculateHash(final CtMethod method) throws NotFoundException {
641         int hash = 17;
642         hash = (37 * hash) + method.getName().hashCode();
643         for (int i = 0; i < method.getParameterTypes().length; i++) {
644             CtClass type = method.getParameterTypes()[i];
645             String name = convertJavassistTypeSignatureToReflectTypeSignature(type.getName().replace('/', '.'));
646             hash = (37 * hash) + name.hashCode();
647         }
648         return hash;
649     }
650 
651     /***
652      * Calculate the hash for a class.
653      * 
654      * @param ctClass the class
655      * @return the hash
656      */
657     public static int calculateHash(final CtClass ctClass) throws NotFoundException {
658         return ctClass.getName().hashCode();
659     }
660 
661     /***
662      * Creates a sorted method list of all the public methods in the class and super classes.
663      *
664      * @TODO NOT IN USE - REMOVE
665      * 
666      * @param klass the class with the methods
667      * @return the sorted method list
668      */
669     public static List createSortedMethodList(final CtClass klass) {
670         if (klass == null) {
671             throw new IllegalArgumentException("class to sort method on can not be null");
672         }
673 
674         // get all public methods including the inherited methods
675         CtMethod[] methods = klass.getDeclaredMethods();
676         List methodList = new ArrayList(methods.length);
677         for (int i = 0; i < methods.length; i++) {
678             CtMethod method = methods[i];
679             if (!method.getName().equals("equals")
680                 && !method.getName().equals("hashCode")
681                 && !method.getName().equals("getClass")
682                 && !method.getName().equals("toString")
683                 && !method.getName().equals("wait")
684                 && !method.getName().equals("notify")
685                 && !method.getName().equals("notifyAll")
686                 && !method.getName().startsWith(TransformationConstants.CLASS_LOOKUP_METHOD)
687                 && !method.getName().startsWith(TransformationConstants.ORIGINAL_METHOD_PREFIX)
688                 && !method.getName().startsWith(TransformationConstants.ASPECTWERKZ_PREFIX)) {
689                 methodList.add(method);
690             }
691         }
692         Collections.sort(methodList, MethodComparator.getInstance(MethodComparator.NORMAL_METHOD));
693         return methodList;
694     }
695 
696     /***
697      * Returrns the join point index for the class.
698      * 
699      * @param klass
700      * @return the index
701      */
702     public static int getJoinPointIndex(final CtClass klass) {
703         byte[] attribute = klass.getAttribute(TransformationConstants.JOIN_POINT_INDEX_ATTRIBUTE);
704         if (attribute == null) {
705             klass.setAttribute(TransformationConstants.JOIN_POINT_INDEX_ATTRIBUTE, new byte[] {
706                 new Integer(0).byteValue()
707             });
708             return 0;
709         }
710         return new Integer(attribute[0]).intValue();
711     }
712 
713     /***
714      * Sets the join point index for the class.
715      * 
716      * @param klass
717      * @param index
718      */
719     public static void setJoinPointIndex(final CtClass klass, final int index) {
720         klass.setAttribute(TransformationConstants.JOIN_POINT_INDEX_ATTRIBUTE, new byte[] {
721             new Integer(index).byteValue()
722         });
723     }
724 }