001    package org.bridj;
002    
003    import java.util.ArrayList;
004    import java.util.HashMap;
005    import java.util.List;
006    import java.util.Map;
007    
008    /**
009     * Collection of handles to natively-bound classes and methods (which native resources can be released all at once).
010     * @author ochafik
011     */
012    public class NativeEntities {
013            static class CBInfo {
014                    long handle;
015                    int size;
016                    public CBInfo(long handle, int size) {
017                            this.handle = handle;
018                            this.size = size;
019                    }
020                    
021            }
022            Map<Class<?>, CBInfo> 
023                    functions = new HashMap<Class<?>, CBInfo>(),
024                    virtualMethods = new HashMap<Class<?>, CBInfo>(),
025                    //getters = new HashMap<Class<?>, CBInfo>(),
026                    //setters = new HashMap<Class<?>, CBInfo>(),
027                    javaToNativeCallbacks = new HashMap<Class<?>, CBInfo>(),
028                    //cppMethods = new HashMap<Class<?>, CBInfo>(),
029                    objcMethodInfos = new HashMap<Class<?>, CBInfo>();
030    
031        /**
032         * Helper class to build a NativeEntities instance easily.
033         */
034            public static class Builder {
035                    List<MethodCallInfo> 
036                            functionInfos = new ArrayList<MethodCallInfo>(),
037                            virtualMethods = new ArrayList<MethodCallInfo>(),
038                            javaToNativeCallbacks = new ArrayList<MethodCallInfo>(),
039                            //getters = new ArrayList<MethodCallInfo>(),
040                            cppMethodInfos = new ArrayList<MethodCallInfo>(),
041                            objcMethodInfos = new ArrayList<MethodCallInfo>();
042                    //List<MethodCallInfo> getterInfos = new ArrayList<MethodCallInfo>();
043                    
044                    public void addFunction(MethodCallInfo info) {
045                            functionInfos.add(info);
046                    }
047                    public void addVirtualMethod(MethodCallInfo info) {
048                            virtualMethods.add(info);
049                    }
050                    /*public void addGetter(MethodCallInfo info) {
051                            getters.add(info);
052                    }
053                    public void addSetter(MethodCallInfo info) {
054                            getters.add(info);
055                    }*/
056                    public void addJavaToNativeCallback(MethodCallInfo info) {
057                            javaToNativeCallbacks.add(info);
058                    }
059                    public void addMethodFunction(MethodCallInfo info) {
060                            cppMethodInfos.add(info);
061                    }//*/
062                    public void addObjCMethod(MethodCallInfo info) {
063                            objcMethodInfos.add(info);
064                    }
065            }
066            
067            /**
068         * Free everything (native callbacks, bindings, etc...).<br>
069         * Called automatically by {@link NativeEntities#finalize()} upon garbage collection.
070         */
071            public void release() {
072                    if (BridJ.debugNeverFree)
073                            return;
074                    
075                    for (CBInfo callbacks : functions.values())
076                        JNI.freeCFunctionBindings(callbacks.handle, callbacks.size);
077                    
078                    /*
079                    for (CBInfo callbacks : cppMethods.values())
080                        JNI.freeCPPMethodBindings(callbacks.handle, callbacks.size);
081                    //*/
082                    for (CBInfo callbacks : javaToNativeCallbacks.values())
083                        JNI.freeJavaToCCallbacks(callbacks.handle, callbacks.size);
084    
085                    for (CBInfo callbacks : virtualMethods.values())
086                        JNI.freeVirtualMethodBindings(callbacks.handle, callbacks.size);
087    
088                    //for (CBInfo callbacks : getters.values())
089                    //    JNI.freeGetters(callbacks.handle, callbacks.size);
090    
091            for (CBInfo callbacks : objcMethodInfos.values())
092                        JNI.freeObjCMethodBindings(callbacks.handle, callbacks.size);
093            }
094            @Override
095            public void finalize() {
096                    release();
097            }
098            public void addDefinitions(Class<?> type, Builder builder) {
099                    int n;
100            try {
101    
102                    n = builder.functionInfos.size();
103                    if (n != 0)
104                            functions.put(type, new CBInfo(JNI.bindJavaMethodsToCFunctions(builder.functionInfos.toArray(new MethodCallInfo[n])), n));
105    
106                    n = builder.virtualMethods.size();
107                    if (n != 0)
108                            virtualMethods.put(type, new CBInfo(JNI.bindJavaMethodsToVirtualMethods(builder.virtualMethods.toArray(new MethodCallInfo[n])), n));
109    
110                    n = builder.javaToNativeCallbacks.size();
111                    if (n != 0)
112                            javaToNativeCallbacks.put(type, new CBInfo(JNI.bindJavaToCCallbacks(builder.javaToNativeCallbacks.toArray(new MethodCallInfo[n])), n));
113    
114                    /*
115                    n = builder.cppMethodInfos.size();
116                    if (n != 0)
117                            cppMethods.put(type, new CBInfo(JNI.bindJavaMethodsToCPPMethods(builder.cppMethodInfos.toArray(new MethodCallInfo[n])), n));
118                    //*/
119                    n = builder.objcMethodInfos.size();
120                    if (n != 0)
121                            objcMethodInfos.put(type, new CBInfo(JNI.bindJavaMethodsToObjCMethods(builder.objcMethodInfos.toArray(new MethodCallInfo[n])), n));
122    
123                    /*n = builder.getters.size();
124                    if (n != 0)
125                            getters.put(type, new CBInfo(JNI.bindGetters(builder.getters.toArray(new MethodCallInfo[n])), n));
126                    */
127            } catch (Throwable th) {
128                assert BridJ.error("Failed to add native definitions for class " + type.getName(), th);
129            }
130            }
131    }