001/*******************************************************************************
002 * Copyright (C) 2009-2011 FuseSource Corp.
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 *******************************************************************************/
011package org.fusesource.hawtjni.generator.model;
012
013import java.lang.annotation.Annotation;
014import java.lang.reflect.Method;
015import java.lang.reflect.Modifier;
016import java.util.ArrayList;
017import java.util.Arrays;
018import java.util.HashSet;
019import java.util.List;
020
021import org.fusesource.hawtjni.runtime.ArgFlag;
022import org.fusesource.hawtjni.runtime.JniArg;
023import org.fusesource.hawtjni.runtime.JniMethod;
024import org.fusesource.hawtjni.runtime.MethodFlag;
025import org.fusesource.hawtjni.runtime.T32;
026
027import static org.fusesource.hawtjni.generator.util.TextSupport.*;
028import static org.fusesource.hawtjni.runtime.MethodFlag.*;
029
030/**
031 * 
032 * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
033 */
034public 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}