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.reflect;
9
10 import org.codehaus.aspectwerkz.exception.WrappedRuntimeException;
11 import org.codehaus.aspectwerkz.transform.TransformationConstants;
12 import org.codehaus.aspectwerkz.util.Strings;
13
14 import java.lang.reflect.Method;
15 import java.util.Comparator;
16
17 /***
18 * Compares Methods. To be used when sorting methods.
19 *
20 * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
21 */
22 public final class MethodComparator implements java.util.Comparator {
23 /***
24 * Compares normal method names.
25 */
26 public static final int NORMAL_METHOD = 0;
27
28 /***
29 * Compares prefixed method names.
30 */
31 public static final int PREFIXED_METHOD = 1;
32
33 /***
34 * Compares method infos.
35 */
36 public static final int METHOD_INFO = 2;
37
38 /***
39 * Defines the type of comparator.
40 */
41 private final int m_type;
42
43 /***
44 * Sets the type.
45 *
46 * @param type the type
47 */
48 private MethodComparator(final int type) {
49 m_type = type;
50 }
51
52 /***
53 * Returns the comparator instance.
54 *
55 * @param type the type of the method comparison
56 * @return the instance
57 */
58 public static Comparator getInstance(final int type) {
59 return new MethodComparator(type);
60 }
61
62 /***
63 * Compares two objects.
64 *
65 * @param o1
66 * @param o2
67 * @return int
68 */
69 public int compare(final Object o1, final Object o2) {
70 switch (m_type) {
71 case NORMAL_METHOD:
72 return compareNormal((Method) o1, (Method) o2);
73 case PREFIXED_METHOD:
74 return comparePrefixed((Method) o1, (Method) o2);
75 case METHOD_INFO:
76 return compareMethodInfo((MethodInfo) o1, (MethodInfo) o2);
77 default:
78 throw new RuntimeException("invalid method comparison type");
79 }
80 }
81
82 /***
83 * Compares two methods.
84 *
85 * @param m1
86 * @param m2
87 * @return int
88 */
89 private int compareNormal(final Method m1, final Method m2) {
90 try {
91 if (m1.equals(m2)) {
92 return 0;
93 }
94 final String m1Name = m1.getName();
95 final String m2Name = m2.getName();
96 if (!m1Name.equals(m2Name)) {
97 return m1Name.compareTo(m2Name);
98 }
99 final Class[] args1 = m1.getParameterTypes();
100 final Class[] args2 = m2.getParameterTypes();
101 if (args1.length < args2.length) {
102 return -1;
103 }
104 if (args1.length > args2.length) {
105 return 1;
106 }
107 if (args1.length == 0) {
108 return 0;
109 }
110 for (int i = 0; i < args1.length; i++) {
111
112 int result = TypeConverter.convertTypeToJava(args1[i]).compareTo(
113 TypeConverter.convertTypeToJava(args2[i])
114 );
115 if (result != 0) {
116 return result;
117 }
118 }
119 } catch (Throwable e) {
120 throw new WrappedRuntimeException(e);
121 }
122 java.lang.System.err.println(m1.getName());
123 java.lang.System.err.println(m2.getName());
124 throw new Error("should be unreachable");
125 }
126
127 /***
128 * Compares two prefixed methods. Assumes the the prefixed methods looks like this: "somePrefix SEP methodName SEP"
129 *
130 * @param m1
131 * @param m2
132 * @return int
133 */
134 private int comparePrefixed(final Method m1, final Method m2) {
135 try {
136 if (m1.equals(m2)) {
137 return 0;
138 }
139
140
141 final String[] m1Tokens = Strings.splitString(m1.getName(), TransformationConstants.DELIMITER);
142 final String[] m2Tokens = Strings.splitString(m2.getName(), TransformationConstants.DELIMITER);
143 final String m1Name = m1Tokens[1];
144 final String m2Name = m2Tokens[1];
145 if (!m1Name.equals(m2Name)) {
146 return m1Name.compareTo(m2Name);
147 }
148 final Class[] args1 = m1.getParameterTypes();
149 final Class[] args2 = m2.getParameterTypes();
150 if (args1.length < args2.length) {
151 return -1;
152 }
153 if (args1.length > args2.length) {
154 return 1;
155 }
156 if (args1.length == 0) {
157 return 0;
158 }
159 for (int i = 0; i < args1.length; i++) {
160
161 int result = TypeConverter.convertTypeToJava(args1[i]).compareTo(
162 TypeConverter.convertTypeToJava(args2[i])
163 );
164 if (result != 0) {
165 return result;
166 }
167 }
168 } catch (Throwable e) {
169 throw new WrappedRuntimeException(e);
170 }
171 java.lang.System.err.println(m1.getName());
172 java.lang.System.err.println(m2.getName());
173 throw new Error("should be unreachable");
174 }
175
176 /***
177 * Compares two methods meta-data.
178 *
179 * @param m1
180 * @param m2
181 * @return int
182 */
183 private int compareMethodInfo(final MethodInfo m1, final MethodInfo m2) {
184 try {
185 if (m1.equals(m2)) {
186 return 0;
187 }
188 final String m1Name = m1.getName();
189 final String m2Name = m2.getName();
190 if (!m1Name.equals(m2Name)) {
191 return m1Name.compareTo(m2Name);
192 }
193 final ClassInfo[] args1 = m1.getParameterTypes();
194 final ClassInfo[] args2 = m2.getParameterTypes();
195 if (args1.length < args2.length) {
196 return -1;
197 }
198 if (args1.length > args2.length) {
199 return 1;
200 }
201 if (args1.length == 0) {
202 return 0;
203 }
204 for (int i = 0; i < args1.length; i++) {
205 int result;
206 if (args1[i].getName().equals(args2[i].getName())) {
207 result = 0;
208 } else {
209 result = args1[i].getName().compareTo(args2[i].getName());
210 }
211 if (result != 0) {
212 return result;
213 }
214 }
215 } catch (Throwable e) {
216 throw new WrappedRuntimeException(e);
217 }
218 java.lang.System.err.println(m1.getName());
219 java.lang.System.err.println(m2.getName());
220 throw new Error("should be unreachable");
221 }
222 }