001/*
002 * BridJ - Dynamic and blazing-fast native interop for Java.
003 * http://bridj.googlecode.com/
004 *
005 * Copyright (c) 2010-2013, Olivier Chafik (http://ochafik.com/)
006 * All rights reserved.
007 *
008 * Redistribution and use in source and binary forms, with or without
009 * modification, are permitted provided that the following conditions are met:
010 * 
011 *     * Redistributions of source code must retain the above copyright
012 *       notice, this list of conditions and the following disclaimer.
013 *     * Redistributions in binary form must reproduce the above copyright
014 *       notice, this list of conditions and the following disclaimer in the
015 *       documentation and/or other materials provided with the distribution.
016 *     * Neither the name of Olivier Chafik nor the
017 *       names of its contributors may be used to endorse or promote products
018 *       derived from this software without specific prior written permission.
019 * 
020 * THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY
021 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
023 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
024 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
027 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030 */
031package org.bridj;
032
033import java.util.ArrayList;
034import java.util.HashMap;
035import java.util.List;
036import java.util.Map;
037
038/**
039 * Collection of handles to natively-bound classes and methods (which native
040 * resources can be released all at once).
041 *
042 * @author ochafik
043 */
044public class NativeEntities {
045
046    static class CBInfo {
047
048        long handle;
049        int size;
050
051        public CBInfo(long handle, int size) {
052            this.handle = handle;
053            this.size = size;
054        }
055    }
056    Map<Class<?>, CBInfo> functions = new HashMap<Class<?>, CBInfo>(),
057            virtualMethods = new HashMap<Class<?>, CBInfo>(),
058            //getters = new HashMap<Class<?>, CBInfo>(),
059            //setters = new HashMap<Class<?>, CBInfo>(),
060            javaToNativeCallbacks = new HashMap<Class<?>, CBInfo>(),
061            //cppMethods = new HashMap<Class<?>, CBInfo>(),
062            objcMethodInfos = new HashMap<Class<?>, CBInfo>();
063
064    /**
065     * Helper class to build a NativeEntities instance easily.
066     */
067    public static class Builder {
068
069        List<MethodCallInfo> functionInfos = new ArrayList<MethodCallInfo>(),
070                virtualMethods = new ArrayList<MethodCallInfo>(),
071                javaToNativeCallbacks = new ArrayList<MethodCallInfo>(),
072                //getters = new ArrayList<MethodCallInfo>(),
073                cppMethodInfos = new ArrayList<MethodCallInfo>(),
074                objcMethodInfos = new ArrayList<MethodCallInfo>();
075        //List<MethodCallInfo> getterInfos = new ArrayList<MethodCallInfo>();
076
077        public void addFunction(MethodCallInfo info) {
078            functionInfos.add(info);
079        }
080
081        public void addVirtualMethod(MethodCallInfo info) {
082            virtualMethods.add(info);
083        }
084        /*public void addGetter(MethodCallInfo info) {
085         getters.add(info);
086         }
087         public void addSetter(MethodCallInfo info) {
088         getters.add(info);
089         }*/
090
091        public void addJavaToNativeCallback(MethodCallInfo info) {
092            javaToNativeCallbacks.add(info);
093        }
094
095        public void addMethodFunction(MethodCallInfo info) {
096            cppMethodInfos.add(info);
097        }//*/
098
099        public void addObjCMethod(MethodCallInfo info) {
100            objcMethodInfos.add(info);
101        }
102    }
103
104    /**
105     * Free everything (native callbacks, bindings, etc...).<br>
106     * Called automatically by {@link NativeEntities#finalize()} upon garbage
107     * collection.
108     */
109    public void release() {
110        if (BridJ.debugNeverFree) {
111            return;
112        }
113
114        for (CBInfo callbacks : functions.values()) {
115            JNI.freeCFunctionBindings(callbacks.handle, callbacks.size);
116        }
117
118        /*
119         for (CBInfo callbacks : cppMethods.values())
120         JNI.freeCPPMethodBindings(callbacks.handle, callbacks.size);
121         //*/
122        for (CBInfo callbacks : javaToNativeCallbacks.values()) {
123            JNI.freeJavaToCCallbacks(callbacks.handle, callbacks.size);
124        }
125
126        for (CBInfo callbacks : virtualMethods.values()) {
127            JNI.freeVirtualMethodBindings(callbacks.handle, callbacks.size);
128        }
129
130        //for (CBInfo callbacks : getters.values())
131        //    JNI.freeGetters(callbacks.handle, callbacks.size);
132
133        for (CBInfo callbacks : objcMethodInfos.values()) {
134            JNI.freeObjCMethodBindings(callbacks.handle, callbacks.size);
135        }
136    }
137
138    @Override
139    public void finalize() {
140        release();
141    }
142
143    public void addDefinitions(Class<?> type, Builder builder) {
144        int n;
145        try {
146
147            n = builder.functionInfos.size();
148            if (n != 0) {
149                functions.put(type, new CBInfo(JNI.bindJavaMethodsToCFunctions(builder.functionInfos.toArray(new MethodCallInfo[n])), n));
150            }
151
152            n = builder.virtualMethods.size();
153            if (n != 0) {
154                virtualMethods.put(type, new CBInfo(JNI.bindJavaMethodsToVirtualMethods(builder.virtualMethods.toArray(new MethodCallInfo[n])), n));
155            }
156
157            n = builder.javaToNativeCallbacks.size();
158            if (n != 0) {
159                javaToNativeCallbacks.put(type, new CBInfo(JNI.bindJavaToCCallbacks(builder.javaToNativeCallbacks.toArray(new MethodCallInfo[n])), n));
160            }
161
162            /*
163             n = builder.cppMethodInfos.size();
164             if (n != 0)
165             cppMethods.put(type, new CBInfo(JNI.bindJavaMethodsToCPPMethods(builder.cppMethodInfos.toArray(new MethodCallInfo[n])), n));
166             //*/
167            n = builder.objcMethodInfos.size();
168            if (n != 0) {
169                objcMethodInfos.put(type, new CBInfo(JNI.bindJavaMethodsToObjCMethods(builder.objcMethodInfos.toArray(new MethodCallInfo[n])), n));
170            }
171
172            /*n = builder.getters.size();
173             if (n != 0)
174             getters.put(type, new CBInfo(JNI.bindGetters(builder.getters.toArray(new MethodCallInfo[n])), n));
175             */
176        } catch (Throwable th) {
177            assert BridJ.error("Failed to add native definitions for class " + type.getName(), th);
178        }
179    }
180}