001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.ejb.cfg;
031:
032: import java.lang.reflect.*;
033: import java.lang.annotation.*;
034: import java.util.*;
035:
036: import com.caucho.util.*;
037:
038: /**
039: * Represents an introspected method.
040: */
041: public class ApiMethod {
042: private static final L10N L = new L10N(ApiMethod.class);
043:
044: private ApiClass _apiClass;
045:
046: private Method _method;
047: private Class _returnType;
048: private Class[] _parameterTypes;
049: private Class[] _exceptionTypes;
050:
051: /**
052: * Creates a new method.
053: *
054: * @param topClass the top class
055: * @param method the introspected method
056: */
057: public ApiMethod(ApiClass apiClass, Method method,
058: HashMap<String, Type> typeMap) {
059: _apiClass = apiClass;
060: _method = method;
061:
062: introspect(method, typeMap);
063: }
064:
065: /**
066: * Returns the underlying method.
067: */
068: public Method getMethod() {
069: return _method;
070: }
071:
072: /**
073: * Returns the method name.
074: */
075: public String getName() {
076: return _method.getName();
077: }
078:
079: /**
080: * Returns the declaring class
081: */
082: public Class getDeclaringClass() {
083: return _method.getDeclaringClass();
084: }
085:
086: /**
087: * Returns true for a public method.
088: */
089: public boolean isPublic() {
090: return Modifier.isPublic(_method.getModifiers());
091: }
092:
093: /**
094: * Returns true for a protected method.
095: */
096: public boolean isProtected() {
097: return Modifier.isProtected(_method.getModifiers());
098: }
099:
100: /**
101: * Returns true for a static method.
102: */
103: public boolean isStatic() {
104: return Modifier.isStatic(_method.getModifiers());
105: }
106:
107: /**
108: * Returns true for a final method.
109: */
110: public boolean isFinal() {
111: return Modifier.isFinal(_method.getModifiers());
112: }
113:
114: /**
115: * Returns true for an abstract method.
116: */
117: public boolean isAbstract() {
118: return Modifier.isAbstract(_method.getModifiers());
119: }
120:
121: /**
122: * Returns the method parameter types.
123: */
124: public Class[] getParameterTypes() {
125: return _parameterTypes;
126: }
127:
128: /**
129: * Returns true for var args
130: */
131: public boolean isVarArgs() {
132: return _method.isVarArgs();
133: }
134:
135: /**
136: * Gets the return type.
137: */
138: public Class getReturnType() {
139: return _returnType;
140: }
141:
142: /**
143: * Returns the method exception types.
144: */
145: public Class[] getExceptionTypes() {
146: return _exceptionTypes;
147: }
148:
149: /**
150: * Returns true if the annotation exists.
151: */
152: public <T extends Annotation> T getAnnotation(Class<T> annType) {
153: return _method.getAnnotation(annType);
154: }
155:
156: /**
157: * Returns an annotation.
158: */
159: public boolean isAnnotationPresent(Class annotationType) {
160: return _method.isAnnotationPresent(annotationType);
161: }
162:
163: /**
164: * Returns true if the method name matches.
165: */
166: public boolean isMatch(ApiMethod method) {
167: return isMatch(method.getName(), method.getParameterTypes());
168: }
169:
170: /**
171: * Returns true if the method name matches.
172: */
173: public boolean isMatch(String name, Class[] param) {
174: if (!name.equals(_method.getName()))
175: return false;
176:
177: if (_parameterTypes.length != param.length)
178: return false;
179:
180: for (int i = 0; i < param.length; i++) {
181: if (!param[i].equals(_parameterTypes[i]))
182: return false;
183: }
184:
185: return true;
186: }
187:
188: private void introspect(Method method, HashMap<String, Type> typeMap) {
189: Type[] paramTypes = method.getGenericParameterTypes();
190:
191: _parameterTypes = new Class[paramTypes.length];
192:
193: for (int i = 0; i < paramTypes.length; i++)
194: _parameterTypes[i] = resolve(paramTypes[i], typeMap);
195:
196: _returnType = resolve(method.getGenericReturnType(), typeMap);
197:
198: Type[] exceptionTypes = method.getGenericExceptionTypes();
199:
200: _exceptionTypes = new Class[exceptionTypes.length];
201:
202: for (int i = 0; i < exceptionTypes.length; i++)
203: _exceptionTypes[i] = resolve(exceptionTypes[i], typeMap);
204: }
205:
206: private Class resolve(Type type, HashMap<String, Type> typeMap) {
207: if (type instanceof Class)
208: return (Class) type;
209: else if (type instanceof TypeVariable) {
210: TypeVariable var = (TypeVariable) type;
211:
212: Type value = typeMap.get(var.getName());
213:
214: if (value != null && value != type)
215: return resolve(value, typeMap);
216:
217: Type[] bounds = var.getBounds();
218:
219: if (bounds == null || bounds.length < 1)
220: return Object.class;
221: else
222: return resolve(bounds[0], typeMap);
223: } else if (type instanceof GenericArrayType) {
224: GenericArrayType arrayType = (GenericArrayType) type;
225:
226: Class compType = resolve(arrayType
227: .getGenericComponentType(), typeMap);
228:
229: try {
230: return Array.newInstance(compType, 0).getClass();
231: } catch (Exception e) {
232: throw new RuntimeException(e);
233: }
234: } else if (type instanceof ParameterizedType) {
235: ParameterizedType pType = (ParameterizedType) type;
236:
237: return (Class) pType.getRawType();
238: } else
239: throw new UnsupportedOperationException(type.getClass()
240: .getName());
241: }
242:
243: @Override
244: public int hashCode() {
245: return _method.getName().hashCode();
246: }
247:
248: @Override
249: public boolean equals(Object o) {
250: if (this == o)
251: return true;
252: else if (!(o instanceof ApiMethod))
253: return false;
254:
255: ApiMethod method = (ApiMethod) o;
256:
257: if (!_method.getName().equals(method._method.getName()))
258: return false;
259:
260: if (_parameterTypes.length != method._parameterTypes.length)
261: return false;
262:
263: for (int i = 0; i < _parameterTypes.length; i++) {
264: if (!_parameterTypes[i].equals(method._parameterTypes[i]))
265: return false;
266: }
267:
268: return true;
269: }
270:
271: public String getFullName() {
272: StringBuilder sb = new StringBuilder();
273:
274: sb.append(_method.getDeclaringClass().getSimpleName());
275: sb.append(".");
276: sb.append(_method.getName());
277: sb.append("(");
278: for (int i = 0; i < _parameterTypes.length; i++) {
279: if (i != 0)
280: sb.append(",");
281: sb.append(_parameterTypes[i].getSimpleName());
282: }
283: sb.append(")");
284:
285: return sb.toString();
286: }
287:
288: public String toString() {
289: StringBuilder sb = new StringBuilder();
290:
291: sb.append("ApiMethod[");
292: sb.append(_method.getDeclaringClass().getSimpleName());
293: sb.append(".");
294: sb.append(_method.getName());
295: sb.append("(");
296: for (int i = 0; i < _parameterTypes.length; i++) {
297: if (i != 0)
298: sb.append(",");
299: sb.append(_parameterTypes[i].getSimpleName());
300: }
301: sb.append(")");
302:
303: sb.append("]");
304:
305: return sb.toString();
306: }
307: }
|