001 /*******************************************************************************
002 * Copyright (c) 2009 Progress Software, Inc.
003 * Copyright (c) 2004, 2008 IBM Corporation and others.
004 *
005 * All rights reserved. This program and the accompanying materials
006 * are made available under the terms of the Eclipse Public License v1.0
007 * which accompanies this distribution, and is available at
008 * http://www.eclipse.org/legal/epl-v10.html
009 *
010 *******************************************************************************/
011 package org.fusesource.hawtjni.generator.model;
012
013 import java.lang.annotation.Annotation;
014 import java.lang.reflect.Method;
015 import java.lang.reflect.Modifier;
016 import java.util.ArrayList;
017 import java.util.Arrays;
018 import java.util.HashSet;
019 import java.util.List;
020
021 import org.fusesource.hawtjni.runtime.ArgFlag;
022 import org.fusesource.hawtjni.runtime.JniArg;
023 import org.fusesource.hawtjni.runtime.JniMethod;
024 import org.fusesource.hawtjni.runtime.MethodFlag;
025 import org.fusesource.hawtjni.runtime.T32;
026
027 import static org.fusesource.hawtjni.generator.util.TextSupport.*;
028 import static org.fusesource.hawtjni.runtime.MethodFlag.*;
029
030 /**
031 *
032 * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
033 */
034 public class ReflectMethod implements JNIMethod {
035
036 private ReflectClass declaringClass;
037 private Method method;
038
039 private List<JNIType> paramTypes32;
040 private List<JNIType> paramTypes64;
041 private List<JNIParameter> parameters;
042 private boolean unique;
043 private JniMethod annotation;
044
045 private boolean allowConversion;
046 private ReflectType returnType;
047
048 private HashSet<MethodFlag> flags;
049
050 public ReflectMethod(ReflectClass declaringClass, Method method) {
051 this.declaringClass = declaringClass;
052 this.method = method;
053 lazyLoad();
054 }
055
056 public int hashCode() {
057 return method.hashCode();
058 }
059
060 public boolean equals(Object obj) {
061 if (!(obj instanceof ReflectMethod))
062 return false;
063 return ((ReflectMethod) obj).method.equals(method);
064 }
065
066 public String toString() {
067 return method.toString();
068 }
069
070 public Method getWrapedMethod() {
071 return method;
072 }
073
074 ///////////////////////////////////////////////////////////////////
075 // JNIMethod interface methods
076 ///////////////////////////////////////////////////////////////////
077
078 public JNIClass getDeclaringClass() {
079 return declaringClass;
080 }
081
082 public int getModifiers() {
083 return method.getModifiers();
084 }
085
086 public String getName() {
087 return method.getName();
088 }
089
090 public List<JNIParameter> getParameters() {
091 lazyLoad();
092 return parameters;
093 }
094
095 public List<JNIType> getParameterTypes() {
096 lazyLoad();
097 return paramTypes32;
098 }
099
100 public List<JNIType> getParameterTypes64() {
101 lazyLoad();
102 return paramTypes64;
103 }
104
105 public JNIType getReturnType32() {
106 lazyLoad();
107 return returnType.asType32(allowConversion);
108 }
109
110 public JNIType getReturnType64() {
111 lazyLoad();
112 return returnType.asType64(allowConversion);
113 }
114
115 public boolean getFlag(MethodFlag flag) {
116 lazyLoad();
117 return flags.contains(flag);
118 }
119
120 public String getCast() {
121 lazyLoad();
122 String rc = annotation == null ? "" : annotation.cast();
123 return cast(rc);
124 }
125
126 public boolean isPointer() {
127 lazyLoad();
128 if( annotation == null ) {
129 return false;
130 }
131 return getFlag(POINTER_RETURN) || ( returnType.getWrappedClass() == Long.TYPE && getCast().endsWith("*)") );
132 }
133
134 public String getCopy() {
135 lazyLoad();
136 return annotation == null ? "" : annotation.copy();
137 }
138
139 public String getAccessor() {
140 lazyLoad();
141 return annotation == null ? "" : annotation.accessor();
142 }
143
144 public String getConditional() {
145 lazyLoad();
146
147 String parentConditional = getDeclaringClass().getConditional();
148 String myConditional = annotation == null ? null : emptyFilter(annotation.conditional());
149 if( parentConditional!=null ) {
150 if( myConditional!=null ) {
151 return parentConditional+" && "+myConditional;
152 } else {
153 return parentConditional;
154 }
155 }
156 return myConditional;
157 }
158
159 public boolean isNativeUnique() {
160 lazyLoad();
161 return unique;
162 }
163
164 public String[] getCallbackTypes() {
165 lazyLoad();
166 if( annotation==null ) {
167 return new String[0];
168 }
169
170 JniArg[] callbackArgs = annotation.callbackArgs();
171 String[] rc = new String[callbackArgs.length];
172 for (int i = 0; i < rc.length; i++) {
173 rc[i] = callbackArgs[i].cast();
174 }
175
176 return rc;
177 }
178
179 public ArgFlag[][] getCallbackFlags() {
180 lazyLoad();
181 if( annotation==null ) {
182 return new ArgFlag[0][];
183 }
184
185 JniArg[] callbackArgs = annotation.callbackArgs();
186 ArgFlag[][] rc = new ArgFlag[callbackArgs.length][];
187 for (int i = 0; i < rc.length; i++) {
188 rc[i] = callbackArgs[i].flags();
189 }
190 return rc;
191 }
192
193
194 ///////////////////////////////////////////////////////////////////
195 // Helper methods
196 ///////////////////////////////////////////////////////////////////
197 static public String emptyFilter(String value) {
198 if( value==null || value.length()==0 )
199 return null;
200 return value;
201 }
202
203 private void lazyLoad() {
204 if( flags!=null ) {
205 return;
206 }
207
208 this.annotation = this.method.getAnnotation(JniMethod.class);
209 this.allowConversion = method.getAnnotation(T32.class)!=null;
210 this.flags = new HashSet<MethodFlag>();
211 if( this.annotation!=null ) {
212 this.flags.addAll(Arrays.asList(this.annotation.flags()));
213 }
214
215 Class<?> returnType = method.getReturnType();
216 Class<?>[] paramTypes = method.getParameterTypes();
217
218 this.paramTypes32 = new ArrayList<JNIType>(paramTypes.length);
219 this.paramTypes64 = new ArrayList<JNIType>(paramTypes.length);
220 this.parameters = new ArrayList<JNIParameter>(paramTypes.length);
221 this.returnType = new ReflectType(returnType);
222
223 Annotation[][] parameterAnnotations = method.getParameterAnnotations();
224 for (int i = 0; i < paramTypes.length; i++) {
225 ReflectParameter parameter = new ReflectParameter(this, i, parameterAnnotations[i]);
226 this.parameters.add(parameter);
227 this.paramTypes32.add( parameter.getType32() );
228 this.paramTypes64.add( parameter.getType64() );
229 }
230
231 unique = true;
232 Class<?> parent = ((ReflectClass)declaringClass).getWrapedClass();
233 String name = method.getName();
234 for (Method mth : parent.getDeclaredMethods() ) {
235 if ( (mth.getModifiers()&Modifier.NATIVE) != 0 && method!=mth && !method.equals(mth) && name.equals(mth.getName())) {
236 unique = false;
237 break;
238 }
239 }
240
241 }
242 }