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