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    }