rjb-1.4.8/0000755000175000017500000000000012161443611011324 5ustar lunarlunarrjb-1.4.8/readme.txt0000644000175000017500000000166112161443611013326 0ustar lunarlunarRjb is Ruby-Java bridge using Java Native Interface. How to install you need to install Java2 sdk, and setup JAVA_HOME enviromental varible except for OS X. I assume that OS X's JAVA_HOME is reported by calling /usr/libexec/java_home. then, ruby setup.rb config ruby setup.rb setup (in Unix) sudo ruby setup.rb install or (in win32) ruby setup.rb install How to test in Win32 cd test ruby test.rb in Unix see test/readme.unix you must set LD_LIBRARY_PATH environmental variable to run rjb. -- Notice for opening non-ASCII 7bit filename If you'll plan to open the non-ascii character named file by Java class through Rjb, it may require to set LC_ALL environment variable in you sciprt. For example in Rails, set above line in production.rb as your environment. ENV['LC_ALL'] = 'en_us.utf8' # or ja_JP.utf8 etc. cf: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4733494 (Thanks Paul for this information). artonx@yahoo.co.jp rjb-1.4.8/readme.sj0000644000175000017500000000213412161443611013117 0ustar lunarlunar準備 ・あらかじめ環境変数にJAVA_HOMEを設定しておいてください。 ・この場合、JAVA_HOMEは、J2SDKのインストールディレクトリの必要があります。 ・あらかじめ環境変数PATHに$JAVA_HOME/binを設定しておいてください。 ・Windowsの場合、PATHには%PATH%;%JAVA_HOME%binを設定することになります。 ・ruby1.8以降が実行できるようにPATHを設定しておいてください。 インストール方法 1. unzip rjb-* 2. cd rjb-* 3. ruby setup.rb config 4. ruby setup.rb setup 5. sudo ruby setup.rb install Windowsでは、ほとんどの場合最初のsudoは不要です。「ほとんどの場合」に該当しない場合は何が必要かはわかっているはずですので説明は省略します。 実行時 ・あらかじめ環境変数にJAVA_HOMEを設定しておいてください。 ・この場合、JAVA_HOMEは、J2SDKのインストールディレクトリの必要があります。 ・Linuxに関してはLD_LIBRARY_PATHに、java2の共有オブジェクトディレクトリを設定しておく必要があります。 テストした環境 Windows2000 SP4-ruby1.8.2-j2se1.5.0, Solaris9-ruby1.8.0-j2se1.4.2, Linux 2.4.26-ruby-1.8.1-j2se1.4.2 連絡先 artonx@yahoo.co.jp http://arton.no-ip.info/collabo/backyard/?RjbQandA (記入時にはdiaryへツッコミを入れてください) rjb-1.4.8/ChangeLog0000755000175000017500000004653212161443611013113 0ustar lunarlunarSun Jun 23 2013 arton *ext/rjb.c RJB_VERSION -> 1.4.8 create typed array exactly (reported by reinvanmeeteren on https://github.com/arton/rjb/issues/23) *test/test.rb add typed array test *test/Test.java add typed array test Tue Jun 18 2013 arton *ext/load.c check fiddle has dlopen (after ruby 2.0). Tue Jun 18 2013 arton *ext/rjb.c RJB_VERSION -> 1.4.7 *ext/load.c rqeuire fiddle first, then dl. the patch originally created by Victor Lellis. Fri May 17 2013 arton *test/test.rb add Byte test Sun Apr 48 2013 arton *ext/rjb.o remove binary *ext/rjb.obj remove binary Sat Jan 26 2013 arton *ext/rjb.c RJB_VERSION -> 1.4.6 for new gem *RBridge.class Java Major Version -> 46 Sun Jan 13 2013 arton *test/test.rb add bignum argument test *ext/rjb.c accept bignum argument for 'J' this bug(or at least mis spec.) was pointed by janroesner. Thanks janroesner ! Tue Dec 17 arton *test/test.rb add test_norarg_invoke *ext/rjb.c _invoke accepts noarg method call (reported by xiao li, thanks) RJB_VERSION -> 1.4.4 for new gem Wed Nov 14 arton *ext/rjb.c RJB_VERSION -> 1.4.3 for new gem *ext/extconf.rb remove checking dl.h, rjb not need to include it. Sat Oct 6 arton *ext/rjb.c RJB_VERSION -> 1.4.2 *test/osx_jvmcheck.rb display vendor and version of JRE for OSX load test *test/osx_loadtest.rb add Oracle JVM support test for OSX *lib/rjb.rb add Oracle JVM support for OSX Sun Aug 19 arton *ext/rjb.c export bound object's original ruby object as @wrapped RJB_VERSION -> 1.4.1 *lib/rjb.rb define Rjb_JavaBridge class for support @wrapped delegation *test/test.rb add @wrapped object invoking test Sun Apr 22 arton *ext/rjb.c add Rjb_JavaProxy#initialize_proxy method for preparing proxy instance. RJB_VERSION -> 1.4.0 *lib/rjb add rjb own directory *lib/rjbextension.rb move contents into rjb/extension.rb *lib/rjb/extension.rb extension library to handle package name easily. *lib/rjb/list.rb implements each method for Iterable and Iterator. Sun Apr 22 arton *ext/rjb.c use URLClassLoader#addJar for Rjb::add_jar method. It accepts unhierarchic load order. *test/jartest2.jar for test Rjb::add_jar. this jar contains a class that extends class in jartest.jar *test/jartest.rb testing Rjb::add_jar, first jartest2.jar then jartest.jar *test/jartest2.rb testing Rjb::add_jar for an array. *test/jartest3.rb testing Rjb::add_jar in NoClassDefError condition. Sat Jan 28 arton *ext/rjb.c RJB_VERSION -> 1.3.9 *ext/jniwrap.h skip __int64 definition if already defined (for latest mingw/gcc). Sat Dec 03 arton *ext/rjb.c RJB_VERSION -> 1.3.8 ignore attach_jvm after rjb was unloaded. (Bug #29451) *test/test_unload.rb add test for unload. if Rjb run after unloading then it causes crush. Wed Nov 09 arton *ext/rjb.c RJB_VERSION -> 1.3.7 *test/test.rb (test_reraise_exception) skip test if RUBY_VERSION =~ /^1\.8/ Wed Nov 09 arton *ext/rjb.c RJB_VERSION -> 1.3.6 *ext/rjbexception.c add to_str method into the exception class. ruby internally calls the method when reraising the exception. *test/test.rb (test_reraise_exception) add reraise test Mon Jul 18 arton *ext/rjb.c fix inhiritance test. add anonymous inner class feature (as JRuby) *test/test.rb add anonymous inner class test *test/Two.java for anonymous inner class test *test/TwoCaller.java for anonymous inner class test Sat Jul 16 arton *ext/laod.c load server JVM if _WIN64 *ext/rjb.c RJB_VERSION -> 1.3.5 *test/test.rb add primitive_conversion and generic test. *test/Test.java add method that takes generic map and returns it Mon Nov 22 arton *ext/rjb.c RJB_VERSION -> 1.3.4 require 'iconv' only if RUBY_VERSION < 1.9.0 implicitly accept ruby's String for [B (byte array) copy back byte[] contents into original String *test/test.rb add string buffer test (test_bothdirection_buffer) Wed Nov 17 arton *ext/rjb.c RJB_VERSION -> 1.3.3 *ext/load.c Check JAVA_HOME before load JVM (OS X specific) change int -> size_t for 64bit OS *test/test_osxjvm.rb add new test for OS X specific JVM detection. Sat Oct 30 arton *ext/rjb.c RJB_VERSION -> 1.3.2 *extconf.rb Change OSX's include path detecting Tue Oct 26 arton *ext/rjb.c RJB_VERSION -> 1.3.1 *rjb.rake make universal-darwin gem for Mac bundled ruby. Sun Oct 24 arton *sample/filechooser.rb omit Thread use (cause JVM crush with 1.9 and StackOverflow with 1.8) Sat Oct 23 arton *ext/rjb.c RJV_VERSION -> 1.3.0 add loaded? class method. add add_classpath method (add jars without invoking load method) *ext/load.c OSX default jvm name changes to "JavaVM" (bug#28667 reported by Jeff Adams, thanks Jeff !) *ext/extconf.rb OSX javahome set to /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK *lib/rjbextension.rb use Rjb::add_classpath method instead of Kernel's class vars. *test/test.rb, test/exttest.rb fix add_jar test, previous version load them from jp directory. Tue Sep 22 arton *ext/rjb.c RJV_VERSION -> 1.2.10 add add_jars method. add_jar and add_jars can take an array of jars. *test/test.rb add calling add_jar with an array test. Tue Sep 21 arton *ext/rjb.h export ClassLoader methods *ext/load.c move ClassLoader interaction codes into rjb.c *ext/rjb.c RJV_VERSION -> 1.2.9 add add_jar method. loading classes throgh URLClassLoader if the user add Jars *lib/rjb.rb change MODIFIER module into a constant. Because it implys Rjb::import. change Config -> RbConfig for 1.9 *test/test.rb add Rjb::add_jar test *test/JarTest.java *test/jartest.jar add for Rjb::add_jar test Fri Sep 17 arton *test/test.rb sort arguments order for test_java_methods (the order is implement dependent) add fixnum conversion test for 64bit platform (test_64fixnum) *ext/rjb.c RJV_VERSION -> 1.2.8 fix rv2jlong bug, the solution was suggested by Ary Borenszweig Sun Aug 29 arton *ext/rjb.c ignore no arguments method signature. name base classes under Rjb module. *lib/rjb.rb implements public_methods and methods *test/test.rb add non arguments method sig test add methods, public_methods, java_methods test Thu Jul 22 arton *ext/rjb.c RJB_VERSION -> 1.2.6 export jv2rv for rjbexception.c *ext/rjb.h export jv2rv for rjbexception.c *ext/rjbexception.c create and keep java exception object for its properties. *test/test.rb add Exception#cause test Wed Jun 9 arton *ext/load.c accept JAVA_HOME having an extra slash at the end *ext/rjb.c RJB_VERSION -> 1.2.5 Fri Jun 5 arton *ext/rjb.h defin HAVE_LONG_LONG if no HAVE_LONG_LONG but LP64 *ext/rjb.c remove unused variables RJB_VERSION -> 1.2.4 Fri Jun 4 arton *ext/riconv.c remove unused function if build with Ruby 1.9 *ext/rjb.c RJB_VERSION -> 1.2.3 to accomodate with rubinius *ext/load.c to accomodate with rubinius *ext/rjbexception.c to accomodate with rubinius Sun May 30 arton *lib/rjbextension.rb Rjb extension from Andreas Ronge's neo4j - directly import jar by require method - Rjb::import without quotations (Java class as Ruby object) *test/exttest.rb test for rjbextension.rb *test/rjbtest.jar test file for rjbextension.rb Sat May 29 arton on behalf of atoulme *ext/rjb.c *ext/load.c *ext/rjbexception.c to accomodate with rubinius thanks atoulme ! Wed May 12 arton *test/test.rb add Class name for TestMixin module because ruby 1.9 doesn't handle the constant. Tue May 11 arton *ext/rjb.c fix duplicate method registering while no alias. add class methods for inspecting method signatures. add class_eval method for extending Java class *test/test.rb add class methods test for inspecting method signatures. add mixin tests Tue May 4 arton *ext/load.c corrected wrong function signature (BUG#28088), pointed and fixed by Romulo A. Ceccon (thanks) *ext/rjb.c using inheritance check while inspecting a object is RJB's instance (for extending it). Tue Mar 16 arton *ext/riconv.c change locale setting "" to "C", fixed by Fabien Sartor (rjb-Bugs-27968) *ext/rjb.c RJB_VERSION -> 1.2.1 Sun Nov 1 arton *ext/load.c load jvm pointed by JVM_LIB environment variable first (suggested by Ittay Dror). *ext/rjb.c RJB_VERSION -> 1.2.0 Sun Oct 11 arton *ext/extconf.rb add double quotation around include path for mingw compiler, original patched by Roger Pack (thanks) remove double quotaion around java_home variable for existing checking by File.directoy? *rjb.rake adding mingw support for the older version compatibility checking Thu Sep 10 arton *ext/load.c Correct previous code (always reload jvm if OSX < Snow Leopard) Clear DL's exception if success *ext/rjb.c RJB_VERSION -> 1.1.9 *ext/rjbexception.c fit arguments for rb_raise to shut warning down Mon Sep 07 arton *ext/load.c Check no compat type dylib after loading was failed (for Snow Leopard) *ext/rjb.c RJB_VERSION -> 1.1.8 Sun Feb 15 arton *test/test/rb add $KCODE and magic comment for iconv *ext/rjb.c RJB_VERSION -> 1.1.7 Thu Feb 5 kuwa1 *test/Test.java *test/test.rb add tests(Umlaut) *ext/rjb.c *ext/load.c fix for ruby19 Sun Nov 16 arton *ext/load.c apply hpux patch, contributed by Ittay Dror. thanks Tue Aug 26 arton *ext/load.c, rjb.c, rjb.h export safe_funcall under the prefix 'rjb'. calling DL with rb_protect for avoiding exception. Mon Aug 25 arton *ext/load.c Fix checking the result for loading alternate_jvm_type. (patch from Kumar, thanks) Thu Aug 14 arton *ext/rjb.c, load.c, etc change comment line // -> /* */ because AIX's compiler add _AIX for load.c (this patch from Ittay Dror, thanks) *ext/load.c add ALT_JVM_TYPE for alternative jvm directory (by Kumar) Sun Jul 13 arton *ext/rjb.c display warning when Rjb load jvm implicitly if $DEBUG or $VERBOSE. Mon May 26 arton *ext/rjb.c correct char primitive conversion for Bigendian machine. use macroes for loading classes *ext/load.c adjust OS X's directory *ext/extconf.rb adjust OS X's directory if Home exists Thu Mar 27 arton *ext/rjb.c mark version 1.1.4 for the next release. *test/test.rb remove unload, because it fails. It's more important to assert each functions. Thu Mar 27 arton *ext/riconv.c activate conv tables for getenv configuration. Tue Mar 5 Kuwashima *ext/rjb.c *ext/rjb.h *ext/rjbexception.c add auto load method. Tue Mar 4 Kuwashima *ext/rjbexception.c *ext/rjb.c *test/test.rb clear(ignore) exception in current java thread, before some operation. *ext/rjbexception.c *ext/rjb.c add auto load for Rjb::bind, Rjb::throw *ext/rjb.c *test/test.rb add Rjb::unbind *test/test.rb add loading rubygems Sat Feb 23 arton *test/test.rb let test_field metod use Test.class instead of Point.class *test/Test.java add a public field for testing Fri Feb 22 arton *ext/rjb.c mark version 1.1.3 for the next release. Fri Feb 22 arton *ext/rjb.c fix field reference (bug# 18238) Wed Jan 9 arton *ext/rjb.h add some ruby macros that defined after 1.8.6 for compatibility Change RBridge.class by 1.4.2 *data/rjb/jp/co/infoseek/hp/arton/rjb/RBridge.class compiled by 1.4.2 version of Java *rjb.c mark version 1.1.2 for the next release. Tue Dec 27 Kuwashima *test/Test.java *test/test.rb *ext/depend *ext/load.c *ext/extconf.rb *ext/rjbexception.c *ext/rjb.c *ext/riconv.c change for compatibility with Ruby-1.9.0 Tue Nov 20 arton *rjb.c mark version 1.10.12 for next relase. *load.c omit useless double-quotations from JAVA_HOME, maybe specifies a longpathname (but useless). Wed Nov 14 Kuwashima *rjb.c add error check to constructor. Fri Nov 9 arton *test.rb *Test.java add test for reproducing rjb-bugs-15430 *rjb.c fix rjb-bugs-15430 that caused by bad array conversion. (generics method result signature is an object, but the real result is typed array) *riconv.c correct to get the number of array element. Tue Oct 23 Kuwashima *riconv.c Change string encoding conversion rule. Mon Oct 22 Kuwashima *riconv.c *riconv.h recycle iconv instance. *test/test.rb add cases for test_kjconv Sun Sep 23 arton *rjb.c version 1.0.9 convert to Ruby's type if Rjb::primitive_converion is enalbed and the result type is java.lang.Object support the object conversion for a bignum to long. Sat Sep 15 arton *rjb.c version 1.0.8 correction of 1.0.7, support long type. Fri Sep 14 arton *rjb.c version 1.0.7 add auto primitive conversion toggled by Rjb::primitive_conversion *test.rb add test_auto_conv Sun Jun 17 arton *rjb.c add method aliases. setXxYy -> xx_yy= getXxYy -> xx_yy isXxYy -> xx_yy? xxYyZz -> xx_yy_zz *test.rb add a test for the method alias feature. Tue Nov 21 arton *rjb.c Skip the constant registering process, if the constant was already defined. *load.c *rjb.c *rjbexception.c *rjb.h add prefix 'rjb' for externed symbol names to avoid confliction. Sun Oct 08 arton (on behalf of richard apodaca) *load.c support AMD64 Mon Sep 11 arton *test.rb add a test of arguments types are various array. *Test.java add a test of arguments types are various array. *rjb.c accept nil for array parameter. Sun Sep 10 arton *test.rb add a test of return type is an object wrapped an array *Test.java add a method that returns an object wrapped an array *rjb.c check array-mark in jv2rv for returned object was an array Tue Aug 1 arton *load.c *rjb.c change load pathname of the bridge class. *post-install.rb add for remove previous installed rjb.so. *rjb.rake add for build Gem. *rjb.rb for preparing the pathname constant of the bridge class. *depend chage binary name from rjb.so to rjbcore.so *extconf.rb chage binary name from rjb.so to rjbcore.so Mon Jul 31 arton *load.c fix buffer allocation Sun Jul 16 (Jun 22) Kuwashima and arton *rjb.c version 0.2.8 *MANIFEST *depend *load.c *rjbexception.c change jni.h to jniwrap.h. change the bridge class's header according to JDK 5.0's javah. *jniwrap.h wrap jni.h for Cygin Sat Jun 10 14:10:05 2006 arton *rjb.c version 0.2.7 support an array of arrays from ruby to java. Mon May 8 08:52:12 2006 arton *load.c revision 5 support both Intel and PPC Mac. Patched version was contributed by Demetrius Nunes. Wed Apr 12 03:57:12 2006 arton *rjb.c version 0.2.6 support an array of arrays. *test.rb add an array of arrays test, some tests are contributed by Darren Day. *Test.java add a test method that returns an array of arrays, some tests are contributed by Darren Day. Sat Dec 24 18:56:38 2005 arton *rjb.c version 0.2.5 release String, Float, Array object after method call. *gctest.rb add for String object gc test Mon Sep 19 01:09:30 2005 arton *rjb.c version 0.2.4 use null instead of empty string when String argument is nil omit unused local variable from jstring2val *test.rb add null string test (bug since utf-8 support) Tue Jun 28 01:57:07 2005 arton *rjb.c version 0.2.3 convert result object to imported class if object is an instance of Class call Class#forName if argument count is 1 *test.rb add test_importobj contributed by Mr. Kuwashima, thanks. Mon Jun 27 20:30:50 2005 arton treat Class.forName as Rjb::import *rjb.c version 0.2.2 add method 'forName' into imported Class object if pass imported object to JVM, extract Class object from ruby object *test.rb add above tests Sat Jun 25 05:58:36 2005 arton most bugs were reported by Mr. Micael Weller, thanks. *rjb.c version 0.2.1 correct derived static method search search class methods then class's instance methods when called by class avoid register non capitalized named constants into constants table correct capitalized named method search *riconv.c never call iconv if $KCODE is nil *load.c using path separator ; for cygwin (by Ryugate) Sun Apr 24 05:26:16 2005 arton *rb.c version 0.2.0 delete localref if globalref was created. load can take the second argument for jvm *load.c load can take the second argument for jvm Mon Jan 17 02:40:21 2005 arton *rjb.c add 'throw' module function. move java exception handling functions into newly created rjbexception.c *rjb.h declations for rjb.c and rjbexception.c *rjbexception.c java exception handling functions, and 'throw' module function. *test.rb adding throw test. Wed Jan 12 00:01:08 2005 Kaspar Schiess and arton *rjb.c correct Rjb::load parameter evaluation (classpath). - many thanks to Mr.Schiess. Sun Nov 21 02:51:43 2004 Kuwashima and arton *rjb.c move dbcs-utf-8 auto conversion feature into riconv.? remove JNI version argument from Rjb::load. (bug reported by Mr.Tateishi) *load.c correct CLASSPATH setting (bad environment name).(bug reported by Mr.Tateishi) *riconv.c riconv.h (contributed by Mr.Kuwashima) DBCS - utf-8 auto conversion functions. *depend MANIFEST add riconv.? - many tanks to Mr.Kuwashima and Mr.Tateishi. Tue Oct 5 23:08:59 2004 Kuwashima and arton *test.rb add kanji conversion test *rjb.c add dbcs(sjis and euc-jp) - utf-8 auto conversion feature. the patch was contributed by Mr.Kuwashima, many thanks. Sun Oct 3 18:24:42 2004 arton *load.c JNIEnv* now using local variable instead of global one. Because AWT event use a worker thread, and JNI need thread's owned JNIEnv. *rjb.c JNIEnv* now using local variable instead of global one. Because AWT event use a worker thread, and JNI need thread's owned JNIEnv. This change was suggested by Mr.Kuwashima, he also tested the behavior, and gave me some test codes. and attach_current_thread is from Mr.Kuwashima's patch. Many thanks to Mr.Kuwashima. Sat Sep 25 03:25:45 2004 arton *rjb.c implements interface's method argument conversion. *test.rb add Comparable test (interface with method arguments) *Test.java add Comparable test method. Wed Sep 22 02:30:15 2004 arton *rjb.c correct constants load, using mid-class. convert null string to nil Wed Sep 22 00:05:32 2004 arton *rjb.c correct ruby type checking. If the parameter type is java.lang.String, rjb instance is always accepted. Mon Sep 20 22:02:53 2004 arton *rjb.c checking method/constructor signature with class when the argument is rjb's instance. Sun Sep 19 00:54:35 2004 arton *rjb.c convert Java exception to Ruby's StandardError derived class. checking method/constructor signature when invoking if no signatur argument is supplied. adding field accessor. Sun Sep 12 21:42:00 2004 arton *rjb.c call exception description when verbose = true. correct recursive import call (for Boolean). corrent method not found message creation. rjb-1.4.8/rjb.rake0000644000175000017500000000326012161443611012746 0ustar lunarlunarrequire 'rubygems' require 'rake/gempackagetask' require 'fileutils' def read_version File.open('ext/rjb.c').each_line do |x| m = /RJB_VERSION\s+"(.+?)"/.match(x) if m return m[1] end end nil end desc "Default Task" task :default => [ :package ] spec = Gem::Specification.new do |s| s.authors = 'arton' s.email = 'artonx@gmail.com' if /mswin|mingw|darwin/ =~ RUBY_PLATFORM s.platform = Gem::Platform::CURRENT else s.platform = Gem::Platform::RUBY s.extensions << 'ext/extconf.rb' end s.required_ruby_version = '>= 1.8.2' s.summary = 'Ruby Java bridge' s.name = 'rjb' s.homepage = 'http://rjb.rubyforge.org/' s.rubyforge_project = 'rjb' s.version = read_version s.requirements << 'none' s.require_path = 'lib' s.requirements << 'JDK 5.0' files = FileList['ext/*.java', 'ext/*.c', 'ext/*.h', 'ext/depend', 'data/rjb/**/*.class', 'lib/*.rb', 'samples/**/*.rb', 'test/*.rb', 'test/**/*.class', 'test/*.jar', 'COPYING', 'ChangeLog', 'readme.*'] if /mswin|mingw/ =~ RUBY_PLATFORM FileUtils.cp 'ext/rjbcore.so', 'lib/rjbcore.so' files << "lib/rjbcore.so" s.requirements << ' VC6 version of Ruby' if RUBY_PLATFORM =~ /mswin/ elsif /darwin/ =~ RUBY_PLATFORM FileUtils.cp 'ext/rjbcore.bundle', 'lib/rjbcore.bundle' files << "lib/rjbcore.bundle" end s.files = files s.test_file = 'test/test.rb' s.description = < Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! rjb-1.4.8/ext/0000755000175000017500000000000012161443611012124 5ustar lunarlunarrjb-1.4.8/ext/MANIFEST0000644000175000017500000000014612161443611013256 0ustar lunarlunarMANIFEST rjb.h riconv.h riconv.c rjb.c load.c rjbexception.c extconf.rb RBridge.java depend jniwrap.h rjb-1.4.8/ext/load.c0000644000175000017500000002765512161443611013226 0ustar lunarlunar/* * Rjb - Ruby <-> Java Bridge * Copyright(c) 2004,2005,2006,2009,2010,2011 arton * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * $Id: load.c 180 2011-12-05 16:34:29Z arton $ */ #include #include #include "ruby.h" #include "extconf.h" #if RJB_RUBY_VERSION_CODE < 190 #include "intern.h" #include "st.h" #include "util.h" #else #include "ruby/intern.h" #include "ruby/st.h" #include "ruby/util.h" #endif #include "jniwrap.h" #include "jp_co_infoseek_hp_arton_rjb_RBridge.h" #include "rjb.h" #define JVM_TYPE "client" #define ALT_JVM_TYPE "classic" #if defined(_WIN32) || defined(__CYGWIN__) #if defined(__CYGWIN__) #define JVMDLL "%s/jre/bin/%s/jvm.dll" #define DIRSEPARATOR '/' #else #define JVMDLL "%s\\jre\\bin\\%s\\jvm.dll" #define DIRSEPARATOR '\\' #if defined(_WIN64) #undef JVM_TYPE #define JVM_TYPE "server" #endif #endif #define CLASSPATH_SEP ';' #elif defined(__APPLE__) && defined(__MACH__) static char* JVMDLL = "%s/JavaVM"; #define DIRSEPARATOR '/' #define CLASSPATH_SEP ':' #define HOME_NAME "/Home" #define HOME_NAME_LEN strlen(HOME_NAME) #define DEFAULT_HOME "/System/Library/Frameworks/JavaVM.framework" #elif defined(_AIX) #define ARCH "ppc" #undef JVM_TYPE #define JVM_TYPE "j9vm" #elif defined(__hpux) #define JVMDLL "%s/jre/lib/%s/%s/libjvm.sl" #define ARCH "PA_RISC" #undef JVM_TYPE #define JVM_TYPE "server" #define DIRSEPARATOR '/' #define CLASSPATH_SEP ':' #else /* defined(_WIN32) || defined(__CYGWIN__) */ #if defined(__sparc_v9__) #define ARCH "sparcv9" #elif defined(__sparc__) #define ARCH "sparc" #elif defined(__amd64__) #define ARCH "amd64" #undef JVM_TYPE #define JVM_TYPE "server" #elif defined(i586) || defined(__i386__) #define ARCH "i386" #endif #ifndef ARCH #include #endif #define JVMDLL "%s/jre/lib/%s/%s/libjvm.so" #define DIRSEPARATOR '/' #define CLASSPATH_SEP ':' #endif #if defined(__APPLE__) && defined(__MACH__) static char* CREATEJVM = "JNI_CreateJavaVM"; static char* GETDEFAULTJVMINITARGS = "JNI_GetDefaultJavaVMInitArgs"; #else #define CREATEJVM "JNI_CreateJavaVM" #define GETDEFAULTJVMINITARGS "JNI_GetDefaultJavaVMInitArgs" #endif typedef int (JNICALL *GETDEFAULTJAVAVMINITARGS)(void*); typedef int (JNICALL *CREATEJAVAVM)(JavaVM**, JNIEnv**, void*); static VALUE jvmdll = Qnil; static VALUE getdefaultjavavminitargsfunc; static VALUE createjavavmfunc; static const char* DLLibs[] = { "fiddle", "dl" }; static const char* DLNames[] = { "Fiddle", "DL" }; static VALUE safe_require(VALUE args) { return rb_require(StringValueCStr(args)); } static int open_jvm(char* libpath) { int sstat; VALUE* argv; size_t i; int state; #if defined(RUBINIUS) i = 1; #else i = 0; #endif for (; i < COUNTOF(DLLibs); i++) { state = 0; rb_protect(safe_require, rb_str_new2(DLLibs[i]), &state); #if !defined(RUBINIUS) if (state || !rb_const_defined_at(rb_cObject, rb_intern(DLNames[i]))) { if (i > 0) { rb_raise(rb_eRuntimeError, "Constants DL and Fiddle is not defined."); return 0; } } else #endif { sstat = 0; argv = ALLOCA_N(VALUE, 4); *argv = rb_const_get(rb_cObject, rb_intern(DLNames[i])); *(argv + 1) = rb_intern("dlopen"); *(argv + 2) = 1; *(argv + 3) = rb_str_new2(libpath); jvmdll = rb_protect(rjb_safe_funcall, (VALUE)argv, &sstat); if (!sstat) { break; } else if (i > 0) { return 0; } } } /* get function pointers of JNI */ #if RJB_RUBY_VERSION_CODE < 190 getdefaultjavavminitargsfunc = rb_funcall(rb_funcall(rb_funcall(jvmdll, rb_intern("[]"), 2, rb_str_new2(GETDEFAULTJVMINITARGS), rb_str_new2("IP")), rb_intern("to_ptr"), 0), rb_intern("to_i"), 0); createjavavmfunc = rb_funcall(rb_funcall(rb_funcall(jvmdll, rb_intern("[]"), 2, rb_str_new2(CREATEJVM), rb_str_new2("IPPP")), rb_intern("to_ptr"), 0), rb_intern("to_i"), 0); #else getdefaultjavavminitargsfunc = rb_funcall(jvmdll, rb_intern("[]"), 1, rb_str_new2(GETDEFAULTJVMINITARGS)); createjavavmfunc = rb_funcall(jvmdll, rb_intern("[]"), 1, rb_str_new2(CREATEJVM)); #endif return 1; } #if defined(__APPLE__) && defined(__MACH__) static int file_exist(const char* dir, const char* file) { VALUE path = rb_funcall(rb_cFile, rb_intern("join"), 2, rb_str_new2(dir), rb_str_new2(file)); VALUE ret = rb_funcall(rb_cFile, rb_intern("exist?"), 1, path); return RTEST(ret); } #endif /* * not completed, only valid under some circumstances. */ static int load_jvm(const char* jvmtype) { char* libpath; char* java_home; char* jh; jh = getenv("JAVA_HOME"); #if defined(__APPLE__) && defined(__MACH__) if (!jh) { jh = DEFAULT_HOME; } else { if (strlen(jh) > HOME_NAME_LEN) { size_t len = strlen(jh); char* p = ALLOCA_N(char, len + 8); jh = strcpy(p, jh); if (*(jh + len - 1) == '/') { --len; *(jh + len) = '\0'; } if (strcasecmp(jh + len - HOME_NAME_LEN, HOME_NAME) == 0) { strcpy(p + len, "/.."); } } if (!jvmtype && !file_exist(jh, "JavaVM")) { jh = DEFAULT_HOME; } } #endif if (!jh) { if (RTEST(ruby_verbose)) { fprintf(stderr, "no JAVA_HOME environment\n"); } return 0; } #if defined(_WIN32) if (*jh == '"' && *(jh + strlen(jh) - 1) == '"') { char* p = ALLOCA_N(char, strlen(jh) + 1); strcpy(p, jh + 1); *(p + strlen(p) - 1) = '\0'; jh = p; } #endif java_home = ALLOCA_N(char, strlen(jh) + 1); strcpy(java_home, jh); if (*(java_home + strlen(jh) - 1) == DIRSEPARATOR) { *(java_home + strlen(jh) - 1) = '\0'; } #if defined(_WIN32) || defined(__CYGWIN__) libpath = ALLOCA_N(char, sizeof(JVMDLL) + strlen(java_home) + strlen(jvmtype) + 1); sprintf(libpath, JVMDLL, java_home, jvmtype); #elif defined(__APPLE__) && defined(__MACH__) libpath = ALLOCA_N(char, sizeof(JVMDLL) + strlen(java_home) + 1); sprintf(libpath, JVMDLL, java_home); #else /* not Windows / MAC OS-X */ libpath = ALLOCA_N(char, sizeof(JVMDLL) + strlen(java_home) + strlen(ARCH) + strlen(jvmtype) + 1); sprintf(libpath, JVMDLL, java_home, ARCH, jvmtype); #endif return open_jvm(libpath); } static int load_bridge(JNIEnv* jenv) { JNINativeMethod nmethod[1]; jbyte buff[8192]; char* bridge; size_t len; FILE* f; #if defined(RUBINIUS) VALUE v = rb_const_get(rb_cObject, rb_intern("RjbConf")); v = rb_const_get(v, rb_intern("BRIDGE_FILE")); #else VALUE v = rb_const_get_at(rb_const_get(rb_cObject, rb_intern("RjbConf")), rb_intern("BRIDGE_FILE")); #endif bridge = StringValuePtr(v); #if defined(DOSISH) bridge = ALLOCA_N(char, strlen(bridge) + 8); strcpy(bridge, StringValuePtr(v)); for (len = 0; bridge[len]; len++) { if (bridge[len] == '/') { bridge[len] = '\\'; } } #endif f = fopen(bridge, "rb"); if (f == NULL) { return -1; } len = fread(buff, 1, sizeof(buff), f); fclose(f); rjb_rbridge = (*jenv)->DefineClass(jenv, "jp/co/infoseek/hp/arton/rjb/RBridge", get_systemloader(jenv), buff, len); if (rjb_rbridge == NULL) { rjb_check_exception(jenv, 1); } rjb_register_bridge = (*jenv)->GetMethodID(jenv, rjb_rbridge, "register", "(Ljava/lang/Class;)Ljava/lang/Object;"); nmethod[0].name = "call"; nmethod[0].signature = "(Ljava/lang/String;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"; nmethod[0].fnPtr = Java_jp_co_infoseek_hp_arton_rjb_RBridge_call; (*jenv)->RegisterNatives(jenv, rjb_rbridge, nmethod, 1); rjb_rbridge = (*jenv)->NewGlobalRef(jenv, rjb_rbridge); return 0; } void rjb_unload_vm() { if (RTEST(jvmdll)) { rb_funcall(jvmdll, rb_intern("close"), 0); jvmdll = Qnil; } } int rjb_create_jvm(JNIEnv** pjenv, JavaVMInitArgs* vm_args, char* userpath, VALUE argv) { static JavaVMOption soptions[] = { #if defined(__sparc_v9__) || defined(__sparc__) { "-Xusealtsigs", NULL }, #elif defined(linux) || defined(__linux__) { "-Xrs", NULL }, #elif defined(__APPLE__) && defined(_ARCH_PPC) { "-Xrs", NULL }, #endif #if defined(SHOW_JAVAGC) { "-verbose:gc", NULL }, #endif { "DUMMY", NULL }, /* for classpath count */ }; char* newpath; size_t len; int result; GETDEFAULTJAVAVMINITARGS initargs; CREATEJAVAVM createjavavm; JavaVMOption* options; size_t optlen; size_t i; VALUE optval; if (!RTEST(jvmdll)) { char* libjvm = getenv("JVM_LIB"); #if defined(_WIN32) if (libjvm && *libjvm == '"' && *(libjvm + strlen(libjvm) - 1) == '"') { char* p = ALLOCA_N(char, strlen(libjvm) + 1); strcpy(p, libjvm + 1); *(p + strlen(p) - 1) = '\0'; libjvm = p; } #endif if (libjvm == NULL || !open_jvm(libjvm)) { #if defined(__APPLE__) && defined(__MACH__) if (!(load_jvm(NULL))) { JVMDLL = "%s/Libraries/libjvm.dylib"; CREATEJVM = "JNI_CreateJavaVM_Impl"; GETDEFAULTJVMINITARGS = "JNI_GetDefaultJavaVMInitArgs_Impl"; #endif if (!(load_jvm(JVM_TYPE) || load_jvm(ALT_JVM_TYPE))) { return -1; } #if defined(__APPLE__) && defined(__MACH__) } #endif } #if RJB_RUBY_VERSION_CODE < 190 && !defined(RUBINIUS) ruby_errinfo = Qnil; #else rb_set_errinfo(Qnil); #endif } if (NIL_P(getdefaultjavavminitargsfunc)) { return -1; } initargs = (GETDEFAULTJAVAVMINITARGS)NUM2ULONG(getdefaultjavavminitargsfunc); result = initargs(vm_args); if (0 > result) { return result; } len = strlen(userpath); if (getenv("CLASSPATH")) { len += strlen(getenv("CLASSPATH")); } newpath = ALLOCA_N(char, len + 32); if (getenv("CLASSPATH")) { sprintf(newpath, "-Djava.class.path=%s%c%s", userpath, CLASSPATH_SEP, getenv("CLASSPATH")); } else { sprintf(newpath, "-Djava.class.path=%s", userpath); } optlen = 0; if (!NIL_P(argv)) { optlen += RARRAY_LEN(argv); } optlen += COUNTOF(soptions); options = ALLOCA_N(JavaVMOption, optlen); options->optionString = newpath; options->extraInfo = NULL; for (i = 1; i < COUNTOF(soptions); i++) { *(options + i) = soptions[i - 1]; } for (; i < optlen; i++) { optval = rb_ary_entry(argv, i - COUNTOF(soptions)); Check_Type(optval, T_STRING); (options + i)->optionString = StringValueCStr(optval); (options + i)->extraInfo = NULL; } vm_args->nOptions = (int)optlen; vm_args->options = options; vm_args->ignoreUnrecognized = JNI_TRUE; if (NIL_P(createjavavmfunc)) { return -1; } createjavavm = (CREATEJAVAVM)NUM2ULONG(createjavavmfunc); result = createjavavm(&rjb_jvm, pjenv, vm_args); if (!result) { result = load_bridge(*pjenv); if (RTEST(ruby_verbose) && result < 0) { fprintf(stderr, "failed to load the bridge class\n"); } } return result; } rjb-1.4.8/ext/depend0000644000175000017500000000360212161443611013307 0ustar lunarlunarriconv.o : riconv.c jp_co_infoseek_hp_arton_rjb_RBridge.h rjb.o : rjb.c jp_co_infoseek_hp_arton_rjb_RBridge.h riconv.h rjb.h rjbexception.o : rjbexception.c jp_co_infoseek_hp_arton_rjb_RBridge.h riconv.h rjb.h load.o : load.c jp_co_infoseek_hp_arton_rjb_RBridge.h jp_co_infoseek_hp_arton_rjb_RBridge.h : jniwrap.h ../data/rjb/jp/co/infoseek/hp/arton/rjb/RBridge.class javah -classpath ../data/rjb jp.co.infoseek.hp.arton.rjb.RBridge ../data/rjb/jp/co/infoseek/hp/arton/rjb/RBridge.class : RBridge.java mkdir -p ../data/rjb/jp/co/infoseek/hp/arton/rjb javac -d ../data/rjb RBridge.java test : rjbcore.so ../test/jp/co/infoseek/hp/arton/rjb/Test.class ../test/jp/co/infoseek/hp/arton/rjb/IBase.class ../test/jp/co/infoseek/hp/arton/rjb/Base.class ../test/jp/co/infoseek/hp/arton/rjb/ExtBase.class ruby ../test/test.rb ../test/jp/co/infoseek/hp/arton/rjb/Test.class : ../test/Test.java javac ../test/Test.java $(RUBY) -r fileutils -e 'FileUtils.mkdir_p "../test/jp/co/infoseek/hp/arton/rjb";FileUtils.mv("../test/Test.class", "../test/jp/co/infoseek/hp/arton/rjb")' ../test/jp/co/infoseek/hp/arton/rjb/IBase.class : ../test/IBase.java javac ../test/IBase.java $(RUBY) -r fileutils -e 'FileUtils.mkdir_p "../test/jp/co/infoseek/hp/arton/rjb";FileUtils.mv("../test/IBase.class", "../test/jp/co/infoseek/hp/arton/rjb")' ../test/jp/co/infoseek/hp/arton/rjb/Base.class : ../test/Base.java ../test/jp/co/infoseek/hp/arton/rjb/IBase.class javac -classpath ../test ../test/Base.java $(RUBY) -r fileutils -e 'FileUtils.mkdir_p "../test/jp/co/infoseek/hp/arton/rjb";FileUtils.mv("../test/Base.class", "../test/jp/co/infoseek/hp/arton/rjb")' ../test/jp/co/infoseek/hp/arton/rjb/ExtBase.class : ../test/ExtBase.java javac -classpath ../test ../test/ExtBase.java $(RUBY) -r fileutils -e 'FileUtils.mkdir_p "../test/jp/co/infoseek/hp/arton/rjb";FileUtils.mv("../test/ExtBase.class", "../test/jp/co/infoseek/hp/arton/rjb")' rjb-1.4.8/ext/riconv.h0000644000175000017500000000141012161443611013571 0ustar lunarlunar/* * Rjb - Ruby <-> Java Bridge * Copyright(c) 2004 Kuwashima * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * $Id: riconv.h 43 2007-12-26 18:55:04Z kuwa1 $ */ #ifndef _RICONV_H #define _RICONV_H VALUE exticonv_local_to_utf8(VALUE); VALUE exticonv_utf8_to_local(VALUE); #endif /* _RICONV_H */ rjb-1.4.8/ext/rjb.h0000644000175000017500000001030212161443611013046 0ustar lunarlunar/* * Rjb - Ruby <-> Java Bridge * Copyright(c) 2004,2005 arton * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * $Id: rjb.h 180 2011-12-05 16:34:29Z arton $ * $Log: rjb.h,v $ * Revision 1.1 2005/01/16 17:36:10 arton * Initial revision * * */ #ifndef RJB_H #define RJB_H #if RJB_RUBY_VERSION_CODE < 190 #if !defined(RHASH_TBL) #define RHASH_TBL(x) RHASH((x))->tbl #endif #endif #if !defined(RSTRING_LEN) #define RSTRING_LEN(s) (RSTRING(s)->len) #endif #if !defined(RSTRING_PTR) #define RSTRING_PTR(s) (RSTRING(s)->ptr) #endif #if !defined(RARRAY_LEN) #define RARRAY_LEN(s) (RARRAY(s)->len) #endif #if !defined(RARRAY_PTR) #define RARRAY_PTR(s) (RARRAY(s)->ptr) #endif #if !defined(COUNTOF) #define COUNTOF(x) (sizeof(x)/sizeof(x[0])) #endif #if !defined(_I64_MIN) #define _I64_MIN (-9223372036854775807i64 - 1) #endif #if !defined(_I64_MAX) #define _I64_MAX 9223372036854775807i64 #endif #if !defined(HAVE_LONG_LONG) && defined(__LP64__) #define HAVE_LONG_LONG 1 #endif /* in load.c */ extern int rjb_create_jvm(JNIEnv** pjenv, JavaVMInitArgs*, char*, VALUE); /* in rjb.c */ extern JavaVM* rjb_jvm; extern jclass rjb_rbridge; extern jmethodID rjb_register_bridge; extern VALUE rjb_loaded_classes; extern jmethodID rjb_class_getName; extern jclass rjb_j_throwable; extern jmethodID rjb_throwable_getMessage; extern JNIEnv* rjb_attach_current_thread(void); extern jclass rjb_find_class(JNIEnv* jenv, VALUE name); extern void rjb_release_string(JNIEnv *jenv, jstring str, const char* chrs); extern VALUE rjb_load_vm_default(); extern void rjb_unload_vm(); extern VALUE rjb_safe_funcall(VALUE args); extern VALUE jv2rv(JNIEnv* jenv, jvalue val); extern jobject get_systemloader(JNIEnv* jenv); extern jclass rjb_find_class_by_name(JNIEnv* jenv, const char* name); /* in rjbexception.c */ extern VALUE rjb_get_exception_class(JNIEnv* jenv, jstring str); extern void rjb_check_exception(JNIEnv* jenv, int t); extern VALUE rjb_s_throw(int, VALUE*, VALUE); /* conversion functions */ typedef void (*R2J)(JNIEnv*, VALUE, jvalue*, const char*, int); typedef VALUE (*J2R)(JNIEnv*, jvalue); typedef jarray (*R2JARRAY)(JNIEnv*, VALUE, const char*); typedef void (JNICALL *RELEASEARRAY)(JNIEnv*, jobject, void*, jint); typedef jlong (JNICALL *INVOKEAL)(JNIEnv*, jobject, jmethodID, const jvalue*); typedef jdouble (JNICALL *INVOKEAD)(JNIEnv*, jobject, jmethodID, const jvalue*); typedef jfloat (JNICALL *INVOKEAF)(JNIEnv*, jobject, jmethodID, const jvalue*); typedef jboolean (JNICALL *INVOKEAZ)(JNIEnv*, jobject, jmethodID, const jvalue*); typedef jshort (JNICALL *INVOKEAS)(JNIEnv*, jobject, jmethodID, const jvalue*); typedef jobject (JNICALL *INVOKEA)(JNIEnv*, jobject, jmethodID, const jvalue*); typedef VALUE (*CONV)(JNIEnv*, void*); /* * internal method class */ struct cls_constructor { jmethodID id; int arg_count; R2J* arg_convert; char* method_signature; char result_signature; char result_arraydepth; }; struct cls_method { struct cls_constructor basic; ID name; int static_method; off_t method; J2R result_convert; /* overload only */ struct cls_method* next; }; /* * internal field class */ struct cls_field { ID name; jfieldID id; char* field_signature; char result_signature; char result_arraydepth; R2J arg_convert; J2R value_convert; int readonly; int static_field; }; /* * Object instance */ struct jvi_data { jclass klass; /* class */ jobject obj; /* instance */ st_table* methods; st_table* fields; }; /* * Class instance */ struct jv_data { struct jvi_data idata; st_table* static_methods; struct cls_constructor** constructors; }; /* * Bridge instance */ struct rj_bridge { jobject bridge; jobject proxy; VALUE wrapped; }; #endif rjb-1.4.8/ext/extconf.rb0000644000175000017500000000323412161443611014121 0ustar lunarlunar#---------------------------------- # extconf.rb # $Revision: $ # $Date: $ #---------------------------------- require 'mkmf' class Path def initialize() if File::ALT_SEPARATOR.nil? @file_separator = File::SEPARATOR else @file_separator = File::ALT_SEPARATOR end end def include(parent, child) inc = joint(parent, child) $INCFLAGS += " -I\"#{inc}\"" $CFLAGS += " -I\"#{inc}\"" inc end def joint(parent, child) parent + @file_separator + child end end javahome = ENV['JAVA_HOME'] if javahome.nil? && RUBY_PLATFORM =~ /darwin/ javahome = `/usr/libexec/java_home`.strip end unless javahome.nil? if javahome[0] == ?" && javahome[-1] == ?" javahome = javahome[1..-2] end raise "JAVA_HOME is not directory." unless File.directory?(javahome) pt = Path.new inc = pt.include(javahome, 'include') if !File.exists?(inc) && RUBY_PLATFORM =~ /darwin/ inc = pt.include('/System/Library/Frameworks/JavaVM.framework', 'Headers') end Dir.open(inc).each do |d| next if d[0] == ?. if File.directory?(pt.joint(inc, d)) pt.include(inc, d) break end end else raise "JAVA_HOME is not set." end def create_rjb_makefile if have_header("jni.h") have_func("locale_charset", "iconv.h") have_func("nl_langinfo", "langinfo.h") have_func("setlocale", "locale.h") have_func("getenv") $defs << "-DRJB_RUBY_VERSION_CODE="+RUBY_VERSION.gsub(/\./, '') create_header create_makefile("rjbcore") else raise "no jni.h in " + $INCFLAGS end end case RUBY_PLATFORM when /mswin32/ $CFLAGS += ' /W3' when /cygwin/, /mingw/ $defs << '-DNONAMELESSUNION' end create_rjb_makefile rjb-1.4.8/ext/jp_co_infoseek_hp_arton_rjb_RBridge.h0000644000175000017500000000116412161443611021401 0ustar lunarlunar/* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class jp_co_infoseek_hp_arton_rjb_RBridge */ #ifndef _Included_jp_co_infoseek_hp_arton_rjb_RBridge #define _Included_jp_co_infoseek_hp_arton_rjb_RBridge #ifdef __cplusplus extern "C" { #endif /* * Class: jp_co_infoseek_hp_arton_rjb_RBridge * Method: call * Signature: (Ljava/lang/String;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; */ JNIEXPORT jobject JNICALL Java_jp_co_infoseek_hp_arton_rjb_RBridge_call (JNIEnv *, jobject, jstring, jobject, jobjectArray); #ifdef __cplusplus } #endif #endif rjb-1.4.8/ext/jniwrap.h0000644000175000017500000000172612161443611013755 0ustar lunarlunar/* * Rjb - Ruby <-> Java Bridge * Copyright(c) 2006 Kuwashima * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * $Id: jniwrap.h 181 2012-01-28 05:28:41Z arton $ */ #ifndef _Included_jniwrap #define _Included_jniwrap #ifdef __cplusplus extern "C" { #endif #if defined(__GNUC__) && (defined(__CYGWIN32__) || defined(__MINGW32__)) #if !defined(__int64) typedef long long __int64; #endif #endif #include #ifdef __cplusplus } #endif #endif rjb-1.4.8/ext/riconv.c0000644000175000017500000001372512161443611013600 0ustar lunarlunar/* * Rjb - Ruby <-> Java Bridge * Copyright(c) 2004 Kuwashima * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * $Id: riconv.c 117 2010-06-04 12:16:25Z arton $ */ #include "ruby.h" #include "extconf.h" #if defined _WIN32 || defined __CYGWIN__ #include #endif #if defined HAVE_NL_LANGINFO #include static const char* const NL_EUC_TABLE[] = { "EUC-JISX0213", "EUC-JP", "EUC-JP-MS" }; static const char* const NL_SJIS_TABLE[] = { "SHIFT_JIS", "SHIFT_JISX0213", "WINDOWS-31J" }; #endif #if defined HAVE_SETLOCALE #include #endif static const char* const LOCALE_EUC_TABLE[] = { "japanese", "ja_JP.eucJP", "japanese.euc", "ja_JP", "ja_JP.ujis" }; static const char* const LOCALE_SJIS_TABLE[] = { "japanese.sjis", "ja_JP.SJIS" }; static const char* const LOCALE_UTF8_TABLE[] = { "ja_JP.UTF-8", "ja_JP.utf8" }; #include "riconv.h" static const char* const CS_EUCJP = "EUC-JP"; static const char* const CS_CP932 = "CP932"; static const char* const CS_SJIS = "SHIFT_JIS"; static const char* const CS_UTF8 = "UTF-8"; #if RJB_RUBY_VERSION_CODE < 190 static VALUE objIconvJ2R; static VALUE objIconvR2J; static const char* charcode; //is this necessary? static char Kcode = '\0'; static int find_table(const char* const str, const char* const table[]) { int i; int size = sizeof(table) / sizeof(table[0]); for (i = 0; i < size; ++i) { if (strstr(str, table[i])) return 1; } return 0; } #endif #if RJB_RUBY_VERSION_CODE < 190 static const char* get_charcode_name_by_locale(const char* const name) { if (find_table(name, LOCALE_UTF8_TABLE)) return NULL; else if (find_table(name, LOCALE_EUC_TABLE)) return CS_EUCJP; else if (find_table(name, LOCALE_SJIS_TABLE)) return CS_SJIS; else return NULL; } /* * Get better charcode name. */ static const char* get_charcode_name() { const char* result = NULL; const char* lang = NULL; switch(Kcode) { case 'E': result = CS_EUCJP; break; case 'S': #if defined _WIN32 || defined __CYGWIN__ result = CS_CP932; #else result = CS_SJIS; #endif break; case 'U': //as is. break; case 'N': default: #if defined _WIN32 || defined __CYGWIN__ if (932 == GetACP()) result = CS_CP932; #elif defined HAVE_NL_LANGINFO setlocale(LC_ALL, "C"); //initialize lang = nl_langinfo(CODESET); if (find_table(lang, NL_EUC_TABLE)) result = CS_EUCJP; else if (find_table(lang, NL_SJIS_TABLE)) result = CS_SJIS; #elif defined HAVE_SETLOCALE setlocale(LC_ALL, "C"); //initialize result = get_charcode_name_by_locale(setlocale(LC_ALL, NULL)); #elif defined HAVE_GETENV if (result = get_charcode_name_by_locale(getenv("LC_ALL"))) ; else if (result = get_charcode_name_by_locale(getenv("LC_CTYPE"))) ; else if (result = get_charcode_name_by_locale(getenv("LANG"))) ; #endif break; } return result; } #endif #if RJB_RUBY_VERSION_CODE < 190 static void reinit() { charcode = get_charcode_name(); if (charcode) { VALUE rb_iconv_klass = rb_const_get(rb_cObject, rb_intern("Iconv")); if (RTEST(rb_iconv_klass)) { ID sym_new = rb_intern("new"); rb_gc_unregister_address(&objIconvR2J); objIconvR2J = rb_funcall(rb_iconv_klass, sym_new, 2, rb_str_new2(CS_UTF8), rb_str_new2(charcode)); rb_gc_register_address(&objIconvR2J); rb_gc_unregister_address(&objIconvJ2R); objIconvJ2R = rb_funcall(rb_iconv_klass, sym_new, 2, rb_str_new2(charcode), rb_str_new2(CS_UTF8)); rb_gc_register_address(&objIconvJ2R); } } else { objIconvR2J = objIconvJ2R = Qnil; } } #endif #if RJB_RUBY_VERSION_CODE < 190 static void check_kcode() { VALUE rb_iconv_klass = rb_const_get(rb_cObject, rb_intern("Iconv")); VALUE kcode = rb_gv_get("$KCODE"); if (RTEST(rb_iconv_klass) && TYPE(kcode) == T_STRING) { char* kcodep = StringValuePtr(kcode); char upper_kcode = toupper(*kcodep); if (Kcode != upper_kcode) { Kcode = upper_kcode; reinit(); } } else { objIconvR2J = objIconvJ2R = Qnil; } } #endif VALUE exticonv_local_to_utf8(VALUE local_string) { #if RJB_RUBY_VERSION_CODE < 190 check_kcode(); if(RTEST(objIconvR2J)) { return rb_funcall(objIconvR2J, rb_intern("iconv"), 1, local_string); } else { return local_string; } #else VALUE rb_cEncoding, encoding, sjis, eucjp, iso2022jp; rb_cEncoding = rb_const_get(rb_cObject, rb_intern("Encoding")); sjis = rb_const_get(rb_cEncoding, rb_intern("SHIFT_JIS")); eucjp = rb_const_get(rb_cEncoding, rb_intern("EUC_JP")); iso2022jp = rb_const_get(rb_cEncoding, rb_intern("ISO_2022_JP")); encoding = rb_funcall(local_string, rb_intern("encoding"), 0); if (encoding == sjis || encoding == eucjp || encoding == iso2022jp) { return rb_funcall(local_string, rb_intern("encode"), 1, rb_str_new2("utf-8")); } else { return local_string; } #endif } VALUE exticonv_utf8_to_local(VALUE utf8_string) { #if RJB_RUBY_VERSION_CODE < 190 check_kcode(); if(RTEST(objIconvR2J)) { return rb_funcall(objIconvJ2R, rb_intern("iconv"), 1, utf8_string); } else { return utf8_string; } #else return rb_funcall(utf8_string, rb_intern("force_encoding"), 1, rb_str_new2("utf-8")); #endif } rjb-1.4.8/ext/rjbexception.c0000644000175000017500000001047112161443611014767 0ustar lunarlunar/* * Rjb - Ruby <-> Java Bridge * Copyright(c) 2004,2005,2006,2010 arton * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * $Id: rjbexception.c 174 2011-11-09 13:47:43Z arton $ */ #include "ruby.h" #include "extconf.h" #if RJB_RUBY_VERSION_CODE < 190 #include "st.h" #else #include "ruby/st.h" #endif #include "jniwrap.h" #include "riconv.h" #include "rjb.h" static VALUE missing_delegate(int argc, VALUE* argv, VALUE self) { ID rmid = rb_to_id(argv[0]); return rb_funcall(rb_ivar_get(self, rb_intern("@cause")), rmid, argc - 1, argv + 1); } static VALUE exception_to_s(VALUE self) { return rb_funcall(rb_ivar_get(self, rb_intern("@cause")), rb_intern("toString"), 0); } /* * handle Java exception * At this time, the Java exception is defined without the package name. * This design may change in future release. */ VALUE rjb_get_exception_class(JNIEnv* jenv, jstring str) { VALUE rexp; char* pcls; VALUE cname; const char* p = (*jenv)->GetStringUTFChars(jenv, str, JNI_FALSE); char* clsname = ALLOCA_N(char, strlen(p) + 1); strcpy(clsname, p); rjb_release_string(jenv, str, p); pcls = strrchr(clsname, '.'); if (pcls) { pcls++; } else { pcls = clsname; } cname = rb_str_new2(pcls); rexp = rb_hash_aref(rjb_loaded_classes, cname); if (rexp == Qnil) { rexp = rb_define_class(pcls, rb_eStandardError); rb_define_method(rexp, "method_missing", missing_delegate, -1); rb_define_method(rexp, "to_str", exception_to_s, 0); #if defined(HAVE_RB_HASH_ASET) || defined(RUBINIUS) rb_hash_aset(rjb_loaded_classes, cname, rexp); #else #ifdef RHASH_TBL st_insert(RHASH_TBL(rjb_loaded_classes), cname, rexp); #else st_insert(RHASH(rjb_loaded_classes)->tbl, cname, rexp); #endif #endif } return rexp; } /* * throw newly created exception with supplied message. */ VALUE rjb_s_throw(int argc, VALUE* argv, VALUE self) { VALUE klass; VALUE message; JNIEnv* jenv = NULL; rjb_load_vm_default(); jenv = rjb_attach_current_thread(); (*jenv)->ExceptionClear(jenv); if (rb_scan_args(argc, argv, "11", &klass, &message) == 2) { jclass excep = rjb_find_class(jenv, klass); if (excep == NULL) { rb_raise(rb_eRuntimeError, "`%s' not found", StringValueCStr(klass)); } (*jenv)->ThrowNew(jenv, excep, StringValueCStr(message)); } else { struct jvi_data* ptr; Data_Get_Struct(klass, struct jvi_data, ptr); if (!(*jenv)->IsInstanceOf(jenv, ptr->obj, rjb_j_throwable)) { rb_raise(rb_eRuntimeError, "arg1 must be a throwable"); } else { (*jenv)->Throw(jenv, ptr->obj); } } return Qnil; } void rjb_check_exception(JNIEnv* jenv, int t) { jthrowable exp = (*jenv)->ExceptionOccurred(jenv); if (exp) { VALUE rexp = Qnil; if (RTEST(ruby_verbose)) { (*jenv)->ExceptionDescribe(jenv); } (*jenv)->ExceptionClear(jenv); if(1) { char* msg = "unknown exception"; jclass cls = (*jenv)->GetObjectClass(jenv, exp); jstring str = (*jenv)->CallObjectMethod(jenv, exp, rjb_throwable_getMessage); if (str) { const char* p = (*jenv)->GetStringUTFChars(jenv, str, JNI_FALSE); msg = ALLOCA_N(char, strlen(p) + 1); strcpy(msg, p); rjb_release_string(jenv, str, p); } str = (*jenv)->CallObjectMethod(jenv, cls, rjb_class_getName); if (str) { rexp = rjb_get_exception_class(jenv, str); } if (rexp == Qnil) { (*jenv)->DeleteLocalRef(jenv, exp); rb_raise(rb_eRuntimeError, "%s", msg); } else { VALUE rexpi = rb_funcall(rexp, rb_intern("new"), 1, rb_str_new2(msg)); jvalue val; val.l = exp; rb_ivar_set(rexpi, rb_intern("@cause"), jv2rv(jenv, val)); rb_exc_raise(rexpi); } } } } rjb-1.4.8/ext/RBridge.java0000644000175000017500000000251612161443611014311 0ustar lunarlunar/* * Rjb - Ruby <-> Java Bridge * Copyright(c) 2004 arton * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * $Id: RBridge.java 2 2006-04-11 19:04:40Z arton $ * $Log: RBridge.java,v $ * Revision 1.2 2004/06/19 09:05:00 arton * delete debug lines * * Revision 1.1 2004/06/19 09:00:19 arton * Initial revision * */ package jp.co.infoseek.hp.arton.rjb; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class RBridge implements InvocationHandler { public Object register(Class itf) { return Proxy.newProxyInstance(itf.getClassLoader(), new Class[] { itf }, this); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return call(method.getName(), proxy, args); } private native Object call(String methodName, Object target, Object[] args); } rjb-1.4.8/ext/rjb.c0000755000175000017500000025412612161443611013062 0ustar lunarlunar/* * Rjb - Ruby <-> Java Bridge * Copyright(c) 2004,2005,2006,2007,2008,2009,2010,2011,2012 arton * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * $Id: rjb.c 199 2012-12-17 13:31:18Z arton $ */ #define RJB_VERSION "1.4.8" #include "ruby.h" #include "extconf.h" #if RJB_RUBY_VERSION_CODE < 190 #include "st.h" #else #include "ruby/st.h" #endif #include "jniwrap.h" #include "jp_co_infoseek_hp_arton_rjb_RBridge.h" #include "riconv.h" #include "rjb.h" #include "ctype.h" /* * Method Modifier Flag defined in * http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#88358 */ #define ACC_PUBLIC 0x0001 #define ACC_PRIVATE 0x0002 #define ACC_PROTECTED 0x0004 #define ACC_STATIC 0x0008 #define ACC_FINAL 0x0010 #define ACC_VOLATILE 0x0040 #define ACC_TRANSIENT 0x0080 #define RJB_FIND_CLASS(var, name) \ var = rjb_find_class_by_name(jenv, name); \ rjb_check_exception(jenv, 1) #define RJB_HOLD_CLASS(var, name) \ var = rjb_find_class_by_name(jenv, name); \ rjb_check_exception(jenv, 1); \ var = (*jenv)->NewGlobalRef(jenv, var) #define RJB_LOAD_METHOD(var, obj, name, sig) \ var = (*jenv)->GetMethodID(jenv, obj, name, sig); \ rjb_check_exception(jenv, 1) #define RJB_LOAD_STATIC_METHOD(var, obj, name, sig) \ var = (*jenv)->GetStaticMethodID(jenv, obj, name, sig); \ rjb_check_exception(jenv, 1) #if defined(RUBINIUS) #define CLASS_NEW(obj, name) rb_define_class_under(rjb, name, obj) #define CLASS_INHERITED(spr, kls) RTEST(rb_funcall(spr, rb_intern(">="), 1, kls)) #else #define CLASS_NEW(obj, name) rb_define_class_under(rjb, name, obj) #define CLASS_INHERITED(spr, kls) RTEST(rb_funcall(spr, rb_intern(">="), 1, kls)) #endif #define IS_RJB_OBJECT(v) (CLASS_INHERITED(rjbi, rb_obj_class(v)) || rb_obj_class(v) == rjb || CLASS_INHERITED(rjbb, rb_obj_class(v))) #define USER_INITIALIZE "@user_initialize" static void register_class(VALUE, VALUE); static VALUE import_class(JNIEnv* jenv, jclass, VALUE); static VALUE register_instance(JNIEnv* jenv, VALUE klass, struct jv_data*, jobject); static VALUE rjb_s_free(struct jv_data*); static VALUE rjb_class_forname(int argc, VALUE* argv, VALUE self); static void setup_metadata(JNIEnv* jenv, VALUE self, struct jv_data*, VALUE classname); static VALUE jarray2rv(JNIEnv* jenv, jvalue val); static jarray r2objarray(JNIEnv* jenv, VALUE v, const char* cls); static VALUE jv2rv_withprim(JNIEnv* jenv, jobject o); static J2R get_arrayconv(const char* cname, char* depth); static jarray r2barray(JNIEnv* jenv, VALUE v, const char* cls); static VALUE rjb_s_bind(VALUE self, VALUE rbobj, VALUE itfname); static VALUE rjb; static VALUE jklass; static VALUE rjbc; static VALUE rjbi; static VALUE rjbb; static VALUE rjba; static ID user_initialize; static ID initialize_proxy; static ID cvar_classpath; static ID anonymousblock; static ID id_call; VALUE rjb_loaded_classes; static VALUE proxies; JavaVM* rjb_jvm; jclass rjb_rbridge; jmethodID rjb_register_bridge; jmethodID rjb_load_class; static JNIEnv* main_jenv; static VALUE primitive_conversion = Qfalse; /* * Object cache, never destroyed */ /* method */ static jmethodID method_getModifiers; static jmethodID method_getName; static jmethodID getParameterTypes; static jmethodID getReturnType; /* field */ static jmethodID field_getModifiers; static jmethodID field_getName; static jmethodID field_getType; /* constructor */ static jmethodID ctrGetParameterTypes; /* class */ static jclass j_class; jmethodID rjb_class_getName; /* throwable */ jclass rjb_j_throwable; jmethodID rjb_throwable_getMessage; /* String global reference */ static jclass j_string; static jmethodID str_tostring; /* Object global reference */ static jclass j_object; /* ClassLoader */ static jclass j_classloader; static jmethodID get_system_classloader; /* URLClassLoader */ static jclass j_url_loader; static jobject url_loader; static jmethodID url_loader_new; static jmethodID url_geturls; static jmethodID url_add_url; /* URL global reference */ static jclass j_url; static jmethodID url_new; enum PrimitiveType { PRM_INT = 0, PRM_LONG, PRM_DOUBLE, PRM_BOOLEAN, PRM_CHARACTER, PRM_SHORT, PRM_BYTE, PRM_FLOAT, /* */ PRM_LAST }; /* * Native type conversion table */ typedef struct jobject_ruby_table { const char* classname; const char* to_prim_method; const char* prmsig; const char* ctrsig; jclass klass; /* primitive class */ jmethodID to_prim_id; jmethodID ctr_id; J2R func; } jprimitive_table; JNIEnv* rjb_attach_current_thread(void) { JNIEnv* env; if (!rjb_jvm) return NULL; (*rjb_jvm)->AttachCurrentThread(rjb_jvm, (void**)&env, '\0'); return env; } void rjb_release_string(JNIEnv *jenv, jstring str, const char* chrs) { (*jenv)->ReleaseStringUTFChars(jenv, str, chrs); (*jenv)->DeleteLocalRef(jenv, str); } static char* java2jniname(char* jnicls) { char* p; for (p = jnicls; *p; p++) { if (*p == '.') { *p = '/'; } } return jnicls; } static char* jniname2java(char* jniname) { char* p; for (p = jniname; *p; p++) { if (*p == '/') { *p = '.'; } } return jniname; } static char* next_sig(char* p) { if (!*p) { return p; } if (*p == '[') { p++; } if (*p == 'L') { while (*p && *p != ';') { p++; } } return (*p) ? ++p : p; } static VALUE jstring2val(JNIEnv* jenv, jstring s) { const char* p; VALUE v; if (s == NULL) { return Qnil; } p = (*jenv)->GetStringUTFChars(jenv, s, NULL); v = rb_str_new2(p); v = exticonv_utf8_to_local(v); rjb_release_string(jenv, s, p); return v; } /* * Type conversion tables */ typedef struct type_conversion_table { const char* jtype; const char* jntype; R2J r2j; J2R j2r; J2R ja2r; R2JARRAY r2ja; off_t jcall; /* for instance method */ off_t jscall; /* for static method */ } jconv_table; /* * conversion methods * val will be released in this function. */ static VALUE jv2rclass(JNIEnv* jenv, jclass jc) { const char* cname; VALUE clsname; VALUE v; jstring nm = (*jenv)->CallObjectMethod(jenv, jc, rjb_class_getName); rjb_check_exception(jenv, 0); cname = (*jenv)->GetStringUTFChars(jenv, nm, NULL); clsname = rb_str_new2(cname); rjb_release_string(jenv, nm, cname); v = rb_hash_aref(rjb_loaded_classes, clsname); if (v == Qnil) { v = import_class(jenv, jc, clsname); } (*jenv)->DeleteLocalRef(jenv, jc); return v; } static VALUE jv2rv_r(JNIEnv* jenv, jvalue val) { const char* cname; jstring nm; jclass klass; VALUE clsname; VALUE v; struct jv_data* ptr; /* object to ruby */ if (!val.l) return Qnil; klass = (*jenv)->GetObjectClass(jenv, val.l); if ((*jenv)->IsSameObject(jenv, klass, j_class)) { (*jenv)->DeleteLocalRef(jenv, klass); return jv2rclass(jenv, val.l); } nm = (*jenv)->CallObjectMethod(jenv, klass, rjb_class_getName); rjb_check_exception(jenv, 0); cname = (*jenv)->GetStringUTFChars(jenv, nm, NULL); if (*cname == '[') { char depth = 0; J2R j2r = get_arrayconv(cname, &depth); rjb_release_string(jenv, nm, cname); v = j2r(jenv, val); (*jenv)->DeleteLocalRef(jenv, klass); (*jenv)->DeleteLocalRef(jenv, val.l); return v; } clsname = rb_str_new2(cname); rjb_release_string(jenv, nm, cname); v = rb_hash_aref(rjb_loaded_classes, clsname); if (v == Qnil) { v = import_class(jenv, klass, clsname); } Data_Get_Struct(v, struct jv_data, ptr); v = register_instance(jenv, v, (struct jv_data*)ptr, val.l); (*jenv)->DeleteLocalRef(jenv, klass); (*jenv)->DeleteLocalRef(jenv, val.l); return v; } VALUE jv2rv(JNIEnv* jenv, jvalue val) { if (RTEST(primitive_conversion)) { return jv2rv_withprim(jenv, val.l); } return jv2rv_r(jenv, val); } static VALUE jvoid2rv(JNIEnv* jenv, jvalue val) { return Qnil; } static VALUE jbyte2rv(JNIEnv* jenv, jvalue val) { return INT2NUM(val.b); } static VALUE jchar2rv(JNIEnv* jenv, jvalue val) { return INT2NUM(val.c); } static VALUE jdouble2rv(JNIEnv* jenv, jvalue val) { return rb_float_new(val.d); } static VALUE jfloat2rv(JNIEnv* jenv, jvalue val) { return rb_float_new((double)val.f); } static VALUE jint2rv(JNIEnv* jenv, jvalue val) { return INT2NUM(val.i); } static VALUE jlong2rv(JNIEnv* jenv, jvalue val) { #if HAVE_LONG_LONG return LL2NUM(val.j); #else char bignum[64]; sprintf(bignum, "%ld * 0x100000000 + 0x%lx", (long)(val.j >> 32), (unsigned long)val.j); return rb_eval_string(bignum); #endif } static VALUE jshort2rv(JNIEnv* jenv, jvalue val) { return INT2NUM(val.s); } static VALUE jboolean2rv(JNIEnv* jenv, jvalue val) { return (val.z) ? Qtrue : Qfalse; } static VALUE jstring2rv(JNIEnv* jenv, jvalue val) { return jstring2val(jenv, (jstring)val.l); } static VALUE ja2r(J2R conv, JNIEnv* jenv, jvalue val, int depth) { jsize len; VALUE v; int i; if (!val.l) return Qnil; if (depth == 1) { return conv(jenv, val); } len = (*jenv)->GetArrayLength(jenv, val.l); v = rb_ary_new2(len); for (i = 0; i < len; i++) { jvalue wrap; wrap.l = (*jenv)->GetObjectArrayElement(jenv, val.l, i); rb_ary_push(v, ja2r(conv, jenv, wrap, depth - 1)); } (*jenv)->DeleteLocalRef(jenv, val.l); return v; } static VALUE jarray2rv(JNIEnv* jenv, jvalue val) { jsize len; VALUE v; int i; if (!val.l) return Qnil; len = (*jenv)->GetArrayLength(jenv, val.l); v = rb_ary_new2(len); for (i = 0; i < len; i++) { jvalue wrap; wrap.l = (*jenv)->GetObjectArrayElement(jenv, val.l, i); /* wrap.l will be release in jv2rv */ rb_ary_push(v, jv2rv(jenv, wrap)); } (*jenv)->DeleteLocalRef(jenv, val.l); return v; } static VALUE ca2rv(JNIEnv* jenv, void* p) { return INT2FIX(*(jchar*)p); } static VALUE da2rv(JNIEnv* jenv, void* p) { return rb_float_new(*(jdouble*)p); } static VALUE fa2rv(JNIEnv* jenv, void* p) { return rb_float_new(*(jfloat*)p); } static VALUE ia2rv(JNIEnv* jenv, void* p) { return INT2NUM(*(jint*)p); } static VALUE la2rv(JNIEnv* jenv, void* p) { #if HAVE_LONG_LONG return LL2NUM(*(jlong*)p); #else return LONG2NUM(*(jlong*)p); #endif } static VALUE sa2rv(JNIEnv* jenv, void* p) { return INT2FIX(*(jshort*)p); } static VALUE ba2rv(JNIEnv* jenv, void* p) { return (*(jboolean*)p) ? Qtrue : Qfalse; } /* * val : released in this function. */ static VALUE call_conv(JNIEnv* jenv, jvalue val, size_t sz, void* p, CONV conv, size_t fnc) { int i; char* cp = (char*)p; jsize len = (*jenv)->GetArrayLength(jenv, val.l); VALUE v = rb_ary_new2(len); for (i = 0; i < len; i++) { rb_ary_push(v, conv(jenv, cp)); cp += sz; } (*(RELEASEARRAY*)(((char*)*jenv) + fnc))(jenv, val.l, p, JNI_ABORT); (*jenv)->DeleteLocalRef(jenv, val.l); return v; } static VALUE jbytearray2rv(JNIEnv* jenv, jvalue val) { jsize len = (*jenv)->GetArrayLength(jenv, val.l); jbyte* p = (*jenv)->GetByteArrayElements(jenv, val.l, NULL); VALUE v = rb_str_new((char*)p, len); (*jenv)->ReleaseByteArrayElements(jenv, val.l, p, JNI_ABORT); (*jenv)->DeleteLocalRef(jenv, val.l); return v; } static VALUE jchararray2rv(JNIEnv* jenv, jvalue val) { jchar* p = (*jenv)->GetCharArrayElements(jenv, val.l, NULL); return call_conv(jenv, val, sizeof(jchar), p, ca2rv, offsetof(struct JNINativeInterface_, ReleaseCharArrayElements)); } static VALUE jdoublearray2rv(JNIEnv* jenv, jvalue val) { jdouble* p = (*jenv)->GetDoubleArrayElements(jenv, val.l, NULL); return call_conv(jenv, val, sizeof(jdouble), p, da2rv, offsetof(struct JNINativeInterface_, ReleaseDoubleArrayElements)); } static VALUE jfloatarray2rv(JNIEnv* jenv, jvalue val) { jfloat* p = (*jenv)->GetFloatArrayElements(jenv, val.l, NULL); return call_conv(jenv, val, sizeof(jfloat), p, fa2rv, offsetof(struct JNINativeInterface_, ReleaseFloatArrayElements)); } static VALUE jintarray2rv(JNIEnv* jenv, jvalue val) { jint* p = (*jenv)->GetIntArrayElements(jenv, val.l, NULL); return call_conv(jenv, val, sizeof(jint), p, ia2rv, offsetof(struct JNINativeInterface_, ReleaseIntArrayElements)); } static VALUE jlongarray2rv(JNIEnv* jenv, jvalue val) { jlong* p = (*jenv)->GetLongArrayElements(jenv, val.l, NULL); return call_conv(jenv, val, sizeof(jlong), p, la2rv, offsetof(struct JNINativeInterface_, ReleaseLongArrayElements)); } static VALUE jshortarray2rv(JNIEnv* jenv, jvalue val) { jshort* p = (*jenv)->GetShortArrayElements(jenv, val.l, NULL); return call_conv(jenv, val, sizeof(jshort), p, sa2rv, offsetof(struct JNINativeInterface_, ReleaseShortArrayElements)); } static VALUE jstringarray2rv(JNIEnv* jenv, jvalue val) { int i; jsize len = (*jenv)->GetArrayLength(jenv, val.l); VALUE v = rb_ary_new2(len); for (i = 0; i < len; i++) { jobject p = (*jenv)->GetObjectArrayElement(jenv, val.l, i); rb_ary_push(v, jstring2val(jenv, (jstring)p)); } (*jenv)->DeleteLocalRef(jenv, val.l); return v; } static VALUE jbooleanarray2rv(JNIEnv* jenv, jvalue val) { jboolean* p = (*jenv)->GetBooleanArrayElements(jenv, val.l, NULL); return call_conv(jenv, val, sizeof(jboolean), p, ba2rv, offsetof(struct JNINativeInterface_, ReleaseBooleanArrayElements)); } /* * table that handles java primitive type. * index: according to enum PrimitiveType. */ static jprimitive_table jpcvt[] = { { "java/lang/Integer", "intValue", "()I", "(I)V", NULL, 0, 0, jint2rv, }, { "java/lang/Long", "longValue", "()J", "(J)V", NULL, 0, 0, jlong2rv, }, { "java/lang/Double", "doubleValue", "()D", "(D)V", NULL, 0, 0, jdouble2rv, }, { "java/lang/Boolean", "booleanValue", "()Z", "(Z)Ljava/lang/Boolean;", NULL, 0, 0, jboolean2rv, }, { "java/lang/Character", "charValue", "()C", NULL, NULL, 0, 0, jchar2rv, }, { "java/lang/Short", "intValue", "()I", NULL, NULL, 0, 0, jint2rv, }, { "java/lang/Byte", "intValue", "()I", NULL, NULL, 0, 0, jint2rv, }, { "java/lang/Float", "doubleValue", "()D", NULL, NULL, 0, 0, jdouble2rv, }, }; /* * o will be released in this function. */ static VALUE jv2rv_withprim(JNIEnv* jenv, jobject o) { jvalue jv; int i; jclass klass; jv.j = 0; if (!o) rb_raise(rb_eRuntimeError, "Object is NULL"); klass = (*jenv)->GetObjectClass(jenv, o); for (i = PRM_INT; i < PRM_LAST; i++) { if ((*jenv)->IsSameObject(jenv, jpcvt[i].klass, klass)) { switch (*(jpcvt[i].to_prim_method)) { case 'i': jv.i = (*jenv)->CallIntMethod(jenv, o, jpcvt[i].to_prim_id); break; case 'b': jv.z = (*jenv)->CallBooleanMethod(jenv, o, jpcvt[i].to_prim_id); break; case 'd': jv.d = (*jenv)->CallDoubleMethod(jenv, o, jpcvt[i].to_prim_id); break; case 'c': jv.c = (*jenv)->CallCharMethod(jenv, o, jpcvt[i].to_prim_id); break; case 'l': jv.j = (*jenv)->CallLongMethod(jenv, o, jpcvt[i].to_prim_id); break; default: rb_raise(rb_eRuntimeError, "no convertor defined(%d)", i); break; } (*jenv)->DeleteLocalRef(jenv, o); return jpcvt[i].func(jenv, jv); } } if ((*jenv)->IsSameObject(jenv, j_string, klass)) { return jstring2val(jenv, o); } jv.l = o; return jv2rv_r(jenv, jv); } /* * functions convert VALUE to jvalue */ static void rv2jv(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release) { jv->l = NULL; } static void rv2jbyte(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release) { if (!release) jv->b = (jbyte)NUM2INT(val); } static void rv2jchar(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release) { if (!release) jv->c = (jchar)NUM2INT(val); } static void rv2jdouble(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release) { if (release) return; switch (TYPE(val)) { case T_FIXNUM: jv->d = NUM2INT(val); break; case T_FLOAT: jv->d = NUM2DBL(val); break; default: rb_raise(rb_eRuntimeError, "can't change to double"); break; } } static void rv2jfloat(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release) { if (release) return; switch (TYPE(val)) { case T_FIXNUM: jv->f = (float)NUM2INT(val); break; case T_FLOAT: jv->f = (float)NUM2DBL(val); break; default: rb_raise(rb_eRuntimeError, "can't change to float"); break; } } static void rv2jint(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release) { if (!release) jv->i = NUM2INT(val); } static void rv2jlong(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release) { if (release) return; switch (TYPE(val)) { case T_FIXNUM: jv->j = FIX2LONG(val); break; default: #if HAVE_LONG_LONG jv->j = NUM2LL(val); #else rb_raise(rb_eRuntimeError, "can't change to long"); #endif break; } } static void rv2jshort(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release) { if (release) return; if (TYPE(val) == T_FIXNUM) { int n = FIX2INT(val); if (abs(n) < 0x7fff) { jv->s = (short)n; return; } } rb_raise(rb_eRuntimeError, "can't change to short"); } static void rv2jboolean(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release) { if (!release) jv->z = (RTEST(val)) ? JNI_TRUE : JNI_FALSE; } static void rv2jstring(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release) { if (!release) { if (TYPE(val) == T_DATA && IS_RJB_OBJECT(val)) { struct jvi_data* ptr; Data_Get_Struct(val, struct jvi_data, ptr); if ((*jenv)->IsInstanceOf(jenv, ptr->obj, j_string)) { jv->l = ptr->obj; } else { jmethodID tostr; jstring js; tostr = (*jenv)->GetMethodID(jenv, ptr->klass, "toString", "()Ljava/lang/String;"); rjb_check_exception(jenv, 0); js = (*jenv)->CallObjectMethod(jenv, ptr->obj, tostr); rjb_check_exception(jenv, 0); jv->l = js; } } else { if (NIL_P(val)) { jv->l = NULL; } else { val = exticonv_local_to_utf8(val); jv->l = (*jenv)->NewStringUTF(jenv, StringValuePtr(val)); } } } else { if (TYPE(val) == T_DATA) { if (IS_RJB_OBJECT(val)) { struct jvi_data* ptr; Data_Get_Struct(val, struct jvi_data, ptr); if ((*jenv)->IsInstanceOf(jenv, ptr->obj, j_string)) { return; /* never delete at this time */ } } } (*jenv)->DeleteLocalRef(jenv, jv->l); } } /* * psig may be NULL (from proxy/array call) */ static void rv2jobject(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release) { if (!release) { jv->l = NULL; if (val == Qtrue || val == Qfalse) { jv->l = (*jenv)->CallStaticObjectMethod(jenv, jpcvt[PRM_BOOLEAN].klass, jpcvt[PRM_BOOLEAN].ctr_id, (val == Qtrue) ? JNI_TRUE : JNI_FALSE); } else if (NIL_P(val)) { /* no-op */ } else if (FIXNUM_P(val)) { jvalue arg; int idx = PRM_INT; #if HAVE_LONG_LONG arg.j = FIX2LONG(val); if (arg.j < INT_MIN || arg.j > INT_MAX) { idx = PRM_LONG; } #else arg.i = FIX2LONG(val); #endif jv->l = (*jenv)->NewObject(jenv, jpcvt[idx].klass, jpcvt[idx].ctr_id, arg); } else { jvalue arg; switch (TYPE(val)) { case T_DATA: if (IS_RJB_OBJECT(val)) { /* TODO: check instanceof (class (in psig) ) */ struct jvi_data* ptr; Data_Get_Struct(val, struct jvi_data, ptr); jv->l = ptr->obj; } else if (rb_obj_class(val) == rjbb) { struct rj_bridge* ptr; Data_Get_Struct(val, struct rj_bridge, ptr); jv->l = ptr->proxy; } else if (CLASS_INHERITED(rjbc, rb_obj_class(val))) { struct jv_data* ptr; Data_Get_Struct(val, struct jv_data, ptr); jv->l = ptr->idata.obj; } break; case T_STRING: if (psig && *psig == '[' && *(psig + 1) == 'B') { jv->l = r2barray(jenv, val, NULL); } else { rv2jstring(jenv, val, jv, NULL, 0); } break; case T_FLOAT: arg.d = NUM2DBL(val); jv->l = (*jenv)->NewObject(jenv, jpcvt[PRM_DOUBLE].klass, jpcvt[PRM_DOUBLE].ctr_id, arg.d); break; case T_ARRAY: jv->l = r2objarray(jenv, val, "Ljava/lang/Object;"); break; #if HAVE_LONG_LONG case T_BIGNUM: arg.j = rb_big2ll(val); jv->l = (*jenv)->NewObject(jenv, jpcvt[PRM_LONG].klass, jpcvt[PRM_LONG].ctr_id, arg); break; #endif case T_OBJECT: default: #if DEBUG fprintf(stderr, "rtype:%d, sig=%s\n", TYPE(val), psig); fflush(stderr); #endif rb_raise(rb_eRuntimeError, "can't convert to java type"); break; } } } else { switch (TYPE(val)) { case T_STRING: case T_FLOAT: case T_ARRAY: case T_BIGNUM: if (jv->l) (*jenv)->DeleteLocalRef(jenv, jv->l); break; } } } static void check_fixnumarray(VALUE v) { size_t i; size_t len = RARRAY_LEN(v); VALUE* p = RARRAY_PTR(v); /* check all fixnum (overflow is permit) */ for (i = 0; i < len; i++) { if (!FIXNUM_P(*p++)) { rb_raise(rb_eRuntimeError, "array element must be a fixnum"); } } } static jarray r2barray(JNIEnv* jenv, VALUE v, const char* cls) { jarray ary = NULL; if (TYPE(v) == T_STRING) { ary = (*jenv)->NewByteArray(jenv, (jint)RSTRING_LEN(v)); (*jenv)->SetByteArrayRegion(jenv, ary, 0, (jint)RSTRING_LEN(v), (const jbyte*)RSTRING_PTR(v)); } else if (TYPE(v) == T_ARRAY) { int i; jbyte* pb; check_fixnumarray(v); ary = (*jenv)->NewByteArray(jenv, (jint)RARRAY_LEN(v)); pb = (*jenv)->GetByteArrayElements(jenv, ary, NULL); for (i = 0; i < RARRAY_LEN(v); i++) { *(pb + i) = (jbyte)FIX2ULONG(RARRAY_PTR(v)[i]); } (*jenv)->ReleaseByteArrayElements(jenv, ary, pb, 0); } if (!ary) { rb_raise(rb_eRuntimeError, "can't coerce to byte array"); } return ary; } static jarray r2carray(JNIEnv* jenv, VALUE v, const char* cls) { jarray ary = NULL; if (TYPE(v) == T_ARRAY) { int i; jchar* pb; check_fixnumarray(v); ary = (*jenv)->NewCharArray(jenv, (jint)RARRAY_LEN(v)); pb = (*jenv)->GetCharArrayElements(jenv, ary, NULL); for (i = 0; i < RARRAY_LEN(v); i++) { *(pb + i) = (jchar)FIX2ULONG(RARRAY_PTR(v)[i]); } (*jenv)->ReleaseCharArrayElements(jenv, ary, pb, 0); return ary; } rb_raise(rb_eRuntimeError, "can't coerce to char array"); } static jarray r2darray(JNIEnv* jenv, VALUE v, const char* cls) { jarray ary = NULL; if (TYPE(v) == T_ARRAY) { int i; jdouble* pb; ary = (*jenv)->NewDoubleArray(jenv, (jint)RARRAY_LEN(v)); pb = (*jenv)->GetDoubleArrayElements(jenv, ary, NULL); for (i = 0; i < RARRAY_LEN(v); i++) { *(pb + i) = (jdouble)rb_num2dbl(RARRAY_PTR(v)[i]); } (*jenv)->ReleaseDoubleArrayElements(jenv, ary, pb, 0); return ary; } rb_raise(rb_eRuntimeError, "can't coerce to double array"); } static jarray r2farray(JNIEnv* jenv, VALUE v, const char* cls) { jarray ary = NULL; if (TYPE(v) == T_ARRAY) { int i; jfloat* pb; ary = (*jenv)->NewFloatArray(jenv, (jint)RARRAY_LEN(v)); pb = (*jenv)->GetFloatArrayElements(jenv, ary, NULL); for (i = 0; i < RARRAY_LEN(v); i++) { *(pb + i) = (jfloat)rb_num2dbl(RARRAY_PTR(v)[i]); } (*jenv)->ReleaseFloatArrayElements(jenv, ary, pb, 0); return ary; } rb_raise(rb_eRuntimeError, "can't coerce to float array"); } static jarray r2iarray(JNIEnv* jenv, VALUE v, const char* cls) { jarray ary = NULL; if (TYPE(v) == T_ARRAY) { int i; jint* pb; check_fixnumarray(v); ary = (*jenv)->NewIntArray(jenv, (jint)RARRAY_LEN(v)); pb = (*jenv)->GetIntArrayElements(jenv, ary, NULL); for (i = 0; i < RARRAY_LEN(v); i++) { *(pb + i) = (jint)FIX2LONG(RARRAY_PTR(v)[i]); } (*jenv)->ReleaseIntArrayElements(jenv, ary, pb, 0); return ary; } rb_raise(rb_eRuntimeError, "can't coerce to int array"); } static jarray r2larray(JNIEnv* jenv, VALUE v, const char* cls) { jarray ary = NULL; if (TYPE(v) == T_ARRAY) { int i; jlong* pb; ary = (*jenv)->NewLongArray(jenv, (jint)RARRAY_LEN(v)); pb = (*jenv)->GetLongArrayElements(jenv, ary, NULL); for (i = 0; i < RARRAY_LEN(v); i++) { #if HAVE_LONG_LONG *(pb + i) = (jlong)rb_num2ll(RARRAY_PTR(v)[i]); #else *(pb + i) = (jlong)FIX2LONG(RARRAY_PTR(v)[i]); #endif } (*jenv)->ReleaseLongArrayElements(jenv, ary, pb, 0); return ary; } rb_raise(rb_eRuntimeError, "can't coerce to long array"); } static jarray r2sarray(JNIEnv* jenv, VALUE v, const char* cls) { jarray ary = NULL; if (TYPE(v) == T_ARRAY) { int i; jshort* pb; check_fixnumarray(v); ary = (*jenv)->NewShortArray(jenv, (jint)RARRAY_LEN(v)); pb = (*jenv)->GetShortArrayElements(jenv, ary, NULL); for (i = 0; i < RARRAY_LEN(v); i++) { *(pb + i) = (jshort)FIX2LONG(RARRAY_PTR(v)[i]); } (*jenv)->ReleaseShortArrayElements(jenv, ary, pb, 0); return ary; } rb_raise(rb_eRuntimeError, "can't coerce to short array"); } static jarray r2boolarray(JNIEnv* jenv, VALUE v, const char* cls) { jarray ary = NULL; if (TYPE(v) == T_ARRAY) { int i; jboolean* pb; ary = (*jenv)->NewBooleanArray(jenv, (jint)RARRAY_LEN(v)); pb = (*jenv)->GetBooleanArrayElements(jenv, ary, NULL); for (i = 0; i < RARRAY_LEN(v); i++) { *(pb + i) = (!RTEST(RARRAY_PTR(v)[i])) ? JNI_FALSE : JNI_TRUE; } (*jenv)->ReleaseBooleanArrayElements(jenv, ary, pb, 0); return ary; } rb_raise(rb_eRuntimeError, "can't coerce to boolean array"); } static jarray r2voidarray(JNIEnv* jenv, VALUE v, const char* cls) { rb_raise(rb_eRuntimeError, "void never arrayed"); } static jarray r2objarray(JNIEnv* jenv, VALUE v, const char* cls) { jarray ary = NULL; if (TYPE(v) == T_ARRAY) { int i; jclass jcls = NULL; char* p = strchr(cls, ';'); if (p) { volatile VALUE clsname = rb_str_new(cls + 1, p - cls - 1); // skip first 'L' jcls = rjb_find_class(jenv, clsname); } ary = (*jenv)->NewObjectArray(jenv, (jint)RARRAY_LEN(v), (jcls) ? jcls : j_object, NULL); rjb_check_exception(jenv, 0); for (i = 0; i < RARRAY_LEN(v); i++) { jvalue jv; rv2jobject(jenv, RARRAY_PTR(v)[i], &jv, NULL, 0); (*jenv)->SetObjectArrayElement(jenv, ary, i, jv.l); } return ary; } rb_raise(rb_eRuntimeError, "can't coerce to object array"); } /* * Type convertion tables */ static const jconv_table jcvt[] = { { "byte", "B", rv2jbyte, jbyte2rv, jbytearray2rv, r2barray, offsetof(struct JNINativeInterface_, CallByteMethodA), offsetof(struct JNINativeInterface_, CallStaticByteMethodA), }, { "char", "C", rv2jchar, jchar2rv, jchararray2rv, r2carray, offsetof(struct JNINativeInterface_, CallCharMethodA), offsetof(struct JNINativeInterface_, CallStaticCharMethodA), }, { "double", "D", rv2jdouble, jdouble2rv, jdoublearray2rv, r2darray, offsetof(struct JNINativeInterface_, CallDoubleMethodA), offsetof(struct JNINativeInterface_, CallStaticDoubleMethodA), }, { "float", "F", rv2jfloat, jfloat2rv, jfloatarray2rv, r2farray, offsetof(struct JNINativeInterface_, CallFloatMethodA), offsetof(struct JNINativeInterface_, CallStaticFloatMethodA), }, { "int", "I", rv2jint, jint2rv, jintarray2rv, r2iarray, offsetof(struct JNINativeInterface_, CallIntMethodA), offsetof(struct JNINativeInterface_, CallStaticIntMethodA), }, { "long", "J", rv2jlong, jlong2rv, jlongarray2rv, r2larray, offsetof(struct JNINativeInterface_, CallLongMethodA), offsetof(struct JNINativeInterface_, CallStaticLongMethodA), }, { "short", "S", rv2jshort, jshort2rv, jshortarray2rv, r2sarray, offsetof(struct JNINativeInterface_, CallShortMethodA), offsetof(struct JNINativeInterface_, CallStaticShortMethodA), }, { "boolean", "Z", rv2jboolean, jboolean2rv, jbooleanarray2rv, r2boolarray, offsetof(struct JNINativeInterface_, CallBooleanMethodA), offsetof(struct JNINativeInterface_, CallStaticBooleanMethodA), }, { "void", "V", rv2jv, jvoid2rv, NULL, r2voidarray, offsetof(struct JNINativeInterface_, CallVoidMethodA), offsetof(struct JNINativeInterface_, CallStaticVoidMethodA), }, { "java.lang.String", "Ljava.lang.String;", rv2jstring, jstring2rv, jstringarray2rv, r2objarray, offsetof(struct JNINativeInterface_, CallObjectMethodA), offsetof(struct JNINativeInterface_, CallStaticObjectMethodA), }, }; static void rv2jarray(JNIEnv* jenv, VALUE val, jvalue* jv, const char* psig, int release) { if (*psig != '[') { rb_raise(rb_eRuntimeError, "argument signature not array"); } if (release) { if (TYPE(val) == T_STRING && *(psig + 1) == 'B') { // copy array's contents into arg string jsize len = (*jenv)->GetArrayLength(jenv, jv->l); jbyte* p = (*jenv)->GetByteArrayElements(jenv, jv->l, NULL); if (len <= RSTRING_LEN(val)) { memcpy(StringValuePtr(val), p, len); } else { VALUE src = rb_str_new((char*)p, len); rb_str_set_len(val, 0); rb_str_append(val, src); } } (*jenv)->DeleteLocalRef(jenv, jv->l); } else { jint i; jarray ja = NULL; if (NIL_P(val)) { /* no-op, null for an array */ } else if (*(psig + 1) == '[') { if (TYPE(val) != T_ARRAY) { rb_raise(rb_eRuntimeError, "array's rank unmatch"); } ja = (*jenv)->NewObjectArray(jenv, (jint)RARRAY_LEN(val), j_object, NULL); rjb_check_exception(jenv, 0); for (i = 0; i < (jint)RARRAY_LEN(val); i++) { jvalue jv; rv2jarray(jenv, RARRAY_PTR(val)[i], &jv, psig + 1, 0); (*jenv)->SetObjectArrayElement(jenv, ja, (jint)i, jv.l); } } else { R2JARRAY r2a = r2objarray; for (i = 0; i < (jint)COUNTOF(jcvt); i++) { if (*(psig + 1) == jcvt[i].jntype[0]) { r2a = jcvt[i].r2ja; break; } } ja = r2a(jenv, val, psig + 1); } jv->l = ja; } } /* */ static R2J get_r2j(JNIEnv* jenv, jobject o, int* siglen, char* sigp) { size_t len, i; const char* cname; R2J result = NULL; jstring nm = (*jenv)->CallObjectMethod(jenv, o, rjb_class_getName); rjb_check_exception(jenv, 0); cname = (*jenv)->GetStringUTFChars(jenv, nm, NULL); if (*cname == '[') { if (siglen) { len = strlen(cname); *siglen += (int)len; strcpy(sigp, cname); } result = rv2jarray; } else { for (i = 0; i < COUNTOF(jcvt); i++) { if (!strcmp(cname, jcvt[i].jtype)) { if (siglen) { *siglen += (int)strlen(jcvt[i].jntype); strcpy(sigp, jcvt[i].jntype); } result = jcvt[i].r2j; break; } } if (!result) { if (siglen) { *siglen += sprintf(sigp, "L%s;", cname); } result = rv2jobject; } } rjb_release_string(jenv, nm, cname); return result; } static J2R get_arrayconv(const char* cname, char* pdepth) { size_t i; size_t start; for (start = 1; *(cname + start) == '['; start++); *pdepth = (char)start; for (i = 0; i < COUNTOF(jcvt); i++) { if (*(cname + start) == jcvt[i].jntype[0]) { if (jcvt[i].jntype[0] == 'L' && strncmp(cname + start, jcvt[i].jntype, strlen(jcvt[i].jntype))) { break; } return jcvt[i].ja2r; } } return &jarray2rv; } static J2R get_j2r(JNIEnv* jenv, jobject cls, char* psig, char* pdepth, char* ppsig, off_t* piv, int static_method) { size_t i; J2R result = NULL; const char* cname; const char* jname = NULL; jstring nm = (*jenv)->CallObjectMethod(jenv, cls, rjb_class_getName); rjb_check_exception(jenv, 0); cname = (*jenv)->GetStringUTFChars(jenv, nm, NULL); if (*cname == '[') { result = get_arrayconv(cname, pdepth); jname = cname; } else { for (i = 0; i < COUNTOF(jcvt); i++) { if (!strcmp(cname, jcvt[i].jtype)) { result = jcvt[i].j2r; *piv = (static_method) ? jcvt[i].jscall : jcvt[i].jcall; if (jcvt[i].jntype[0] != 'L') { *psig = jcvt[i].jntype[0]; } jname = jcvt[i].jntype; break; } } } if (ppsig) { if (!jname) { sprintf(ppsig, "L%s;", cname); } else { strcpy(ppsig, jname); } java2jniname(ppsig); } rjb_release_string(jenv, nm, cname); return result; } static void setup_j2r(JNIEnv* jenv, jobject cls, struct cls_method* pm, int static_method) { off_t iv = 0; J2R result = get_j2r(jenv, cls, &pm->basic.result_signature, &pm->basic.result_arraydepth, NULL, &iv, static_method); pm->result_convert = (result) ? result : jv2rv; if (iv) { pm->method = iv; } else { pm->method = (static_method) ? offsetof(struct JNINativeInterface_, CallStaticObjectMethodA) : offsetof(struct JNINativeInterface_, CallObjectMethodA); } } static void fill_convert(JNIEnv* jenv, struct cls_constructor* cls, jobjectArray tp, int count) { int i, siglen; R2J* tbl = ALLOC_N(R2J, count); char** sig = (char**)ALLOCA_N(char*, count); char siga[256]; cls->arg_convert = tbl; memset(tbl, 0, sizeof(R2J) * count); siglen = 0; for (i = 0; i < count; i++) { jobject o = (*jenv)->GetObjectArrayElement(jenv, tp, i); *(tbl + i) = get_r2j(jenv, o, &siglen, siga); *(sig + i) = ALLOCA_N(char, strlen(siga) + 1); strcpy(*(sig + i), siga); } cls->method_signature = ALLOC_N(char, siglen + 1); *(cls->method_signature) = 0; for (i = 0; i < count; i++) { strcat(cls->method_signature, *(sig + i)); } } /* * create method info structure * m = instance of Method class * c = instance of the class */ static void setup_methodbase(JNIEnv* jenv, struct cls_constructor* pm, jobjectArray parama, jsize pcount) { pm->arg_count = pcount; pm->method_signature = NULL; pm->result_signature = 'O'; pm->result_arraydepth = 0; pm->arg_convert = NULL; if (pcount) { fill_convert(jenv, pm, parama, pcount); } } static void register_methodinfo(struct cls_method* newpm, st_table* tbl) { struct cls_method* pm; if (st_lookup(tbl, newpm->name, (st_data_t*)&pm)) { newpm->next = pm->next; pm->next = newpm; } else { newpm->next = NULL; st_insert(tbl, newpm->name, (VALUE)newpm); } } static struct cls_method* clone_methodinfo(struct cls_method* pm) { struct cls_method* result = ALLOC(struct cls_method); memcpy(result, pm, sizeof(struct cls_method)); return result; } static int make_alias(const char* jname, char* rname) { int ret = 0; while (*jname) { if (isupper(*jname)) { *rname++ = '_'; *rname++ = tolower(*jname++); ret = 1; } else { *rname++ = *jname++; } } *rname = '\0'; return ret; } static void create_methodinfo(JNIEnv* jenv, st_table* tbl, jobject m, int static_method) { struct cls_method* result; struct cls_method* pm; const char* jname; int alias; jstring nm; jobjectArray parama; jobject cls; jsize param_count; char* rname; result = ALLOC(struct cls_method); parama = (*jenv)->CallObjectMethod(jenv, m, getParameterTypes); rjb_check_exception(jenv, 0); param_count = (*jenv)->GetArrayLength(jenv, parama); rjb_check_exception(jenv, 0); setup_methodbase(jenv, &result->basic, parama, param_count); nm = (*jenv)->CallObjectMethod(jenv, m, method_getName); rjb_check_exception(jenv, 0); jname = (*jenv)->GetStringUTFChars(jenv, nm, NULL); rname = ALLOCA_N(char, strlen(jname) * 2 + 8); alias = make_alias(jname, rname); result->name = rb_intern(jname); rjb_release_string(jenv, nm, jname); result->basic.id = (*jenv)->FromReflectedMethod(jenv, m); rjb_check_exception(jenv, 0); cls = (*jenv)->CallObjectMethod(jenv, m, getReturnType); rjb_check_exception(jenv, 0); setup_j2r(jenv, cls, result, static_method); (*jenv)->DeleteLocalRef(jenv, cls); result->static_method = static_method; register_methodinfo(result, tbl); /* create method alias */ pm = NULL; if (strlen(rname) > 3 && (*rname == 'g' || *rname == 's') && *(rname + 1) == 'e' && *(rname + 2) == 't') { pm = clone_methodinfo(result); if (*rname == 's') { if (result->basic.arg_count == 1) { rname += 3; strcat(rname, "="); } } else { rname += 3; } if (*rname == '_') rname++; } else if (strlen(rname) > 2 && result->basic.result_signature == 'Z' && *rname == 'i' && *(rname + 1) == 's') { pm = clone_methodinfo(result); rname += 2; if (*rname == '_') rname++; strcat(rname, "?"); } else if (alias) { pm = clone_methodinfo(result); } if (pm) { pm->name = rb_intern(rname); register_methodinfo(pm, tbl); } } static void create_fieldinfo(JNIEnv* jenv, st_table* tbl, jobject f, int readonly, int static_field) { struct cls_field* result; const char* jname; jstring nm; jobject cls; char sigs[256]; off_t iv = 0; result = ALLOC(struct cls_field); memset(result, 0, sizeof(struct cls_field)); nm = (*jenv)->CallObjectMethod(jenv, f, field_getName); rjb_check_exception(jenv, 0); jname = (*jenv)->GetStringUTFChars(jenv, nm, NULL); result->name = rb_intern(jname); rjb_release_string(jenv, nm, jname); result->id = (*jenv)->FromReflectedField(jenv, f); rjb_check_exception(jenv, 0); cls = (*jenv)->CallObjectMethod(jenv, f, field_getType); rjb_check_exception(jenv, 0); result->value_convert = get_j2r(jenv, cls, &result->result_signature, &result->result_arraydepth, sigs, &iv, 0); result->arg_convert = get_r2j(jenv, cls, NULL, NULL); (*jenv)->DeleteLocalRef(jenv, cls); result->field_signature = ALLOC_N(char, strlen(sigs) + 1); strcpy(result->field_signature, sigs); if (!result->value_convert) result->value_convert = jv2rv; result->readonly = readonly; result->static_field = static_field; st_insert(tbl, result->name, (VALUE)result); } static void setup_constructors(JNIEnv* jenv, struct cls_constructor*** pptr, jobjectArray methods) { int i; struct cls_constructor* pc; jsize mcount = (*jenv)->GetArrayLength(jenv, methods); struct cls_constructor** tbl = ALLOC_N(struct cls_constructor*, mcount + 1); *pptr = tbl; for (i = 0; i < mcount; i++) { jobjectArray parama; jsize pcount; jobject c = (*jenv)->GetObjectArrayElement(jenv, methods, i); rjb_check_exception(jenv, 0); pc = ALLOC(struct cls_constructor); tbl[i] = pc; parama = (*jenv)->CallObjectMethod(jenv, c, ctrGetParameterTypes); rjb_check_exception(jenv, 0); pcount = (*jenv)->GetArrayLength(jenv, parama); rjb_check_exception(jenv, 0); setup_methodbase(jenv, pc, parama, pcount); pc->id = (*jenv)->FromReflectedMethod(jenv, c); (*jenv)->DeleteLocalRef(jenv, c); } tbl[mcount] = NULL; } static void setup_methods(JNIEnv* jenv, st_table** tbl, st_table** static_tbl, jobjectArray methods) { int i; jint modifier; jsize mcount = (*jenv)->GetArrayLength(jenv, methods); *tbl = st_init_numtable_with_size(mcount); *static_tbl = st_init_numtable(); for (i = 0; i < mcount; i++) { jobject m = (*jenv)->GetObjectArrayElement(jenv, methods, i); rjb_check_exception(jenv, 0); modifier = (*jenv)->CallIntMethod(jenv, m, method_getModifiers); if (!(modifier & ACC_STATIC)) { create_methodinfo(jenv, *tbl, m, 0); } else { create_methodinfo(jenv, *static_tbl, m, 1); } (*jenv)->DeleteLocalRef(jenv, m); } } static void setup_fields(JNIEnv* jenv, st_table** tbl, jobjectArray flds) { int i; jint modifier; jsize fcount = (*jenv)->GetArrayLength(jenv, flds); *tbl = st_init_numtable_with_size(fcount); for (i = 0; i < fcount; i++) { jobject f = (*jenv)->GetObjectArrayElement(jenv, flds, i); rjb_check_exception(jenv, 0); modifier = (*jenv)->CallIntMethod(jenv, f, field_getModifiers); create_fieldinfo(jenv, *tbl, f, modifier & ACC_FINAL, modifier & ACC_STATIC); (*jenv)->DeleteLocalRef(jenv, f); } } static void load_constants(JNIEnv* jenv, jclass klass, VALUE self, jobjectArray flds) { int i; jint modifier; jsize fcount = (*jenv)->GetArrayLength(jenv, flds); for (i = 0; i < fcount; i++) { jobject f = (*jenv)->GetObjectArrayElement(jenv, flds, i); rjb_check_exception(jenv, 0); modifier = (*jenv)->CallIntMethod(jenv, f, field_getModifiers); rjb_check_exception(jenv, 0); if ((modifier & (ACC_PUBLIC | ACC_STATIC | ACC_FINAL)) == (ACC_PUBLIC | ACC_STATIC | ACC_FINAL)) { jstring nm; const char* cname; jobject cls; char sig; char depth; off_t iv; J2R j2r; jvalue jv; jfieldID jfid; char sigs[256]; char* pname; /* constants make define directly in the ruby object */ cls = (*jenv)->CallObjectMethod(jenv, f, field_getType); rjb_check_exception(jenv, 0); iv = 0; sig = depth = 0; j2r = get_j2r(jenv, cls, &sig, &depth, sigs, &iv, 1); if (!j2r) j2r = jv2rv; (*jenv)->DeleteLocalRef(jenv, cls); nm = (*jenv)->CallObjectMethod(jenv, f, field_getName); rjb_check_exception(jenv, 0); cname = (*jenv)->GetStringUTFChars(jenv, nm, NULL); rjb_check_exception(jenv, 0); jfid = (*jenv)->GetStaticFieldID(jenv, klass, cname, sigs); rjb_check_exception(jenv, 0); switch (sig) { case 'D': jv.d = (*jenv)->GetStaticDoubleField(jenv, klass, jfid); break; case 'Z': jv.z = (*jenv)->GetStaticBooleanField(jenv, klass, jfid); break; case 'B': jv.b = (*jenv)->GetStaticByteField(jenv, klass, jfid); break; case 'F': jv.f = (*jenv)->GetStaticFloatField(jenv, klass, jfid); break; case 'C': jv.c = (*jenv)->GetStaticCharField(jenv, klass, jfid); break; case 'S': jv.s = (*jenv)->GetStaticShortField(jenv, klass, jfid); break; case 'J': jv.j = (*jenv)->GetStaticLongField(jenv, klass, jfid); break; case 'I': jv.i = (*jenv)->GetStaticIntField(jenv, klass, jfid); break; default: jv.l = (*jenv)->GetStaticObjectField(jenv, klass, jfid); break; } pname = (char*)cname; if (!isupper(*cname)) { pname = ALLOCA_N(char, strlen(cname) + 1); strcpy(pname, cname); *pname = toupper(*pname); if (!isupper(*pname) || rb_const_defined(rb_obj_class(self), rb_intern(pname))) { pname = NULL; } } if (pname) { rb_define_const(rb_obj_class(self), pname, j2r(jenv, jv)); } rjb_release_string(jenv, nm, cname); } (*jenv)->DeleteLocalRef(jenv, f); } } static void setup_metadata(JNIEnv* jenv, VALUE self, struct jv_data* ptr, VALUE classname) { jmethodID mid; jobjectArray methods; jobjectArray flds; jclass klass = (*jenv)->GetObjectClass(jenv, ptr->idata.obj); ptr->idata.klass = (*jenv)->NewGlobalRef(jenv, klass); rjb_check_exception(jenv, 0); mid = (*jenv)->GetMethodID(jenv, klass, "getMethods", "()[Ljava/lang/reflect/Method;"); rjb_check_exception(jenv, 0); methods = (*jenv)->CallNonvirtualObjectMethod(jenv, ptr->idata.obj, klass, mid); rjb_check_exception(jenv, 0); setup_methods(jenv, &ptr->idata.methods, &ptr->static_methods, methods); mid = (*jenv)->GetMethodID(jenv, klass, "getConstructors", "()[Ljava/lang/reflect/Constructor;"); rjb_check_exception(jenv, 0); methods = (*jenv)->CallNonvirtualObjectMethod(jenv, ptr->idata.obj, klass, mid); rjb_check_exception(jenv, 0); setup_constructors(jenv, &ptr->constructors, methods); mid = (*jenv)->GetMethodID(jenv, klass, "getFields", "()[Ljava/lang/reflect/Field;"); rjb_check_exception(jenv, 0); flds = (*jenv)->CallNonvirtualObjectMethod(jenv, ptr->idata.obj, klass, mid); rjb_check_exception(jenv, 0); setup_fields(jenv, &ptr->idata.fields, flds); register_class(self, classname); load_constants(jenv, ptr->idata.obj, self, flds); } /* * load Java Virtual Machine * def load(class_path = '', vmargs = []) * class_path: passes for the class dir and jar name * vmargs: strng array of vmarg (such as -Xrs) * * change in rjb 0.1.7, omit first argument for JNI version. * because I misunderstood the number means (JVM but JNI). */ static VALUE rjb_s_load(int argc, VALUE* argv, VALUE self) { JNIEnv* jenv; JavaVMInitArgs vm_args; jint res; VALUE classpath; VALUE user_path; VALUE vm_argv; char* userpath; ID stradd = rb_intern("<<"); ID pathsep = rb_intern("PATH_SEPARATOR"); int i; jclass jmethod; jclass jfield; jclass jconstructor; if (rjb_jvm) { return Qnil; } memset(&vm_args, 0, sizeof(vm_args)); vm_args.version = JNI_VERSION_1_4; rb_scan_args(argc, argv, "02", &user_path, &vm_argv); if (!NIL_P(user_path)) { Check_Type(user_path, T_STRING); } else { user_path = rb_str_new2("."); } classpath = rb_cvar_get(rjb, cvar_classpath); for (i = 0; i < RARRAY_LEN(classpath); i++) { rb_funcall(user_path, stradd, 1, rb_const_get(rb_cFile, pathsep)); rb_funcall(user_path, stradd, 1, rb_ary_entry(classpath, 0)); } userpath = StringValueCStr(user_path); if (!NIL_P(vm_argv)) { Check_Type(vm_argv, T_ARRAY); } jenv = NULL; res = rjb_create_jvm(&jenv, &vm_args, userpath, vm_argv); if (res < 0) { rjb_jvm = NULL; rb_raise(rb_eRuntimeError, "can't create Java VM"); } else { main_jenv = jenv; } RJB_FIND_CLASS(jconstructor, "java/lang/reflect/Constructor"); RJB_LOAD_METHOD(ctrGetParameterTypes, jconstructor, "getParameterTypes", "()[Ljava/lang/Class;"); RJB_FIND_CLASS(jmethod, "java/lang/reflect/Method"); RJB_LOAD_METHOD(method_getModifiers, jmethod, "getModifiers", "()I"); RJB_LOAD_METHOD(method_getName, jmethod, "getName", "()Ljava/lang/String;"); RJB_LOAD_METHOD(getParameterTypes, jmethod, "getParameterTypes", "()[Ljava/lang/Class;"); RJB_LOAD_METHOD(getReturnType, jmethod, "getReturnType", "()Ljava/lang/Class;"); rjb_check_exception(jenv, 1); RJB_FIND_CLASS(jfield, "java/lang/reflect/Field"); RJB_LOAD_METHOD(field_getModifiers, jfield, "getModifiers", "()I"); RJB_LOAD_METHOD(field_getName, jfield, "getName", "()Ljava/lang/String;"); RJB_LOAD_METHOD(field_getType, jfield, "getType", "()Ljava/lang/Class;"); rjb_check_exception(jenv, 1); RJB_HOLD_CLASS(j_class, "java/lang/Class"); RJB_LOAD_METHOD(rjb_class_getName, j_class, "getName", "()Ljava/lang/String;"); rjb_check_exception(jenv, 1); RJB_HOLD_CLASS(rjb_j_throwable, "java/lang/Throwable"); RJB_LOAD_METHOD(rjb_throwable_getMessage, rjb_j_throwable, "getMessage", "()Ljava/lang/String;"); rjb_check_exception(jenv, 1); RJB_HOLD_CLASS(j_string, "java/lang/String"); RJB_LOAD_METHOD(str_tostring, j_string, "toString", "()Ljava/lang/String;"); rjb_check_exception(jenv, 1); RJB_HOLD_CLASS(j_object, "java/lang/Object"); rjb_check_exception(jenv, 1); RJB_HOLD_CLASS(j_url, "java/net/URL"); RJB_LOAD_METHOD(url_new, j_url, "", "(Ljava/lang/String;)V"); rjb_check_exception(jenv, 1); for (i = PRM_INT; i < PRM_LAST; i++) { jclass klass; RJB_FIND_CLASS(klass, jpcvt[i].classname); if (i == PRM_BOOLEAN) { RJB_LOAD_STATIC_METHOD(jpcvt[i].ctr_id, klass, "valueOf", jpcvt[i].ctrsig); } else if (jpcvt[i].ctrsig) { RJB_LOAD_METHOD(jpcvt[i].ctr_id, klass, "", jpcvt[i].ctrsig); } RJB_LOAD_METHOD(jpcvt[i].to_prim_id, klass, jpcvt[i].to_prim_method, jpcvt[i].prmsig); jpcvt[i].klass = (*jenv)->NewGlobalRef(jenv, klass); } jklass = import_class(jenv, j_class, rb_str_new2("java.lang.Class")); rb_define_method(rb_singleton_class(jklass), "forName", rjb_class_forname, -1); rb_define_alias(rb_singleton_class(jklass), "for_name", "forName"); rb_gc_register_address(&jklass); return Qnil; } /* * load Java Virtual Machine with default arguments. */ VALUE rjb_load_vm_default() { if (rjb_jvm) return Qfalse; rb_warning("Rjb::implicit jvm loading"); return rjb_s_load(0, NULL, 0); } /* * common prelude */ JNIEnv* rjb_prelude() { JNIEnv* jenv = NULL; rjb_load_vm_default(); jenv = rjb_attach_current_thread(); (*jenv)->ExceptionClear(jenv); return jenv; } jobject get_systemloader(JNIEnv* jenv) { if (!j_classloader) { RJB_HOLD_CLASS(j_classloader, "java/lang/ClassLoader"); RJB_LOAD_STATIC_METHOD(get_system_classloader, j_classloader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;"); rjb_check_exception(jenv, 1); } return (*jenv)->CallStaticObjectMethod(jenv, j_classloader, get_system_classloader); } static jobject get_class_loader(JNIEnv* jenv) { return (url_loader) ? url_loader : get_systemloader(jenv); } /* * unload Java Virtual Machine * * def unload() * classes.clear * unload(jvm) * end */ static int clear_classes(VALUE key, VALUE val, VALUE dummy) { return ST_DELETE; } static VALUE rjb_s_unload(int argc, VALUE* argv, VALUE self) { int result = 0; #if defined(HAVE_RB_HASH_FOREACH) || defined(RUBINIUS) rb_hash_foreach(rjb_loaded_classes, clear_classes, 0); #else #if defined(RHASH_TBL) st_foreach(RHASH_TBL(rjb_loaded_classes), clear_classes, 0); #else st_foreach(RHASH(rjb_loaded_classes)->tbl, clear_classes, 0); #endif #endif if (rjb_jvm) { JNIEnv* jenv = rjb_attach_current_thread(); (*jenv)->ExceptionClear(jenv); result = (*rjb_jvm)->DestroyJavaVM(rjb_jvm); rjb_jvm = NULL; rjb_unload_vm(); } return INT2NUM(result); } static VALUE rjb_s_loaded(VALUE self) { return (rjb_jvm) ? Qtrue : Qfalse; } /* * return all classes that were already loaded. * this method simply returns the global hash, * but it's safe because the hash was frozen. */ static VALUE rjb_s_classes(VALUE self) { return rjb_loaded_classes; } /** * For JRuby conpatible option */ static VALUE rjb_s_set_pconversion(VALUE self, VALUE val) { primitive_conversion = (RTEST(val)) ? Qtrue : Qfalse; return val; } /** * For JRuby conpatible option */ static VALUE rjb_s_get_pconversion(VALUE self) { return primitive_conversion; } /* * free java class */ #if 0 static void free_constructor(struct cls_constructor* p) { free(p->arg_convert); free(p->method_signature); } static int free_method_item(ID key, struct cls_method* pm, int dummy) { for (; pm; pm = pm->next) { free_constructor(&pm->basic); } return ST_CONTINUE; } #endif /* * finalize Object instance */ static VALUE rjb_delete_ref(struct jvi_data* ptr) { JNIEnv* jenv = rjb_attach_current_thread(); if (jenv) { (*jenv)->DeleteGlobalRef(jenv, ptr->obj); } return Qnil; } /* * finalize Bridge instance */ static VALUE rj_bridge_free(struct rj_bridge* ptr) { JNIEnv* jenv = rjb_attach_current_thread(); if (jenv) { (*jenv)->DeleteLocalRef(jenv, ptr->proxy); (*jenv)->DeleteLocalRef(jenv, ptr->bridge); } return Qnil; } /* * mark wrapped object in the Bridge */ static void rj_bridge_mark(struct rj_bridge* ptr) { rb_gc_mark(ptr->wrapped); } /* * finalize Class instance */ static VALUE rjb_s_free(struct jv_data* ptr) { /* class never delete JNIEnv* jenv = rjb_attach_current_thread(); struct cls_constructor** c; rjb_delete_ref(&ptr->idata); if (ptr->constructors) { for (c = ptr->constructors; *c; c++) { free_constructor(*c); } } free(ptr->constructors); if (ptr->idata.methods) { st_foreach(ptr->idata.methods, (int(*)())free_method_item, 0); st_free_table(ptr->idata.methods); } (*jenv)->DeleteGlobalRef(jenv, ptr->idata.klass); st_delete(RHASH(rjb_loaded_classes)->tbl, clsname, NULL); */ return Qnil; } /* * create new instance of this class */ static VALUE createinstance(JNIEnv* jenv, int argc, VALUE* argv, VALUE self, struct cls_constructor* pc) { int i; char* psig = pc->method_signature; jobject obj = NULL; VALUE result; struct jv_data* jklass; struct jvi_data* org; jvalue* args = (argc) ? ALLOCA_N(jvalue, argc) : NULL; Data_Get_Struct(self, struct jv_data, jklass); org = &jklass->idata; for (i = 0; i < argc; i++) { R2J pr2j = *(pc->arg_convert + i); pr2j(jenv, argv[i], args + i, psig, 0); psig = next_sig(psig); rjb_check_exception(jenv, 1); } obj = (*jenv)->NewObjectA(jenv, org->obj, pc->id, args); if (!obj) { rjb_check_exception(jenv, 1); } psig = pc->method_signature; for (i = 0; i < argc; i++) { R2J pr2j = *(pc->arg_convert + i); pr2j(jenv, argv[i], args + i, psig, 1); psig = next_sig(psig); } result = register_instance(jenv, self, jklass, obj); (*jenv)->DeleteLocalRef(jenv, obj); return result; } static VALUE import_class(JNIEnv* jenv, jclass jcls, VALUE clsname) { VALUE v; VALUE rexp; struct jv_data* ptr; char* pclsname = StringValueCStr(clsname); char* nm = ALLOCA_N(char, strlen(pclsname) + 1); strcpy(nm, pclsname); *nm = toupper(*nm); for (pclsname = nm; *pclsname; pclsname++) { if (*pclsname == '.') { *pclsname = '_'; } } rexp = rb_define_class_under(rjb, nm, rjbc); ptr = ALLOC(struct jv_data); memset(ptr, 0, sizeof(struct jv_data)); v = Data_Wrap_Struct(rexp, NULL, rjb_s_free, ptr); ptr->idata.obj = (*jenv)->NewGlobalRef(jenv, jcls); setup_metadata(jenv, v, ptr, clsname); return v; } static VALUE rjb_a_initialize(VALUE self, VALUE proc) { return rb_ivar_set(self, anonymousblock, proc); } static VALUE rjb_a_missing(int argc, VALUE* argv, VALUE self) { VALUE proc = rb_ivar_get(self, anonymousblock); return rb_funcall2(proc, id_call, argc, argv); } static VALUE rjb_i_prepare_proxy(VALUE self) { return rb_funcall(self, rb_intern("instance_eval"), 1, rb_str_new2("instance_eval(&" USER_INITIALIZE ")")); } static VALUE register_instance(JNIEnv* jenv, VALUE klass, struct jv_data* org, jobject obj) { volatile VALUE v; VALUE iproc; struct jvi_data* ptr = ALLOC(struct jvi_data); memset(ptr, 0, sizeof(struct jvi_data)); v = Data_Wrap_Struct(rjbi, NULL, rjb_delete_ref, ptr); ptr->klass = org->idata.obj; ptr->obj = (*jenv)->NewGlobalRef(jenv, obj); ptr->methods = org->idata.methods; ptr->fields = org->idata.fields; iproc = rb_ivar_get(klass, user_initialize); if (iproc != Qnil) { rb_ivar_set(v, user_initialize, iproc); rb_funcall(v, rb_intern("_prepare_proxy"), 0, 0); } rb_funcall(v, initialize_proxy, 0, 0); return v; } /* * temporary signature check * return !0 if found */ static int check_rtype(JNIEnv* jenv, VALUE* pv, char* p) { char* pcls = NULL; if (*p == 'L') { char* pt = strchr(p, ';'); if (pt) { size_t len = pt - p - 1; pcls = ALLOCA_N(char, len + 1); strncpy(pcls, p + 1, len); *(pcls + len) = '\0'; } } if (pcls && !strcmp("java.lang.Object", pcls)) { return 1; } switch (TYPE(*pv)) { case T_FIXNUM: return strchr("BCDFIJS", *p) != NULL; case T_BIGNUM: return strchr("BCDFIJS", *p) != NULL; case T_FLOAT: return strchr("DF", *p) != NULL; case T_STRING: return pcls && !strcmp("java.lang.String", pcls) || *p == '[' && *(p + 1) == 'B'; case T_TRUE: case T_FALSE: return *p == 'Z'; case T_ARRAY: return *p == '['; case T_DATA: if (IS_RJB_OBJECT(*pv) && pcls) { /* imported object */ jclass cls; struct jvi_data* ptr; int result = 0; if (!strcmp("java.lang.String", pcls)) return 1; Data_Get_Struct(*pv, struct jvi_data, ptr); RJB_FIND_CLASS(cls, java2jniname(pcls)); if (cls) { result = (cls && (*jenv)->IsInstanceOf(jenv, ptr->obj, cls)); (*jenv)->DeleteLocalRef(jenv, cls); } return result; } else if (pcls) { VALUE blockobj = rb_class_new_instance(1, pv, rjba); *pv = rjb_s_bind(rjbb, blockobj, rb_str_new2(pcls)); } /* fall down to the next case */ case T_OBJECT: /* fall down to the next case */ default: if (pcls || *p == '[') { return 1; } return 0; } } /* * new instance with signature */ static VALUE rjb_newinstance_s(int argc, VALUE* argv, VALUE self) { VALUE vsig, rest; char* sig; VALUE ret = Qnil; struct jv_data* ptr; int found = 0; JNIEnv* jenv = rjb_prelude(); rb_scan_args(argc, argv, "1*", &vsig, &rest); sig = StringValueCStr(vsig); Data_Get_Struct(self, struct jv_data, ptr); if (ptr->constructors) { struct cls_constructor** pc = ptr->constructors; for (pc = ptr->constructors; *pc; pc++) { if ((*pc)->arg_count == argc - 1 && !strcmp(sig, (*pc)->method_signature)) { found = 1; ret = createinstance(jenv, argc - 1, argv + 1, self, *pc); break; } } } if (!found) { rb_raise(rb_eRuntimeError, "Constructor not found"); } return ret; } static VALUE rjb_newinstance(int argc, VALUE* argv, VALUE self) { VALUE ret = Qnil; struct jv_data* ptr; struct cls_constructor** pc; int found = 0; JNIEnv* jenv = rjb_prelude(); Data_Get_Struct(self, struct jv_data, ptr); if (ptr->constructors) { int i; char* psig; for (pc = ptr->constructors; *pc; pc++) { if ((*pc)->arg_count == argc) { found = 1; psig = (*pc)->method_signature; for (i = 0; i < argc; i++) { if (!check_rtype(jenv, argv + i, psig)) { found = 0; break; } psig = next_sig(psig); } if (found) { ret = createinstance(jenv, argc, argv, self, *pc); break; } } } } if (!found) { rb_raise(rb_eRuntimeError, "Constructor not found"); } return ret; } /* * find java class using added classloader */ jclass rjb_find_class_by_name(JNIEnv* jenv, const char* name) { jclass cls; if (url_loader) { jvalue v; char* binname = ALLOCA_N(char, strlen(name) + 32); strcpy(binname, name); v.l = (*jenv)->NewStringUTF(jenv, jniname2java(binname)); cls = (*jenv)->CallObjectMethod(jenv, url_loader, rjb_load_class, v); (*jenv)->DeleteLocalRef(jenv, v.l); } else { cls = (*jenv)->FindClass(jenv, name); } return cls; } /* * find java class from classname */ jclass rjb_find_class(JNIEnv* jenv, VALUE name) { char* cname; char* jnicls; Check_Type(name, T_STRING); cname = StringValueCStr(name); jnicls = ALLOCA_N(char, strlen(cname) + 1); strcpy(jnicls, cname); return rjb_find_class_by_name(jenv, java2jniname(jnicls)); } /* * get specified method signature */ static VALUE get_signatures(VALUE mname, st_table* st) { VALUE ret; struct cls_method* pm; ID rmid = rb_to_id(mname); if (!st_lookup(st, rmid, (st_data_t*)&pm)) { const char* tname = rb_id2name(rmid); rb_raise(rb_eRuntimeError, "Fail: unknown method name `%s'", tname); } ret = rb_ary_new(); for (; pm; pm = pm->next) { if (pm->basic.method_signature) { rb_ary_push(ret, rb_str_new2(pm->basic.method_signature)); } else { rb_ary_push(ret, Qnil); } } return ret; } static VALUE rjb_get_signatures(VALUE self, VALUE mname) { struct jv_data* ptr; Data_Get_Struct(self, struct jv_data, ptr); return get_signatures(mname, ptr->idata.methods); } static VALUE rjb_get_static_signatures(VALUE self, VALUE mname) { struct jv_data* ptr; Data_Get_Struct(self, struct jv_data, ptr); return get_signatures(mname, ptr->static_methods); } static VALUE rjb_get_ctor_signatures(VALUE self) { VALUE ret; struct jv_data* ptr; struct cls_constructor** pc; Data_Get_Struct(self, struct jv_data, ptr); ret = rb_ary_new(); if (ptr->constructors) { for (pc = ptr->constructors; *pc; pc++) { rb_ary_push(ret, rb_str_new2((*pc)->method_signature)); } } return ret; } /* * jclass Rjb::bind(rbobj, interface_name) */ static VALUE rjb_s_bind(VALUE self, VALUE rbobj, VALUE itfname) { VALUE result = Qnil; jclass itf; JNIEnv* jenv = rjb_prelude(); itf = rjb_find_class(jenv, itfname); rjb_check_exception(jenv, 1); if (itf) { struct rj_bridge* ptr = ALLOC(struct rj_bridge); memset(ptr, 0, sizeof(struct rj_bridge)); ptr->bridge = (*jenv)->NewGlobalRef(jenv, (*jenv)->AllocObject(jenv, rjb_rbridge)); if (!ptr->bridge) { free(ptr); rjb_check_exception(jenv, 1); return Qnil; } ptr->proxy = (*jenv)->CallObjectMethod(jenv, ptr->bridge, rjb_register_bridge, itf); ptr->proxy = (*jenv)->NewGlobalRef(jenv, ptr->proxy); ptr->wrapped = rbobj; result = Data_Wrap_Struct(rjbb, rj_bridge_mark, rj_bridge_free, ptr); rb_ary_push(proxies, result); rb_ivar_set(result, rb_intern("@wrapped"), rbobj); } return result; } /* * Rjb's class is not Class but Object, so add class_eval for the Java class. */ static VALUE rjb_class_eval(int argc, VALUE* argv, VALUE self) { if (rb_block_given_p()) { rb_ivar_set(self, user_initialize, rb_block_proc()); } return self; } static VALUE rjb_s_impl(VALUE self) { VALUE obj; VALUE proc; rb_need_block(); proc = rb_block_proc(); obj = rb_class_new_instance(1, &proc, rjba); return rjb_s_bind(rjbb, obj, rb_funcall(self, rb_intern("name"), 0)); } /* * jclass Rjb::bind(rbobj, interface_name) */ static VALUE rjb_s_unbind(VALUE self, VALUE rbobj) { #if defined(RUBINIUS) return rb_funcall(proxies, rb_intern("delete"), 1, rbobj); #else return rb_ary_delete(proxies, rbobj); #endif } /* * Jclass Rjb::import(classname) */ static VALUE rjb_s_import(VALUE self, VALUE clsname) { JNIEnv* jenv; jclass jcls; VALUE v = rb_hash_aref(rjb_loaded_classes, clsname); if (v != Qnil) { return v; } jenv = rjb_prelude(); jcls = rjb_find_class(jenv, clsname); if (!jcls) { rjb_check_exception(jenv, 0); rb_raise(rb_eRuntimeError, "`%s' not found", StringValueCStr(clsname)); } v = import_class(jenv, jcls, clsname); return v; } static void register_class(VALUE self, VALUE clsname) { rb_define_singleton_method(self, "new", rjb_newinstance, -1); rb_define_singleton_method(self, "new_with_sig", rjb_newinstance_s, -1); rb_define_singleton_method(self, "class_eval", rjb_class_eval, -1); rb_define_singleton_method(self, "sigs", rjb_get_signatures, 1); rb_define_singleton_method(self, "static_sigs", rjb_get_static_signatures, 1); rb_define_singleton_method(self, "ctor_sigs", rjb_get_ctor_signatures, 0); rb_ivar_set(self, user_initialize, Qnil); /* * the hash was frozen, so it need to call st_ func directly. */ #if defined(HAVE_RB_HASH_ASET) || defined(RUBINIUS) rb_hash_aset(rjb_loaded_classes, clsname, self); #else #ifdef RHASH_TBL st_insert(RHASH_TBL(rjb_loaded_classes), clsname, self); #else st_insert(RHASH(rjb_loaded_classes)->tbl, clsname, self); #endif #endif } static jobject conv_jarname_to_url(JNIEnv* jenv, VALUE jarname) { jvalue arg; jobject url; #if defined(DOSISH) size_t len; #endif char* jarp; char* urlp; SafeStringValue(jarname); jarp = StringValueCStr(jarname); urlp = ALLOCA_N(char, strlen(jarp) + 32); if (strncmp(jarp, "http:", 5) && strncmp(jarp, "https:", 6)) { #if defined(DOSISH) if (strlen(jarp) > 1 && jarp[1] == ':') { sprintf(urlp, "file:///%s", jarp); } else #endif { sprintf(urlp, "file://%s", jarp); } } else { strcpy(urlp, jarp); } #if defined(DOSISH) for (len = 0; len < strlen(urlp); len++) { if (urlp[len] == '\\') { urlp[len] = '/'; } } #endif arg.l = (*jenv)->NewStringUTF(jenv, urlp); rjb_check_exception(jenv, 0); url = (*jenv)->NewObject(jenv, j_url, url_new, arg); rjb_check_exception(jenv, 0); return url; } /* * Rjb::add_classpath(jarname) */ static VALUE rjb_s_add_classpath(VALUE self, VALUE jarname) { VALUE cpath = rb_cvar_get(self, cvar_classpath); SafeStringValue(jarname); rb_ary_push(cpath, jarname); return cpath; } /* * Rjb::add_jar(jarname) */ static VALUE rjb_s_add_jar(VALUE self, VALUE jarname) { size_t i; JNIEnv* jenv; size_t count; jvalue args[2]; if (rb_type(jarname) != T_ARRAY) { SafeStringValue(jarname); count = 0; } else { count = RARRAY_LEN(jarname); } jenv = rjb_prelude(); if (!j_url_loader) { j_url_loader = (*jenv)->NewGlobalRef(jenv, (*jenv)->FindClass(jenv, "java/net/URLClassLoader")); RJB_LOAD_METHOD(rjb_load_class, j_url_loader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); RJB_LOAD_METHOD(url_loader_new, j_url_loader, "", "([Ljava/net/URL;Ljava/lang/ClassLoader;)V"); RJB_LOAD_METHOD(url_geturls, j_url_loader, "getURLs", "()[Ljava/net/URL;"); RJB_LOAD_METHOD(url_add_url, j_url_loader, "addURL", "(Ljava/net/URL;)V"); } if (!url_loader) { args[0].l = (*jenv)->NewObjectArray(jenv, (jsize)((count == 0) ? 1 : count), j_url, NULL); rjb_check_exception(jenv, 0); if (!count) { (*jenv)->SetObjectArrayElement(jenv, args[0].l, 0, conv_jarname_to_url(jenv, jarname)); } else { for (i = 0; i < count; i++) { (*jenv)->SetObjectArrayElement(jenv, args[0].l, (jint)i, conv_jarname_to_url(jenv, rb_ary_entry(jarname, i))); } } rjb_check_exception(jenv, 0); args[1].l = get_class_loader(jenv); url_loader = (*jenv)->NewObjectA(jenv, j_url_loader, url_loader_new, args); rjb_check_exception(jenv, 0); (*jenv)->NewGlobalRef(jenv, url_loader); (*jenv)->DeleteLocalRef(jenv, args[0].l); } else { jvalue v; if (count) { for (i = 0; i < count; i++) { v.l = conv_jarname_to_url(jenv, rb_ary_entry(jarname, i)); (*jenv)->CallObjectMethod(jenv, url_loader, url_add_url, v); rjb_check_exception(jenv, 0); (*jenv)->DeleteLocalRef(jenv, v.l); } } else { v.l = conv_jarname_to_url(jenv, jarname); (*jenv)->CallObjectMethod(jenv, url_loader, url_add_url, v); rjb_check_exception(jenv, 0); (*jenv)->DeleteLocalRef(jenv, v.l); } } return Qtrue; } static VALUE rjb_s_urls(VALUE self) { JNIEnv* jenv; jvalue ret; if (!url_loader) return Qnil; jenv = rjb_prelude(); ret.l = (*jenv)->CallObjectMethod(jenv, url_loader, url_geturls); return jarray2rv(jenv, ret); } /* * return class name */ static VALUE rjb_i_class(VALUE self) { JNIEnv* jenv = rjb_attach_current_thread(); struct jvi_data* ptr; jstring nm; Data_Get_Struct(self, struct jvi_data, ptr); nm = (*jenv)->CallObjectMethod(jenv, ptr->klass, rjb_class_getName); rjb_check_exception(jenv, 0); return jstring2val(jenv, nm); } /* * invoker */ static VALUE getter(JNIEnv* jenv, struct cls_field* pf, struct jvi_data* ptr) { jvalue jv; switch (pf->result_signature) { case 'D': if (pf->static_field) { jv.d = (*jenv)->GetStaticDoubleField(jenv, ptr->klass, pf->id); } else { jv.d = (*jenv)->GetDoubleField(jenv, ptr->obj, pf->id); } break; case 'Z': if (pf->static_field) { jv.z = (*jenv)->GetStaticBooleanField(jenv, ptr->klass, pf->id); } else { jv.z = (*jenv)->GetBooleanField(jenv, ptr->obj, pf->id); } break; case 'B': if (pf->static_field) { jv.b = (*jenv)->GetStaticByteField(jenv, ptr->klass, pf->id); } else { jv.b = (*jenv)->GetByteField(jenv, ptr->obj, pf->id); } break; case 'F': if (pf->static_field) { jv.f = (*jenv)->GetStaticFloatField(jenv, ptr->klass, pf->id); } else { jv.f = (*jenv)->GetFloatField(jenv, ptr->obj, pf->id); } break; case 'C': if (pf->static_field) { jv.c = (*jenv)->GetStaticCharField(jenv, ptr->klass, pf->id); } else { jv.c = (*jenv)->GetCharField(jenv, ptr->obj, pf->id); } break; case 'S': if (pf->static_field) { jv.s = (*jenv)->GetStaticShortField(jenv, ptr->klass, pf->id); } else { jv.s = (*jenv)->GetShortField(jenv, ptr->obj, pf->id); } break; case 'J': if (pf->static_field) { jv.j = (*jenv)->GetStaticLongField(jenv, ptr->klass, pf->id); } else { jv.j = (*jenv)->GetLongField(jenv, ptr->obj, pf->id); } break; case 'I': if (pf->static_field) { jv.i = (*jenv)->GetStaticIntField(jenv, ptr->klass, pf->id); } else { jv.i = (*jenv)->GetIntField(jenv, ptr->obj, pf->id); } break; default: if (pf->static_field) { jv.l = (*jenv)->GetStaticObjectField(jenv, ptr->klass, pf->id); } else { jv.l = (*jenv)->GetObjectField(jenv, ptr->obj, pf->id); } break; } if (pf->result_arraydepth) { return ja2r(pf->value_convert, jenv, jv, pf->result_arraydepth); } else { return pf->value_convert(jenv, jv); } } static void setter(JNIEnv* jenv, struct cls_field* pf, struct jvi_data* ptr, VALUE val) { jvalue jv; pf->arg_convert(jenv, val, &jv, pf->field_signature, 0); switch (*pf->field_signature) { case 'D': if (pf->static_field) { (*jenv)->SetStaticDoubleField(jenv, ptr->klass, pf->id, jv.d); } else { (*jenv)->SetDoubleField(jenv, ptr->obj, pf->id, jv.d); } break; case 'Z': if (pf->static_field) { (*jenv)->SetStaticBooleanField(jenv, ptr->klass, pf->id, jv.z); } else { (*jenv)->SetBooleanField(jenv, ptr->obj, pf->id, jv.z); } break; case 'B': if (pf->static_field) { (*jenv)->SetStaticByteField(jenv, ptr->klass, pf->id, jv.b); } else { (*jenv)->SetByteField(jenv, ptr->obj, pf->id, jv.b); } break; case 'F': if (pf->static_field) { (*jenv)->SetStaticFloatField(jenv, ptr->klass, pf->id, jv.f); } else { (*jenv)->SetFloatField(jenv, ptr->obj, pf->id, jv.f); } break; case 'C': if (pf->static_field) { (*jenv)->SetStaticCharField(jenv, ptr->klass, pf->id, jv.c); } else { (*jenv)->SetCharField(jenv, ptr->obj, pf->id, jv.c); } break; case 'S': if (pf->static_field) { (*jenv)->SetStaticShortField(jenv, ptr->klass, pf->id, jv.s); } else { (*jenv)->SetShortField(jenv, ptr->obj, pf->id, jv.s); } break; case 'J': if (pf->static_field) { (*jenv)->SetStaticLongField(jenv, ptr->klass, pf->id, jv.j); } else { (*jenv)->SetLongField(jenv, ptr->obj, pf->id, jv.j); } break; case 'I': if (pf->static_field) { (*jenv)->SetStaticIntField(jenv, ptr->klass, pf->id, jv.i); } else { (*jenv)->SetIntField(jenv, ptr->obj, pf->id, jv.i); } break; default: if (pf->static_field) { (*jenv)->SetStaticObjectField(jenv, ptr->klass, pf->id, jv.l); } else { (*jenv)->SetObjectField(jenv, ptr->obj, pf->id, jv.l); } break; } pf->arg_convert(jenv, val, &jv, pf->field_signature, 1); } static VALUE invoke(JNIEnv* jenv, struct cls_method* pm, struct jvi_data* ptr, int argc, VALUE* argv, const char* sig) { int i, found; jvalue jv; jvalue* args; char* psig; struct cls_method* orgpm = pm; if (rb_block_given_p()) { VALUE* pargs = ALLOCA_N(VALUE, argc + 1); memcpy(pargs, argv, argc * sizeof(VALUE)); *(pargs + argc) = rb_block_proc(); ++argc; argv = pargs; } for (found = 0; pm; pm = pm->next) { if (argc == pm->basic.arg_count) { if (sig && pm->basic.method_signature) { if (!strcmp(sig, pm->basic.method_signature)) { found = 1; break; } } else { psig = pm->basic.method_signature; found = 1; for (i = 0; i < argc; i++) { if (!check_rtype(jenv, argv + i, psig)) { found = 0; break; } psig = next_sig(psig); } if (found) break; } } } if (!found) { const char* tname = rb_id2name(orgpm->name); if (sig) { rb_raise(rb_eRuntimeError, "Fail: unknown method name `%s(\'%s\')'", tname, sig); } else { rb_raise(rb_eRuntimeError, "Fail: unknown method name `%s'", tname); } } args = (argc) ? ALLOCA_N(jvalue, argc) : NULL; psig = pm->basic.method_signature; for (i = 0; i < argc; i++) { R2J pr2j = *(pm->basic.arg_convert + i); pr2j(jenv, argv[i], args + i, psig, 0); psig = next_sig(psig); } switch (pm->basic.result_signature) { case 'D': { INVOKEAD voked = *(INVOKEAD*)(((char*)*jenv) + pm->method); jv.d = voked(jenv, ptr->obj, pm->basic.id, args); } break; case 'Z': case 'B': { INVOKEAZ vokez = *(INVOKEAZ*)(((char*)*jenv) + pm->method); jv.z = vokez(jenv, ptr->obj, pm->basic.id, args); } break; case 'F': { INVOKEAF vokef = *(INVOKEAF*)(((char*)*jenv) + pm->method); jv.f = vokef(jenv, ptr->obj, pm->basic.id, args); } break; case 'C': case 'S': { INVOKEAS vokes = *(INVOKEAS*)(((char*)*jenv) + pm->method); jv.s = vokes(jenv, ptr->obj, pm->basic.id, args); } break; #if HAVE_LONG_LONG case 'J': { INVOKEAL vokel = *(INVOKEAL*)(((char*)*jenv) + pm->method); jv.j = vokel(jenv, ptr->obj, pm->basic.id, args); } break; #endif default: { INVOKEA voke = *(INVOKEA*)(((char*)*jenv) + pm->method); jv.l = voke(jenv, ptr->obj, pm->basic.id, args); } break; } rjb_check_exception(jenv, 1); psig = pm->basic.method_signature; for (i = 0; i < argc; i++) { R2J pr2j = *(pm->basic.arg_convert + i); pr2j(jenv, argv[i], args + i, psig, 1); psig = next_sig(psig); } if (pm->basic.result_arraydepth) { return ja2r(pm->result_convert, jenv, jv, pm->basic.result_arraydepth); } else { return pm->result_convert(jenv, jv); } } /* * Object invocation */ static VALUE invoke_by_instance(ID rmid, int argc, VALUE* argv, struct jvi_data* ptr, char* sig) { VALUE ret = Qnil; JNIEnv* jenv = rjb_attach_current_thread(); struct cls_field* pf; struct cls_method* pm; const char* tname = rb_id2name(rmid); if (argc == 0 && st_lookup(ptr->fields, rmid, (st_data_t*)&pf)) { ret = getter(jenv, pf, ptr); } else { if (argc == 1 && *(tname + strlen(tname) - 1) == '=') { char* fname = ALLOCA_N(char, strlen(tname) + 1); strcpy(fname, tname); fname[strlen(tname) - 1] = '\0'; if (st_lookup(ptr->fields, rb_intern(fname), (st_data_t*)&pf)) { setter(jenv, pf, ptr, *argv); return ret; } /* fall through for the setter alias name */ } if (st_lookup(ptr->methods, rmid, (st_data_t*)&pm)) { ret = invoke(jenv, pm, ptr, argc, argv, sig); } else { rb_raise(rb_eRuntimeError, "Fail: unknown method name `%s'", tname); } } return ret; } static VALUE get_signature(int* argc, VALUE* argv, VALUE* rmid) { VALUE vsig; rb_scan_args(*argc, argv, "1*", rmid, &vsig); if (*argc == 1) { ++*argc; vsig = Qnil; } else { vsig = *(argv + 1); } return vsig; } static VALUE rjb_i_invoke(int argc, VALUE* argv, VALUE self) { VALUE vsig, rmid; char* sig; struct jvi_data* ptr; vsig = get_signature(&argc, argv, &rmid); rmid = rb_to_id(rmid); sig = NIL_P(vsig) ? NULL : StringValueCStr(vsig); Data_Get_Struct(self, struct jvi_data, ptr); return invoke_by_instance(rmid, argc - 2, argv + 2, ptr, sig); } static VALUE rjb_i_missing(int argc, VALUE* argv, VALUE self) { struct jvi_data* ptr; ID rmid = rb_to_id(argv[0]); Data_Get_Struct(self, struct jvi_data, ptr); return invoke_by_instance(rmid, argc -1, argv + 1, ptr, NULL); } /* * Class invocation (first static method, then instance method) */ static VALUE invoke_by_class(ID rmid, int argc, VALUE* argv, struct jv_data* ptr, char* sig) { VALUE ret = Qnil; struct jv_data* clsptr; struct cls_field* pf; struct cls_method* pm; const char* tname = rb_id2name(rmid); JNIEnv* jenv = rjb_attach_current_thread(); Data_Get_Struct(jklass, struct jv_data, clsptr); if (argc == 0 && st_lookup(ptr->idata.fields, rmid, (st_data_t*)&pf)) { if (!pf->static_field) { rb_raise(rb_eRuntimeError, "instance field `%s' for class", tname); } ret = getter(jenv, pf, &ptr->idata); } else if (argc == 1 && *(tname + strlen(tname) - 1) == '=') { char* fname = ALLOCA_N(char, strlen(tname) + 1); strcpy(fname, tname); fname[strlen(tname) - 1] = '\0'; if (st_lookup(ptr->idata.fields, rb_intern(fname), (st_data_t*)&pf)) { if (!pf->static_field) { rb_raise(rb_eRuntimeError, "instance field `%s' for class", fname); } setter(jenv, pf, &ptr->idata, *argv); } else { rb_raise(rb_eRuntimeError, "Fail: unknown field name `%s'", fname); } } else if (st_lookup(ptr->static_methods, rmid, (st_data_t*)&pm)) { ret = invoke(jenv, pm, &ptr->idata, argc, argv, sig); } else if (st_lookup(clsptr->idata.methods, rmid, (st_data_t*)&pm)) { ret = invoke(jenv, pm, &ptr->idata, argc, argv, sig); } else { if (st_lookup(ptr->idata.methods, rmid, (st_data_t*)&pm)) { rb_raise(rb_eRuntimeError, "instance method `%s' for class", tname); } else { rb_raise(rb_eRuntimeError, "Fail: unknown method name `%s'", tname); } } return ret; } static VALUE rjb_invoke(int argc, VALUE* argv, VALUE self) { VALUE vsig, rmid; char* sig; struct jv_data* ptr; vsig = get_signature(&argc, argv, &rmid); rmid = rb_to_id(rmid); sig = NIL_P(vsig) ? NULL : StringValueCStr(vsig); Data_Get_Struct(self, struct jv_data, ptr); return invoke_by_class(rmid, argc - 2, argv + 2, ptr, sig); } static VALUE find_const(VALUE pv) { VALUE* p = (VALUE*)pv; return rb_const_get(*p, (ID)*(p + 1)); } static VALUE rjb_missing(int argc, VALUE* argv, VALUE self) { struct jv_data* ptr; ID rmid = rb_to_id(argv[0]); const char* rmname = rb_id2name(rmid); if (isupper(*rmname)) { VALUE r, args[2]; int state = 0; args[0] = rb_obj_class(self); args[1] = rmid; r = rb_protect(find_const, (VALUE)args, &state); if (!state) { return r; } } Data_Get_Struct(self, struct jv_data, ptr); return invoke_by_class(rmid, argc - 1, argv + 1, ptr, NULL); } /* * Class#forName entry. */ static VALUE rjb_class_forname(int argc, VALUE* argv, VALUE self) { if (argc == 1) { return rjb_s_import(self, *argv); } else { struct jv_data* ptr; ID rmid = rb_intern("forName"); Data_Get_Struct(self, struct jv_data, ptr); return invoke_by_class(rmid, argc, argv, ptr, NULL); } } /* * Class initializer called by Ruby while requiring this library */ void Init_rjbcore() { #if RJB_RUBY_VERSION_CODE < 190 #if defined(RUBINIUS) rb_require("iconv"); #else rb_protect((VALUE(*)(VALUE))rb_require, (VALUE)"iconv", NULL); #endif #endif rjb_loaded_classes = rb_hash_new(); #ifndef RUBINIUS OBJ_FREEZE(rjb_loaded_classes); #endif rb_global_variable(&rjb_loaded_classes); proxies = rb_ary_new(); rb_global_variable(&proxies); user_initialize = rb_intern(USER_INITIALIZE); initialize_proxy = rb_intern("initialize_proxy"); rjb = rb_define_module("Rjb"); rb_define_module_function(rjb, "load", rjb_s_load, -1); rb_define_module_function(rjb, "unload", rjb_s_unload, -1); rb_define_module_function(rjb, "loaded?", rjb_s_loaded, 0); rb_define_module_function(rjb, "import", rjb_s_import, 1); rb_define_module_function(rjb, "bind", rjb_s_bind, 2); rb_define_module_function(rjb, "unbind", rjb_s_unbind, 1); rb_define_module_function(rjb, "classes", rjb_s_classes, 0); rb_define_module_function(rjb, "throw", rjb_s_throw, -1); rb_define_module_function(rjb, "primitive_conversion=", rjb_s_set_pconversion, 1); rb_define_module_function(rjb, "primitive_conversion", rjb_s_get_pconversion, 0); rb_define_module_function(rjb, "add_classpath", rjb_s_add_classpath, 1); rb_define_module_function(rjb, "add_jar", rjb_s_add_jar, 1); rb_define_alias(rjb, "add_jars", "add_jar"); rb_define_module_function(rjb, "urls", rjb_s_urls, 0); rb_define_const(rjb, "VERSION", rb_str_new2(RJB_VERSION)); rb_define_class_variable(rjb, "@@classpath", rb_ary_new()); cvar_classpath = rb_intern("@@classpath"); /* Java class object */ rjbc = CLASS_NEW(rb_cObject, "Rjb_JavaClass"); rb_gc_register_address(&rjbc); rb_define_method(rjbc, "method_missing", rjb_missing, -1); rb_define_method(rjbc, "impl", rjb_s_impl, 0); rb_define_method(rjbc, "_invoke", rjb_invoke, -1); rb_define_method(rjbc, "_classname", rjb_i_class, 0); /* Java instance object */ rjbi = CLASS_NEW(rb_cObject, "Rjb_JavaProxy"); rb_gc_register_address(&rjbi); rb_define_method(rjbi, "method_missing", rjb_i_missing, -1); rb_define_method(rjbi, "_invoke", rjb_i_invoke, -1); rb_define_method(rjbi, "_classname", rjb_i_class, 0); rb_define_method(rjbi, "_prepare_proxy", rjb_i_prepare_proxy, 0); rb_define_alias(rjbi, "include", "extend"); /* Ruby-Java Bridge object */ rjbb = CLASS_NEW(rb_cObject, "Rjb_JavaBridge"); rb_gc_register_address(&rjbb); /* anonymous interface object */ rjba = CLASS_NEW(rb_cObject, "Rjb_AnonymousClass"); rb_gc_register_address(&rjba); rb_define_method(rjba, "initialize", rjb_a_initialize, 1); rb_define_method(rjba, "method_missing", rjb_a_missing, -1); anonymousblock = rb_intern("@anon_block"); id_call = rb_intern("call"); } VALUE rjb_safe_funcall(VALUE args) { VALUE* argp = (VALUE*)args; return rb_funcall2(*argp, *(argp + 1), (int)*(argp + 2), argp + 3); } /** Entry point from JavaVM through java.reflect.Proxy */ JNIEXPORT jobject JNICALL Java_jp_co_infoseek_hp_arton_rjb_RBridge_call (JNIEnv * jenv, jobject bridge, jstring name, jobject proxy, jobjectArray args) { int i; jvalue j; memset(&j, 0, sizeof(j)); for (i = 0; i < RARRAY_LEN(proxies); i++) { struct rj_bridge* ptr; VALUE val = RARRAY_PTR(proxies)[i]; Data_Get_Struct(val, struct rj_bridge, ptr); if ((*jenv)->IsSameObject(jenv, proxy, ptr->proxy)) { int sstat; VALUE result; VALUE* argv = NULL; int argc = 3; ID id = rb_to_id(jstring2val(jenv, name)); if (args) { int i; jsize js = (*jenv)->GetArrayLength(jenv, args); argc += (int)js; argv = ALLOCA_N(VALUE, argc); memset(argv, 0, sizeof(VALUE*) * argc); for (i = 3; i < argc; i++) { jobject f = (*jenv)->GetObjectArrayElement(jenv, args, i - 3); /* f will be release in jv2rv_withprim */ *(argv + i) = jv2rv_withprim(jenv, f); } } else { argv = ALLOCA_N(VALUE, argc + 1); memset(argv, 0, sizeof(VALUE*) * (argc + 1)); } *argv = ptr->wrapped; *(argv + 1) = id; *(argv + 2) = argc - 3; result = rb_protect(rjb_safe_funcall, (VALUE)argv, &sstat); rv2jobject(jenv, result, &j, NULL, 0); /* I can't delete this object... */ break; } } return j.l; } rjb-1.4.8/ext/extconf.h0000755000175000017500000000025512161443611013750 0ustar lunarlunar#ifndef EXTCONF_H #define EXTCONF_H #define HAVE_JNI_H 1 #define HAVE_DL_H 1 #define HAVE_SETLOCALE 1 #define HAVE_GETENV 1 #define RJB_RUBY_VERSION_CODE 187 #endif rjb-1.4.8/setup.rb0000644000175000017500000007111012161443611013011 0ustar lunarlunar# # setup.rb # # Copyright (c) 2000-2004 Minero Aoki # # This program is free software. # You can distribute/modify this program under the terms of # the GNU LGPL, Lesser General Public License version 2.1. # unless Enumerable.method_defined?(:map) # Ruby 1.4.6 module Enumerable alias map collect end end unless File.respond_to?(:read) # Ruby 1.6 def File.read(fname) open(fname) {|f| return f.read } end end def File.binread(fname) open(fname, 'rb') {|f| return f.read } end # for corrupted windows stat(2) def File.dir?(path) File.directory?((path[-1,1] == '/') ? path : path + '/') end class SetupError < StandardError; end def setup_rb_error(msg) raise SetupError, msg end # # Config # if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg } ARGV.delete(arg) require arg.split(/=/, 2)[1] $".push 'rbconfig.rb' else require 'rbconfig' end def multipackage_install? FileTest.directory?(File.dirname($0) + '/packages') end class ConfigItem def initialize(name, template, default, desc) @name = name.freeze @template = template @value = default @default = default.dup.freeze @description = desc end attr_reader :name attr_reader :description attr_accessor :default alias help_default default def help_opt "--#{@name}=#{@template}" end def value @value end def eval(table) @value.gsub(%r<\$([^/]+)>) { table[$1] } end def set(val) @value = check(val) end private def check(val) setup_rb_error "config: --#{name} requires argument" unless val val end end class BoolItem < ConfigItem def config_type 'bool' end def help_opt "--#{@name}" end private def check(val) return 'yes' unless val unless /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i =~ val setup_rb_error "config: --#{@name} accepts only yes/no for argument" end (/\Ay(es)?|\At(rue)/i =~ value) ? 'yes' : 'no' end end class PathItem < ConfigItem def config_type 'path' end private def check(path) setup_rb_error "config: --#{@name} requires argument" unless path path[0,1] == '$' ? path : File.expand_path(path) end end class ProgramItem < ConfigItem def config_type 'program' end end class SelectItem < ConfigItem def initialize(name, template, default, desc) super @ok = template.split('/') end def config_type 'select' end private def check(val) unless @ok.include?(val.strip) setup_rb_error "config: use --#{@name}=#{@template} (#{val})" end val.strip end end class PackageSelectionItem < ConfigItem def initialize(name, template, default, help_default, desc) super name, template, default, desc @help_default = help_default end attr_reader :help_default def config_type 'package' end private def check(val) unless File.dir?("packages/#{val}") setup_rb_error "config: no such package: #{val}" end val end end class ConfigTable_class def initialize(items) @items = items @table = {} items.each do |i| @table[i.name] = i end ALIASES.each do |ali, name| @table[ali] = @table[name] end end include Enumerable def each(&block) @items.each(&block) end def key?(name) @table.key?(name) end def lookup(name) @table[name] or raise ArgumentError, "no such config item: #{name}" end def add(item) @items.push item @table[item.name] = item end def remove(name) item = lookup(name) @items.delete_if {|i| i.name == name } @table.delete_if {|name, i| i.name == name } item end def new dup() end def savefile '.config' end def load begin t = dup() File.foreach(savefile()) do |line| k, v = *line.split(/=/, 2) t[k] = v.strip end t rescue Errno::ENOENT setup_rb_error $!.message + "#{File.basename($0)} config first" end end def save @items.each {|i| i.value } File.open(savefile(), 'w') {|f| @items.each do |i| f.printf "%s=%s\n", i.name, i.value if i.value end } end def [](key) lookup(key).eval(self) end def []=(key, val) lookup(key).set val end end c = ::Config::CONFIG rubypath = c['bindir'] + '/' + c['ruby_install_name'] major = c['MAJOR'].to_i minor = c['MINOR'].to_i teeny = c['TEENY'].to_i version = "#{major}.#{minor}" # ruby ver. >= 1.4.4? newpath_p = ((major >= 2) or ((major == 1) and ((minor >= 5) or ((minor == 4) and (teeny >= 4))))) if c['rubylibdir'] # V < 1.6.3 _stdruby = c['rubylibdir'] _siteruby = c['sitedir'] _siterubyver = c['sitelibdir'] _siterubyverarch = c['sitearchdir'] elsif newpath_p # 1.4.4 <= V <= 1.6.3 _stdruby = "$prefix/lib/ruby/#{version}" _siteruby = c['sitedir'] _siterubyver = "$siteruby/#{version}" _siterubyverarch = "$siterubyver/#{c['arch']}" else # V < 1.4.4 _stdruby = "$prefix/lib/ruby/#{version}" _siteruby = "$prefix/lib/ruby/#{version}/site_ruby" _siterubyver = _siteruby _siterubyverarch = "$siterubyver/#{c['arch']}" end libdir = '-* dummy libdir *-' stdruby = '-* dummy rubylibdir *-' siteruby = '-* dummy site_ruby *-' siterubyver = '-* dummy site_ruby version *-' parameterize = lambda {|path| path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')\ .sub(/\A#{Regexp.quote(libdir)}/, '$libdir')\ .sub(/\A#{Regexp.quote(stdruby)}/, '$stdruby')\ .sub(/\A#{Regexp.quote(siteruby)}/, '$siteruby')\ .sub(/\A#{Regexp.quote(siterubyver)}/, '$siterubyver') } libdir = parameterize.call(c['libdir']) stdruby = parameterize.call(_stdruby) siteruby = parameterize.call(_siteruby) siterubyver = parameterize.call(_siterubyver) siterubyverarch = parameterize.call(_siterubyverarch) if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg } makeprog = arg.sub(/'/, '').split(/=/, 2)[1] else makeprog = 'make' end common_conf = [ PathItem.new('prefix', 'path', c['prefix'], 'path prefix of target environment'), PathItem.new('bindir', 'path', parameterize.call(c['bindir']), 'the directory for commands'), PathItem.new('libdir', 'path', libdir, 'the directory for libraries'), PathItem.new('datadir', 'path', parameterize.call(c['datadir']), 'the directory for shared data'), PathItem.new('mandir', 'path', parameterize.call(c['mandir']), 'the directory for man pages'), PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']), 'the directory for man pages'), PathItem.new('stdruby', 'path', stdruby, 'the directory for standard ruby libraries'), PathItem.new('siteruby', 'path', siteruby, 'the directory for version-independent aux ruby libraries'), PathItem.new('siterubyver', 'path', siterubyver, 'the directory for aux ruby libraries'), PathItem.new('siterubyverarch', 'path', siterubyverarch, 'the directory for aux ruby binaries'), PathItem.new('rbdir', 'path', '$siterubyver', 'the directory for ruby scripts'), PathItem.new('sodir', 'path', '$siterubyverarch', 'the directory for ruby extentions'), PathItem.new('rubypath', 'path', rubypath, 'the path to set to #! line'), ProgramItem.new('rubyprog', 'name', rubypath, 'the ruby program using for installation'), ProgramItem.new('makeprog', 'name', makeprog, 'the make program to compile ruby extentions'), SelectItem.new('shebang', 'all/ruby/never', 'ruby', 'shebang line (#!) editing mode'), BoolItem.new('without-ext', 'yes/no', 'no', 'does not compile/install ruby extentions') ] class ConfigTable_class # open again ALIASES = { 'std-ruby' => 'stdruby', 'site-ruby-common' => 'siteruby', # For backward compatibility 'site-ruby' => 'siterubyver', # For backward compatibility 'bin-dir' => 'bindir', 'bin-dir' => 'bindir', 'rb-dir' => 'rbdir', 'so-dir' => 'sodir', 'data-dir' => 'datadir', 'ruby-path' => 'rubypath', 'ruby-prog' => 'rubyprog', 'ruby' => 'rubyprog', 'make-prog' => 'makeprog', 'make' => 'makeprog' } end multipackage_conf = [ PackageSelectionItem.new('with', 'name,name...', '', 'ALL', 'package names that you want to install'), PackageSelectionItem.new('without', 'name,name...', '', 'NONE', 'package names that you do not want to install') ] if multipackage_install? ConfigTable = ConfigTable_class.new(common_conf + multipackage_conf) else ConfigTable = ConfigTable_class.new(common_conf) end module MetaConfigAPI def eval_file_ifexist(fname) instance_eval File.read(fname), fname, 1 if File.file?(fname) end def config_names ConfigTable.map {|i| i.name } end def config?(name) ConfigTable.key?(name) end def bool_config?(name) ConfigTable.lookup(name).config_type == 'bool' end def path_config?(name) ConfigTable.lookup(name).config_type == 'path' end def value_config?(name) case ConfigTable.lookup(name).config_type when 'bool', 'path' true else false end end def add_config(item) ConfigTable.add item end def add_bool_config(name, default, desc) ConfigTable.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc) end def add_path_config(name, default, desc) ConfigTable.add PathItem.new(name, 'path', default, desc) end def set_config_default(name, default) ConfigTable.lookup(name).default = default end def remove_config(name) ConfigTable.remove(name) end end # # File Operations # module FileOperations def mkdir_p(dirname, prefix = nil) dirname = prefix + File.expand_path(dirname) if prefix $stderr.puts "mkdir -p #{dirname}" if verbose? return if no_harm? # does not check '/'... it's too abnormal case dirs = File.expand_path(dirname).split(%r<(?=/)>) if /\A[a-z]:\z/i =~ dirs[0] disk = dirs.shift dirs[0] = disk + dirs[0] end dirs.each_index do |idx| path = dirs[0..idx].join('') Dir.mkdir path unless File.dir?(path) end end def rm_f(fname) $stderr.puts "rm -f #{fname}" if verbose? return if no_harm? if File.exist?(fname) or File.symlink?(fname) File.chmod 0777, fname File.unlink fname end end def rm_rf(dn) $stderr.puts "rm -rf #{dn}" if verbose? return if no_harm? Dir.chdir dn Dir.foreach('.') do |fn| next if fn == '.' next if fn == '..' if File.dir?(fn) verbose_off { rm_rf fn } else verbose_off { rm_f fn } end end Dir.chdir '..' Dir.rmdir dn end def move_file(src, dest) File.unlink dest if File.exist?(dest) begin File.rename src, dest rescue File.open(dest, 'wb') {|f| f.write File.binread(src) } File.chmod File.stat(src).mode, dest File.unlink src end end def install(from, dest, mode, prefix = nil) $stderr.puts "install #{from} #{dest}" if verbose? return if no_harm? realdest = prefix ? prefix + File.expand_path(dest) : dest realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest) str = File.binread(from) if diff?(str, realdest) verbose_off { rm_f realdest if File.exist?(realdest) } File.open(realdest, 'wb') {|f| f.write str } File.chmod mode, realdest File.open("#{objdir_root()}/InstalledFiles", 'a') {|f| if prefix f.puts realdest.sub(prefix, '') else f.puts realdest end } end end def diff?(new_content, path) return true unless File.exist?(path) new_content != File.binread(path) end def command(str) $stderr.puts str if verbose? system str or raise RuntimeError, "'system #{str}' failed" end def ruby(str) command config('rubyprog') + ' ' + str end def make(task = '') command config('makeprog') + ' ' + task end def extdir?(dir) File.exist?(dir + '/MANIFEST') end def all_files_in(dirname) Dir.open(dirname) {|d| return d.select {|ent| File.file?("#{dirname}/#{ent}") } } end REJECT_DIRS = %w( CVS SCCS RCS CVS.adm .svn ) def all_dirs_in(dirname) Dir.open(dirname) {|d| return d.select {|n| File.dir?("#{dirname}/#{n}") } - %w(. ..) - REJECT_DIRS } end end # # Main Installer # module HookUtils def run_hook(name) try_run_hook "#{curr_srcdir()}/#{name}" or try_run_hook "#{curr_srcdir()}/#{name}.rb" end def try_run_hook(fname) return false unless File.file?(fname) begin instance_eval File.read(fname), fname, 1 rescue setup_rb_error "hook #{fname} failed:\n" + $!.message end true end end module HookScriptAPI def get_config(key) @config[key] end alias config get_config def set_config(key, val) @config[key] = val end # # srcdir/objdir (works only in the package directory) # #abstract srcdir_root #abstract objdir_root #abstract relpath def curr_srcdir "#{srcdir_root()}/#{relpath()}" end def curr_objdir "#{objdir_root()}/#{relpath()}" end def srcfile(path) "#{curr_srcdir()}/#{path}" end def srcexist?(path) File.exist?(srcfile(path)) end def srcdirectory?(path) File.dir?(srcfile(path)) end def srcfile?(path) File.file? srcfile(path) end def srcentries(path = '.') Dir.open("#{curr_srcdir()}/#{path}") {|d| return d.to_a - %w(. ..) } end def srcfiles(path = '.') srcentries(path).select {|fname| File.file?(File.join(curr_srcdir(), path, fname)) } end def srcdirectories(path = '.') srcentries(path).select {|fname| File.dir?(File.join(curr_srcdir(), path, fname)) } end end class ToplevelInstaller Version = '3.3.1' Copyright = 'Copyright (c) 2000-2004 Minero Aoki' TASKS = [ [ 'all', 'do config, setup, then install' ], [ 'config', 'saves your configurations' ], [ 'show', 'shows current configuration' ], [ 'setup', 'compiles ruby extentions and others' ], [ 'install', 'installs files' ], [ 'clean', "does `make clean' for each extention" ], [ 'distclean',"does `make distclean' for each extention" ] ] def ToplevelInstaller.invoke instance().invoke end @singleton = nil def ToplevelInstaller.instance @singleton ||= new(File.dirname($0)) @singleton end include MetaConfigAPI def initialize(ardir_root) @config = nil @options = { 'verbose' => true } @ardir = File.expand_path(ardir_root) end def inspect "#<#{self.class} #{__id__()}>" end def invoke run_metaconfigs case task = parsearg_global() when nil, 'all' @config = load_config('config') parsearg_config init_installers exec_config exec_setup exec_install else @config = load_config(task) __send__ "parsearg_#{task}" init_installers __send__ "exec_#{task}" end end def run_metaconfigs eval_file_ifexist "#{@ardir}/metaconfig" end def load_config(task) case task when 'config' ConfigTable.new when 'clean', 'distclean' if File.exist?(ConfigTable.savefile) then ConfigTable.load else ConfigTable.new end else ConfigTable.load end end def init_installers @installer = Installer.new(@config, @options, @ardir, File.expand_path('.')) end # # Hook Script API bases # def srcdir_root @ardir end def objdir_root '.' end def relpath '.' end # # Option Parsing # def parsearg_global valid_task = /\A(?:#{TASKS.map {|task,desc| task }.join '|'})\z/ while arg = ARGV.shift case arg when /\A\w+\z/ setup_rb_error "invalid task: #{arg}" unless valid_task =~ arg return arg when '-q', '--quiet' @options['verbose'] = false when '--verbose' @options['verbose'] = true when '-h', '--help' print_usage $stdout exit 0 when '-v', '--version' puts "#{File.basename($0)} version #{Version}" exit 0 when '--copyright' puts Copyright exit 0 else setup_rb_error "unknown global option '#{arg}'" end end nil end def parsearg_no_options unless ARGV.empty? setup_rb_error "#{task}: unknown options: #{ARGV.join ' '}" end end alias parsearg_show parsearg_no_options alias parsearg_setup parsearg_no_options alias parsearg_clean parsearg_no_options alias parsearg_distclean parsearg_no_options def parsearg_config re = /\A--(#{ConfigTable.map {|i| i.name }.join('|')})(?:=(.*))?\z/ @options['config-opt'] = [] while i = ARGV.shift if /\A--?\z/ =~ i @options['config-opt'] = ARGV.dup break end m = re.match(i) or setup_rb_error "config: unknown option #{i}" name, value = *m.to_a[1,2] @config[name] = value end end def parsearg_install @options['no-harm'] = false @options['install-prefix'] = '' while a = ARGV.shift case a when /\A--no-harm\z/ @options['no-harm'] = true when /\A--prefix=(.*)\z/ path = $1 path = File.expand_path(path) unless path[0,1] == '/' @options['install-prefix'] = path else setup_rb_error "install: unknown option #{a}" end end end def print_usage(out) out.puts 'Typical Installation Procedure:' out.puts " $ ruby #{File.basename $0} config" out.puts " $ ruby #{File.basename $0} setup" out.puts " # ruby #{File.basename $0} install (may require root privilege)" out.puts out.puts 'Detailed Usage:' out.puts " ruby #{File.basename $0} " out.puts " ruby #{File.basename $0} [] []" fmt = " %-24s %s\n" out.puts out.puts 'Global options:' out.printf fmt, '-q,--quiet', 'suppress message outputs' out.printf fmt, ' --verbose', 'output messages verbosely' out.printf fmt, '-h,--help', 'print this message' out.printf fmt, '-v,--version', 'print version and quit' out.printf fmt, ' --copyright', 'print copyright and quit' out.puts out.puts 'Tasks:' TASKS.each do |name, desc| out.printf fmt, name, desc end fmt = " %-24s %s [%s]\n" out.puts out.puts 'Options for CONFIG or ALL:' ConfigTable.each do |item| out.printf fmt, item.help_opt, item.description, item.help_default end out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's" out.puts out.puts 'Options for INSTALL:' out.printf fmt, '--no-harm', 'only display what to do if given', 'off' out.printf fmt, '--prefix=path', 'install path prefix', '$prefix' out.puts end # # Task Handlers # def exec_config @installer.exec_config @config.save # must be final end def exec_setup @installer.exec_setup end def exec_install @installer.exec_install end def exec_show ConfigTable.each do |i| printf "%-20s %s\n", i.name, i.value end end def exec_clean @installer.exec_clean end def exec_distclean @installer.exec_distclean end end class ToplevelInstallerMulti < ToplevelInstaller include HookUtils include HookScriptAPI include FileOperations def initialize(ardir) super @packages = all_dirs_in("#{@ardir}/packages") raise 'no package exists' if @packages.empty? end def run_metaconfigs eval_file_ifexist "#{@ardir}/metaconfig" @packages.each do |name| eval_file_ifexist "#{@ardir}/packages/#{name}/metaconfig" end end def init_installers @installers = {} @packages.each do |pack| @installers[pack] = Installer.new(@config, @options, "#{@ardir}/packages/#{pack}", "packages/#{pack}") end with = extract_selection(config('with')) without = extract_selection(config('without')) @selected = @installers.keys.select {|name| (with.empty? or with.include?(name)) \ and not without.include?(name) } end def extract_selection(list) a = list.split(/,/) a.each do |name| setup_rb_error "no such package: #{name}" unless @installers.key?(name) end a end def print_usage(f) super f.puts 'Inluded packages:' f.puts ' ' + @packages.sort.join(' ') f.puts end # # multi-package metaconfig API # attr_reader :packages def declare_packages(list) raise 'package list is empty' if list.empty? list.each do |name| raise "directory packages/#{name} does not exist"\ unless File.dir?("#{@ardir}/packages/#{name}") end @packages = list end # # Task Handlers # def exec_config run_hook 'pre-config' each_selected_installers {|inst| inst.exec_config } run_hook 'post-config' @config.save # must be final end def exec_setup run_hook 'pre-setup' each_selected_installers {|inst| inst.exec_setup } run_hook 'post-setup' end def exec_install run_hook 'pre-install' each_selected_installers {|inst| inst.exec_install } run_hook 'post-install' end def exec_clean rm_f ConfigTable.savefile run_hook 'pre-clean' each_selected_installers {|inst| inst.exec_clean } run_hook 'post-clean' end def exec_distclean rm_f ConfigTable.savefile run_hook 'pre-distclean' each_selected_installers {|inst| inst.exec_distclean } run_hook 'post-distclean' end # # lib # def each_selected_installers Dir.mkdir 'packages' unless File.dir?('packages') @selected.each do |pack| $stderr.puts "Processing the package `#{pack}' ..." if @options['verbose'] Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}") Dir.chdir "packages/#{pack}" yield @installers[pack] Dir.chdir '../..' end end def verbose? @options['verbose'] end def no_harm? @options['no-harm'] end end class Installer FILETYPES = %w( bin lib ext data ) include HookScriptAPI include HookUtils include FileOperations def initialize(config, opt, srcroot, objroot) @config = config @options = opt @srcdir = File.expand_path(srcroot) @objdir = File.expand_path(objroot) @currdir = '.' end def inspect "#<#{self.class} #{File.basename(@srcdir)}>" end # # Hook Script API base methods # def srcdir_root @srcdir end def objdir_root @objdir end def relpath @currdir end # # configs/options # def no_harm? @options['no-harm'] end def verbose? @options['verbose'] end def verbose_off begin save, @options['verbose'] = @options['verbose'], false yield ensure @options['verbose'] = save end end # # TASK config # def exec_config exec_task_traverse 'config' end def config_dir_bin(rel) end def config_dir_lib(rel) end def config_dir_ext(rel) extconf if extdir?(curr_srcdir()) end def extconf opt = @options['config-opt'].join(' ') command "#{config('rubyprog')} \"#{curr_srcdir()}/extconf.rb\" #{opt}" end def config_dir_data(rel) end # # TASK setup # def exec_setup exec_task_traverse 'setup' end def setup_dir_bin(rel) all_files_in(curr_srcdir()).each do |fname| adjust_shebang "#{curr_srcdir()}/#{fname}" end end def adjust_shebang(path) return if no_harm? tmpfile = File.basename(path) + '.tmp' begin File.open(path, 'rb') {|r| first = r.gets return unless File.basename(config('rubypath')) == 'ruby' return unless File.basename(first.sub(/\A\#!/, '').split[0]) == 'ruby' $stderr.puts "adjusting shebang: #{File.basename(path)}" if verbose? File.open(tmpfile, 'wb') {|w| w.print first.sub(/\A\#!\s*\S+/, '#! ' + config('rubypath')) w.write r.read } move_file tmpfile, File.basename(path) } ensure File.unlink tmpfile if File.exist?(tmpfile) end end def setup_dir_lib(rel) end def setup_dir_ext(rel) make if extdir?(curr_srcdir()) end def setup_dir_data(rel) end # # TASK install # def exec_install rm_f 'InstalledFiles' exec_task_traverse 'install' end def install_dir_bin(rel) install_files collect_filenames_auto(), "#{config('bindir')}/#{rel}", 0755 end def install_dir_lib(rel) install_files ruby_scripts(), "#{config('rbdir')}/#{rel}", 0644 end def install_dir_ext(rel) return unless extdir?(curr_srcdir()) install_files ruby_extentions('.'), "#{config('sodir')}/#{File.dirname(rel)}", 0555 end def install_dir_data(rel) install_files collect_filenames_auto(), "#{config('datadir')}/#{rel}", 0644 end def install_files(list, dest, mode) mkdir_p dest, @options['install-prefix'] list.each do |fname| install fname, dest, mode, @options['install-prefix'] end end def ruby_scripts collect_filenames_auto().select {|n| /\.rb\z/ =~ n } end # picked up many entries from cvs-1.11.1/src/ignore.c reject_patterns = %w( core RCSLOG tags TAGS .make.state .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb *~ *.old *.bak *.BAK *.orig *.rej _$* *$ *.org *.in .* ) mapping = { '.' => '\.', '$' => '\$', '#' => '\#', '*' => '.*' } REJECT_PATTERNS = Regexp.new('\A(?:' + reject_patterns.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| mapping[ch] } }.join('|') + ')\z') def collect_filenames_auto mapdir((existfiles() - hookfiles()).reject {|fname| REJECT_PATTERNS =~ fname }) end def existfiles all_files_in(curr_srcdir()) | all_files_in('.') end def hookfiles %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt| %w( config setup install clean ).map {|t| sprintf(fmt, t) } }.flatten end def mapdir(filelist) filelist.map {|fname| if File.exist?(fname) # objdir fname else # srcdir File.join(curr_srcdir(), fname) end } end def ruby_extentions(dir) Dir.open(dir) {|d| ents = d.select {|fname| /\.#{::Config::CONFIG['DLEXT']}\z/ =~ fname } if ents.empty? setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first" end return ents } end # # TASK clean # def exec_clean exec_task_traverse 'clean' rm_f ConfigTable.savefile rm_f 'InstalledFiles' end def clean_dir_bin(rel) end def clean_dir_lib(rel) end def clean_dir_ext(rel) return unless extdir?(curr_srcdir()) make 'clean' if File.file?('Makefile') end def clean_dir_data(rel) end # # TASK distclean # def exec_distclean exec_task_traverse 'distclean' rm_f ConfigTable.savefile rm_f 'InstalledFiles' end def distclean_dir_bin(rel) end def distclean_dir_lib(rel) end def distclean_dir_ext(rel) return unless extdir?(curr_srcdir()) make 'distclean' if File.file?('Makefile') end # # lib # def exec_task_traverse(task) run_hook "pre-#{task}" FILETYPES.each do |type| if config('without-ext') == 'yes' and type == 'ext' $stderr.puts 'skipping ext/* by user option' if verbose? next end traverse task, type, "#{task}_dir_#{type}" end run_hook "post-#{task}" end def traverse(task, rel, mid) dive_into(rel) { run_hook "pre-#{task}" __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '') all_dirs_in(curr_srcdir()).each do |d| traverse task, "#{rel}/#{d}", mid end run_hook "post-#{task}" } end def dive_into(rel) return unless File.dir?("#{@srcdir}/#{rel}") dir = File.basename(rel) Dir.mkdir dir unless File.dir?(dir) prevdir = Dir.pwd Dir.chdir dir $stderr.puts '---> ' + rel if verbose? @currdir = rel yield Dir.chdir prevdir $stderr.puts '<--- ' + rel if verbose? @currdir = File.dirname(rel) end end if $0 == __FILE__ begin if multipackage_install? ToplevelInstallerMulti.invoke else ToplevelInstaller.invoke end rescue SetupError raise if $DEBUG $stderr.puts $!.message $stderr.puts "Try 'ruby #{$0} --help' for detailed usage." exit 1 end end rjb-1.4.8/data/0000755000175000017500000000000012161443611012235 5ustar lunarlunarrjb-1.4.8/data/rjb/0000755000175000017500000000000012161443611013012 5ustar lunarlunarrjb-1.4.8/data/rjb/jp/0000755000175000017500000000000012161443611013423 5ustar lunarlunarrjb-1.4.8/data/rjb/jp/co/0000755000175000017500000000000012161443611014024 5ustar lunarlunarrjb-1.4.8/data/rjb/jp/co/infoseek/0000755000175000017500000000000012161443611015627 5ustar lunarlunarrjb-1.4.8/data/rjb/jp/co/infoseek/hp/0000755000175000017500000000000012161443611016236 5ustar lunarlunarrjb-1.4.8/data/rjb/jp/co/infoseek/hp/arton/0000755000175000017500000000000012161443611017361 5ustar lunarlunarrjb-1.4.8/data/rjb/jp/co/infoseek/hp/arton/rjb/0000755000175000017500000000000012161443611020136 5ustar lunarlunarrjb-1.4.8/lib/0000755000175000017500000000000012161443611012072 5ustar lunarlunarrjb-1.4.8/lib/rjb/0000755000175000017500000000000012161443611012647 5ustar lunarlunarrjb-1.4.8/lib/rjb/extension.rb0000644000175000017500000000710412161443611015212 0ustar lunarlunar=begin Copyright(c) 2010 arton This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. $Id: rjbextension.rb 147 2010-10-23 05:10:33Z arton $ This file is from Andreas Ronge project neo4j http://github.com/andreasronge/neo4j/blob/rjb/lib/rjb_ext.rb Copyright (c) 2008 Andreas Ronge Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. =end # Loads the JVM with the given classpath and arguments to the jre. # All needed .jars should be included in classpath. module Kernel alias rjb_original_require require def require(path) rjb_original_require(path) rescue LoadError # check that it's not a jar file raise unless path =~ /\.jar/ # This will maybe use the wrong jar file from a previous version of the GEM # puts "LOAD PATH #{$LOAD_PATH}" found_path = $LOAD_PATH.reverse.find{|p| File.exist?(File.join(p,path))} raise unless found_path abs_path = File.join(found_path, path) # check that the file exists raise unless File.exist?(abs_path) # try to load it using RJB if Rjb::loaded? Rjb::add_jar abs_path else Rjb::add_classpath abs_path end end def load_jvm(jargs = []) return if Rjb::loaded? classpath = ENV['CLASSPATH'] ||= '' Rjb::load(classpath, jargs) end end class JavaPackage def initialize(pack_name, parent_pack = nil) @pack_name = pack_name @parent_pack = parent_pack @cache = {} end def method_missing(m, *args) # return if possible old module/class @cache[m] ||= create_package_or_class(m) end def create_package_or_class(m) method = m.to_s if class?(method) Rjb::import("#{self}.#{method}") else JavaPackage.new(method, self) end end def to_s if @parent_pack "#{@parent_pack.to_s}.#@pack_name" else "#@pack_name" end end def class?(a) first_letter = a[0,1] first_letter >= 'A' && first_letter <= 'Z' end @@cache = {} def self.new(pack_name, parent_pack = nil) @@cache[pack_name] ||= super end end module RjbConf # make them as singleton ORG = JavaPackage.new('org') JAVA = JavaPackage.new('java') end def org RjbConf::ORG end def java RjbConf::JAVA end rjb-1.4.8/lib/rjb/list.rb0000644000175000017500000000120412161443611014144 0ustar lunarlunar# encoding: utf-8 =begin Copyright(c) 2012 arton =end require 'rjb' module Rjb JIterable = import('java.lang.Iterable') JIterator = import('java.util.Iterator') module Iterable def each it = iterator while it.has_next yield it.next end end end module Iterator def each while has_next yield self.next end end end class Rjb_JavaProxy def initialize_proxy if JIterable.isInstance(self) include Iterable include Enumerable elsif JIterator.isInstance(self) include Iterator include Enumerable end end end end rjb-1.4.8/lib/rjb.rb0000755000175000017500000000537212161443611013206 0ustar lunarlunar=begin Copyright(c) 2006-2010,2012 arton =end require 'rbconfig' module RjbConf if /darwin/ =~ RUBY_PLATFORM if ENV['JVM_LIB'].nil? || ENV['JVM_LIB'] == '' if ENV['JAVA_HOME'].nil? || ENV['JAVA_HOME'] == '' jvms = Dir.glob("#{`/usr/libexec/java_home`.strip}/**/libjvm.dylib") else jvms = Dir.glob("#{ENV['JAVA_HOME']}/**/libjvm.dylib") end if jvms.size > 0 ENV['JVM_LIB'] = jvms[0] end end end dir = File.join(File.dirname(File.dirname(__FILE__)), 'data') if File.exist?(dir) datadir = dir else datadir = RbConfig::CONFIG['datadir'] end BRIDGE_FILE = File.join(datadir, 'rjb', 'jp', 'co', 'infoseek', 'hp', 'arton', 'rjb', 'RBridge.class') unless File.exist?(BRIDGE_FILE) raise 'bridge file not found' end end require 'rjbcore' module Rjb module MODIFIER def self.STATIC 8 end def self.PUBLIC 1 end end module JMethod def instance_method?(m) m.modifiers & MODIFIER.STATIC == 0 end def public_method?(m) (m.modifiers & MODIFIER.PUBLIC) == MODIFIER.PUBLIC end def jmethods(org, klass, &blk) (org + klass.getMethods.select do |m| blk.call(m) end.map do |m| m.name end).uniq end def format_sigs(s) if s.size < 0 '' elsif s.size == 1 s[0] else "[#{s.map{|m|m.nil? ? 'void' : m}.join(', ')}]" end end end class Rjb_JavaClass include JMethod def public_methods(inh = true) jmethods(super(inh), self) do |m| !instance_method?(m) && public_method?(m) end end def methods(inh = true) jmethods(super(inh), self) do |m| !instance_method?(m) && public_method?(m) end end def java_methods jmethods([], self) do |m| !instance_method?(m) && public_method?(m) end.map do |m| "#{m}(#{format_sigs(self.static_sigs(m))})" end end end class Rjb_JavaProxy include JMethod def initialize_proxy end def public_methods(inh = true) jmethods(super(inh), getClass) do |m| instance_method?(m) && public_method?(m) end end def methods(inh = true) jmethods(super(inh), getClass) do |m| instance_method?(m) && public_method?(m) end end def java_methods jmethods([], getClass) do |m| instance_method?(m) && public_method?(m) end.map do |m| "#{m}(#{format_sigs(getClass.sigs(m))})" end end end class Rjb_JavaBridge def method_missing(name, *args) @wrapped.__send__(name, *args) end def respond_to?(name, inc_private = false) @wrapped.respond_to?(name, inc_private) end attr_reader :wrapped end end rjb-1.4.8/lib/rjbextension.rb0000644000175000017500000000003112161443611015123 0ustar lunarlunarrequire 'rjb/extension' rjb-1.4.8/samples/0000755000175000017500000000000012161443611012770 5ustar lunarlunarrjb-1.4.8/samples/filechooser.rb0000644000175000017500000000111612161443611015616 0ustar lunarlunar#!/usr/local/bin/ruby -Ks #coding: cp932 require 'rjb' Rjb::load unless RUBY_VERSION =~ /^1\.9/ class String def encode(s) self end end end class FileChooser @@klass = Rjb::import('javax.swing.JFileChooser') def initialize(ext = '*', desc = 'any files') @selected = nil end def show() chooser = @@klass.new if chooser.showOpenDialog(nil) == @@klass.APPROVE_OPTION @selected = chooser.getSelectedFile end end attr_reader :selected end f = FileChooser.new if f.show puts f.selected.getAbsolutePath.encode('cp932') end puts 'bye' rjb-1.4.8/samples/unzip.rb0000644000175000017500000000230012161443611014455 0ustar lunarlunarrequire 'rjb' if Rjb::VERSION < '1.3.4' $stderr.puts "require rjb-1.3.4 or later, bye." exit 1 end class ZipFile include Enumerable Zip = Rjb::import('java.util.zip.ZipFile') def initialize(file, &block) @zipfile = Zip.new(file) if block yield self @zipfile.close end end def close @zipfile.close end def each(&block) unless block Enumerator.new(self) else e = @zipfile.entries while e.has_more_elements yield e.next_element end end end def size @zipfile.size end def unzip(ent) if String === ent ent = @zipfile.entry(ent) end is = @zipfile.input_stream(ent) buff = "\0" * 4096 File.open(ent.name, 'wb') do |fout| loop do len = is.read(buff, 0, buff.size) break if len < 0 fout.write(buff[0, len]) end is.close end end end if __FILE__ == $0 if ARGV.size == 0 puts 'usage: ruby unzip.rb filename' else ARGV.each do |file| ZipFile.new(file) do |zip| zip.each do |f| puts "#{f.name}, #{f.size}" unless f.directory? zip.unzip(f) end end end end end end rjb-1.4.8/pre-install.rb0000644000175000017500000000030512161443611014101 0ustar lunarlunar=begin Copyright (c) 2006 arton =end require 'rbconfig' if File.exist?(File.join(Config::CONFIG['sitearchdir'], 'rjb.so')) File.delete(File.join(Config::CONFIG['sitearchdir'], 'rjb.so')) end rjb-1.4.8/test/0000755000175000017500000000000012161443611012303 5ustar lunarlunarrjb-1.4.8/test/readme.txt0000644000175000017500000000040512161443611014300 0ustar lunarlunarhow to run the test you should set lD_LIBRARY_PATH environment variable to point the JVM. for example) If you use Linux Sun Java2 Standard Edition, export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$JAVA_HOME/jre/lib/i386:$JAVA_HOME/jre/lib/i386/client ruby test.rb rjb-1.4.8/test/osx_jvmcheck.rb0000644000175000017500000000031012161443611015305 0ustar lunarlunar# coding: utf-8 begin require 'rjb' rescue LoadError require 'rubygems' require 'rjb' end S = Rjb::import('java.lang.System') puts "#{S.property('java.vendor')} #{S.property('java.version')}" rjb-1.4.8/test/JarTest2.java0000755000175000017500000000026712161443611014614 0ustar lunarlunarpackage jp.co.infoseek.hp.arton.rjb; public class JarTest2 extends JarTest { public String add(String a, String b) { return super.add(a, b) + " extended"; } } rjb-1.4.8/test/jartest2.rb0000644000175000017500000000066712161443611014377 0ustar lunarlunar#!/usr/local/env ruby -Ku # encoding: utf-8 begin require 'rjb' rescue LoadError require 'rubygems' require 'rjb' end require 'test/unit' class JarTest < Test::Unit::TestCase include Rjb def setup Rjb::load() end def test_depends add_jar([File.expand_path('./jartest2.jar'), File.expand_path('./jartest.jar')]) assert Rjb::import('jp.co.infoseek.hp.arton.rjb.JarTest2') end end rjb-1.4.8/test/test.rb0000755000175000017500000006474512161443611013632 0ustar lunarlunar#!/usr/local/env ruby -Ku # encoding: utf-8 # $Id: test.rb 199 2012-12-17 13:31:18Z arton $ begin require 'rjb' rescue LoadError require 'rubygems' require 'rjb' end require 'test/unit' require 'fileutils' FileUtils.rm_f 'jp/co/infoseek/hp/arton/rjb/Base.class' FileUtils.rm_f 'jp/co/infoseek/hp/arton/rjb/ExtBase.class' puts "start RJB(#{Rjb::VERSION}) test" class TestRjb < Test::Unit::TestCase include Rjb def setup Rjb::load('.') Rjb::add_jar(File.expand_path('rjbtest.jar')) Rjb::primitive_conversion = false @jString = import('java.lang.String') @jInteger = import('java.lang.Integer') @jShort = import('java.lang.Short') @jDouble = import('java.lang.Double') @jFloat = import('java.lang.Float') @jBoolean = import('java.lang.Boolean') @jByte = import('java.lang.Byte') @jLong = import('java.lang.Long') @jChar = import('java.lang.Character') end def teardown end def test_metaclass cls = import('java.lang.Class') assert_equal('java.lang.Class', cls._classname) assert_equal('java.lang.Class', cls.getName) assert_equal(17, cls.getModifiers) end def test_scalar assert_equal('java.lang.Class', @jString._classname) assert_equal('class java.lang.String', @jString.toString) str = @jString.new assert_equal('java.lang.String', str._classname) assert_equal(0, str.length) assert_equal('', str.toString) str = @jString.new_with_sig('Ljava.lang.String;', "abcde") # result integer assert_equal(5, str.length) # result string assert_equal('abcde', str.toString) # argument test # char assert_equal('abxde', str.replace("c".sum, "x".sum)) # string assert_equal('abdxe', str.replaceAll('cd', 'dx')) # int assert_equal('bc', str.substring(1, 3)) assert_equal('e', str.substring(4)) # float with static assert_equal('5.23', @jString._invoke('valueOf', 'F', 5.23)) assert_equal('25.233', @jString._invoke('valueOf', 'D', 25.233)) # rjb object (String) str2 = @jString.new_with_sig('Ljava.lang.String;', 'fghijk') assert_equal('abcdefghijk', str.concat(str2)) # rjb object other (implicit toString call is Rjb feature) i = @jInteger.new_with_sig('I', 35901) assert_equal('abcde35901', str.concat(i)) # result boolean and argument is rjb object assert_equal(false, i.equals(str)) assert_equal(false, str.equals(i)) assert_equal(true, str.equals("abcde")) assert_equal(true, str.equals(str)) # long l = @jLong.new_with_sig('J', -9223372036854775808) assert_equal(-9223372036854775808, l.longValue) l = @jLong.new_with_sig('J', 9223372036854775807) assert_equal(9223372036854775807, l.longValue) # double d = @jDouble.new_with_sig('D', 1234.5678901234567890) assert_equal(1234.5678901234567890, d.doubleValue) # byte b = @jByte.new_with_sig('B', 13) assert_equal(13, b.byteValue) # float f = @jFloat.new_with_sig('F', 13.5) assert_equal(13.5, f.floatValue) # short s = @jShort.new_with_sig('S', 1532) assert_equal(1532, s.shortValue) c = @jChar.new_with_sig('C', "A".sum) assert_equal("A".sum, c.charValue) end def test_array str = @jString.new_with_sig('[C', ["a".sum, "b".sum, "c".sum, "d".sum, "e".sum, "c".sum, "f".sum, "c".sum, "g".sum]) assert_equal('abcdecfcg', str.toString) # conv string array splt = str.split('c') assert(Array === splt) assert_equal(4, splt.size) assert_equal('ab', splt[0]) assert_equal('g', splt[3]) # conv byte array to (ruby)string ba = str.getBytes assert_equal('abcdecfcg', ba) # conv char array to array(int) ca = str.toCharArray assert_equal(["a".sum, "b".sum, "c".sum, "d".sum, "e".sum, "c".sum, "f".sum, "c".sum, "g".sum], ca) end def test_importobj() sys = import('java.lang.System') props = sys.getProperties assert_equal('java.util.Properties', props._classname) if /cygwin/ =~ RUBY_PLATFORM # patch for dirty environment assert_equal(Dir::pwd, %x[cygpath -u #{props.getProperty('user.dir').gsub('\\', '/')}].chop) else assert_equal(Dir::pwd, props.getProperty('user.dir').gsub('\\', '/')) end assert_equal(@jBoolean.valueOf(true).booleanValue(), true) assert_equal(@jBoolean.valueOf(false).booleanValue(), false) assert_equal(@jBoolean.valueOf('true').booleanValue(), true) assert_equal(@jBoolean.valueOf('false').booleanValue(), false) end def test_importobjarray() jarray = import('java.util.ArrayList') a = jarray.new() a.add(@jInteger.new_with_sig('I', 1)) a.add(@jInteger.new_with_sig('I', 2)) a.add(@jInteger.new_with_sig('I', 3)) oa = a.toArray assert_equal(3, oa.size) assert_equal(1, oa[0].intValue) assert_equal(2, oa[1].intValue) assert_equal(3, oa[2].intValue) end def test_kjconv() if Object::const_defined?(:Encoding) test = import('jp.co.infoseek.hp.arton.rjb.Test').new euc_kj = "\xb4\xc1\xbb\xfa\xa5\xc6\xa5\xad\xa5\xb9\xa5\xc8".force_encoding Encoding::EUC_JP s = @jString.new(euc_kj) assert_equal(s.toString().encoding, Encoding::UTF_8) assert(test.isSameString(s)) assert(test.isSameString(euc_kj)) assert_equal(s.toString().encode(Encoding::EUC_JP), euc_kj) sjis_kj = "\x8a\xbf\x8e\x9a\x83\x65\x83\x4c\x83\x58\x83\x67".force_encoding Encoding::SHIFT_JIS s = @jString.new(sjis_kj) assert_equal(s.toString().encoding, Encoding::UTF_8) assert(test.isSameString(s)) assert(test.isSameString(sjis_kj)) assert_equal(s.toString().encode(Encoding::SHIFT_JIS), sjis_kj) utf8_kj = "\xE6\xBC\xA2\xE5\xAD\x97\xE3\x83\x86\xE3\x82\xAD\xE3\x82\xB9\xE3\x83\x88".force_encoding Encoding::UTF_8 s = @jString.new(utf8_kj) assert_equal(s.toString().encoding, Encoding::UTF_8) assert(test.isSameString(s)) assert(test.isSameString(utf8_kj)) assert_equal(s.toString().encode(Encoding::UTF_8), utf8_kj) iso2022jp_kj = "\x1b\x24\x42\x34\x41\x3b\x7a\x25\x46\x25\x2d\x25\x39\x25\x48\x1b\x28\x42".force_encoding Encoding::ISO_2022_JP s = @jString.new(iso2022jp_kj) assert_equal(s.toString().encoding, Encoding::UTF_8) assert(test.isSameString(s)) assert(test.isSameString(iso2022jp_kj)) assert_equal(s.toString().encode(Encoding::ISO_2022_JP), iso2022jp_kj) assert_equal(@jString.new("abcdef".force_encoding(Encoding::ASCII_8BIT)).toString(), "abcdef") assert_equal(@jString.new("abcdef".force_encoding(Encoding::find("us-ascii"))).toString(), "abcdef") else default_kcode = $KCODE begin $KCODE = 'euc' euc_kj = "\xb4\xc1\xbb\xfa\xa5\xc6\xa5\xad\xa5\xb9\xa5\xc8" s = @jString.new(euc_kj) assert_equal(s.toString(), euc_kj) $KCODE = 'sjis' sjis_kj = "\x8a\xbf\x8e\x9a\x83\x65\x83\x4c\x83\x58\x83\x67" s = @jString.new(sjis_kj) assert_equal(s.toString(), sjis_kj) $KCODE = 'utf8' utf8_kj = "\xE6\xBC\xA2\xE5\xAD\x97\xE3\x83\x86\xE3\x82\xAD\xE3\x82\xB9\xE3\x83\x88" s = @jString.new(utf8_kj) assert_equal(s.toString(), utf8_kj) $KCODE = 'none' if /mswin(?!ce)|mingw|cygwin|bccwin/ =~ RUBY_PLATFORM #expecting shift_jis on windows none_kj = "\x8a\xbf\x8e\x9a\x83\x65\x83\x4c\x83\x58\x83\x67" else #expecting utf-8 unless windows none_kj = "\xE6\xBC\xA2\xE5\xAD\x97\xE3\x83\x86\xE3\x82\xAD\xE3\x82\xB9\xE3\x83\x88" end s = @jString.new(none_kj) assert_equal(s.toString(), none_kj) $KCODE = 'utf8' utf8_kj = "\xE6\xBC\xA2\xE5\xAD\x97\xE3\x83\x86\xE3\x82\xAD\xE3\x82\xB9\xE3\x83\x88" s = @jString.new(utf8_kj) assert_equal(s.toString(), utf8_kj) $KCODE = 'sjis' sjis_kj = "\x8a\xbf\x8e\x9a\x83\x65\x83\x4c\x83\x58\x83\x67" s = @jString.new(sjis_kj) assert_equal(s.toString(), sjis_kj) $KCODE = 'euc' euc_kj = "\xb4\xc1\xbb\xfa\xa5\xc6\xa5\xad\xa5\xb9\xa5\xc8" s = @jString.new(euc_kj) assert_equal(s.toString(), euc_kj) ensure $KCODE = default_kcode end end end def test_combination_charcters teststr = "\xc7\x96\xc3\xbc\xcc\x84\x75\xcc\x88\xcc\x84\xed\xa1\xa9\xed\xba\xb2\xe3\x81\x8b\xe3\x82\x9a" test = import('jp.co.infoseek.hp.arton.rjb.Test').new s = test.getUmlaut() if Object::const_defined?(:Encoding) #>=1.9 teststr = teststr.force_encoding(Encoding::UTF_8) assert_equal(s, teststr) else default_kcode = $KCODE begin $KCODE = "utf8" assert_equal(s, teststr) ensure $KCODE = default_kcode end end end def test_constants() assert_equal(0x7fffffffffffffff, @jLong.MAX_VALUE) assert_equal(-9223372036854775808, @jLong.MIN_VALUE) end class TestIter def initialize() @i = 5 end def hasNext() @i > 0 end def next() @i -= 1 @i.to_s end end def test_newobject() it = TestIter.new it = bind(it, 'java.util.Iterator') test = import('jp.co.infoseek.hp.arton.rjb.Test') a = test.new assert_equal("43210", a.concat(it)) end def test_unbind() it = TestIter.new it = bind(it, 'java.util.Iterator') assert_equal(it, unbind(it)) end class TestComparator def compare(o1, o2) o1.to_i - o2.to_i end def equals(o) o == self end end def test_comparator cp = TestComparator.new cp = bind(cp, 'java.util.Comparator') test = import('jp.co.infoseek.hp.arton.rjb.Test') a = test.new assert_equal(0, a.check(cp, 123, 123)) assert_equal(5, a.check(cp, 81, 76)) assert_equal(-5, a.check(cp, 76, 81)) end # assert_raise is useless in this test, because NumberFormatException may be defined in # its block. def test_exception() begin @jInteger.parseInt('blabla') flunk('no exception') rescue NumberFormatException => e assert_nil(e.cause) # OK end end class TestIterator def initialize(tp) @type = tp end def hasNext() true end def next() if @type == 0 Rjb::throw('java.util.NoSuchElementException', 'test exception') elsif @type == 1 Rjb::throw(Rjb::import('java.util.NoSuchElementException').new('instance test')) end end end def test_throw() it = TestIterator.new(0) it = bind(it, 'java.util.Iterator') test = import('jp.co.infoseek.hp.arton.rjb.Test') a = test.new begin a.concat(it) flunk('no exception') rescue NoSuchElementException => e assert_equal('test exception', e.message) end end def test_instance_throw() it = TestIterator.new(1) it = bind(it, 'java.util.Iterator') test = import('jp.co.infoseek.hp.arton.rjb.Test') a = test.new begin a.concat(it) flunk('no exception') rescue NoSuchElementException => e assert_equal('instance test', e.message) end end def test_null_string() sys = import('java.lang.System') begin sys.getProperty(nil) flunk('no exception') rescue NullPointerException => e assert(true) rescue RuntimeError => e flunk(e.message) end end def test_throw_error() begin throw(self) flunk('no exception') rescue TypeError => e end begin throw(@jString.new('a')) flunk('no exception') rescue RuntimeError => e assert_equal('arg1 must be a throwable', e.message) end begin throw('java.lang.NoSuchException', 'test') flunk('no excpetion') rescue RuntimeError => e assert_equal("`java.lang.NoSuchException' not found", e.message) end end def test_throw_clear() assert_nothing_raised { begin Rjb::throw('java.util.NoSuchElementException', 'test exception') rescue #drop ruby exception end test = import('jp.co.infoseek.hp.arton.rjb.Test') begin Rjb::throw('java.util.NoSuchElementException', 'test exception') rescue #drop ruby exception end test.new begin Rjb::throw('java.util.NoSuchElementException', 'test exception') rescue #drop ruby exception end @jString.new_with_sig('Ljava.lang.String;', "abcde") begin Rjb::throw('java.util.NoSuchElementException', 'test exception') rescue #drop ruby exception end it = TestIterator.new(0) it = bind(it, 'java.util.Iterator') begin Rjb::throw('java.util.NoSuchElementException', 'test exception') rescue NoSuchElementException end begin Rjb::throw('java.lang.IllegalAccessException', 'test exception') rescue IllegalAccessException end unbind(it) } end def test_field() test = import('jp.co.infoseek.hp.arton.rjb.Test').new assert_equal('Hello World !!', test.helloData) test.helloData = 'Goodby World !' assert_equal('Goodby World !', test.helloData) end def test_instancemethod_from_class() begin assert_equal('true', @jString.valueOf(true)) @jString.length flunk('no exception') rescue RuntimeError => e assert_equal('instance method `length\' for class', e.message) end end def test_instancefield_from_class() point = import('java.awt.Point') begin point.x flunk('no exception') rescue RuntimeError => e assert_equal('instance field `x\' for class', e.message) end begin point.x = 30 rescue RuntimeError => e assert_equal('instance field `x\' for class', e.message) end end def test_static_derived_method() ext = import('jp.co.infoseek.hp.arton.rjb.ExtBase') assert_equal("sVal", ext.getSVal) end def test_capitalized_method() bs = import('jp.co.infoseek.hp.arton.rjb.Base') assert_equal("val", bs.val) assert_equal("Val", bs.Val) end def test_underscored_constant() bs = import('jp.co.infoseek.hp.arton.rjb.Base') assert_equal(5, bs._NUMBER_FIVE) end def test_passingclass() ibs = import('jp.co.infoseek.hp.arton.rjb.IBase') bs = import('jp.co.infoseek.hp.arton.rjb.Base') assert_equal('interface jp.co.infoseek.hp.arton.rjb.IBase', bs.intf(ibs)) end def test_fornamehook() # j2se class cls = import('java.lang.Class') c = cls.forName('java.lang.Class') assert_equal(cls, c) # user class bs = import('jp.co.infoseek.hp.arton.rjb.Base') b = cls.forName('jp.co.infoseek.hp.arton.rjb.Base') assert_equal(bs, b) # check class that was loaded from classpath loader = Rjb::import('java.lang.ClassLoader') b = cls.forName('jp.co.infoseek.hp.arton.rjb.IBase', true, loader.getSystemClassLoader) assert(b.isInterface) end def test_send_array_of_arrays() test = import('jp.co.infoseek.hp.arton.rjb.Test').new a = test.joinStringArray([['ab', 'cd'], ['ef', 'gh']]) assert_equal(['ab', 'cd', 'ef', 'gh'], a) a = test.joinIntArray([[1, 2, 3], [4, 5, 6]]) a.collect! {|e| e.intValue } assert_equal([1, 2, 3, 4, 5, 6], a) r = [[[ 1, 2], [2, 3] ], [[ 3, 4], [5, 6]], [[7, 8], [1, 3]]] a = test.throughIntArray(r) assert_equal(a, r) end def test_import_and_instanciate() b = import('jp.co.infoseek.hp.arton.rjb.Base') assert_equal('hello', b.new.getInstanceVar()) end def test_array_of_arrays() jversion = import('java.lang.System').getProperty('java.version') if /^1\.5/ =~ jversion method = import('java.lang.reflect.Method') end test = import('jp.co.infoseek.hp.arton.rjb.Test').new a = test.getStringArrayOfArrays() assert_equal("abc", a[0][0]) assert_equal("def", a[0][1]) assert_equal("123", a[1][0]) assert_equal("456", a[1][1]) ints = test.getIntArrayOfArrays() assert_equal(2, ints.size ) assert_equal([1,2,3], ints[0] ) assert_equal([[1,2,3],[4,5,6]], ints ) sized = test.getSizedArray() assert_equal("find me",sized[0][1][2][3]) mixed = test.getMixedArray() assert_equal(12,mixed[0][0][0].intValue) assert_equal("another string",mixed[1][0][1].toString) assert_equal([],mixed[2]) end def test_CastObjectArray() test = import('jp.co.infoseek.hp.arton.rjb.Test').new a = test.getObjectArray() assert_equal(1, a[0].intValue) assert_equal('Hello World !', a[1].toString) a = test.getObjectArrayOfArray() assert_equal(1, a[0][0].intValue) assert_equal('Hello World !', a[0][1].toString) assert_equal(2, a[1][0].intValue) assert_equal('Hello World !!', a[1][1].toString) end def test_CallByNullForArrays() test = import('jp.co.infoseek.hp.arton.rjb.Test').new assert_equal(nil, test.callWithArrays(nil, nil, nil, nil, nil, nil, nil, nil)) end def test_failed_constructor_call() begin s = @jString.new('a', 'b', 'c') flunk('no exception') rescue RuntimeError => e assert(e) end end def test_rubyize loader = Rjb::import('java.lang.ClassLoader') cls = import('java.lang.Class') b = cls.for_name('jp.co.infoseek.hp.arton.rjb.IBase', true, loader.system_class_loader) assert(b.interface?) stringbuffer = Rjb::import('java.lang.StringBuffer') sb = stringbuffer.new('abc') assert_equal(1, sb.index_of('bc')) sb.set_char_at(1, "B".sum) assert_equal('aBc', sb.to_string) sb.length = 2 assert_equal('aB', sb.to_string) end def test_auto_conv assert_equal(false, Rjb::primitive_conversion) Rjb::primitive_conversion = true assert_equal(true, Rjb::primitive_conversion) assert_equal(1, @jInteger.valueOf('1')) assert_equal(-1, @jInteger.valueOf('-1')) assert_equal(2, @jShort.valueOf('2')) assert_equal(-2, @jShort.valueOf('-2')) assert_equal(3.1, @jDouble.valueOf('3.1')) assert_equal(4.5, @jFloat.valueOf('4.5')) assert(@jBoolean.TRUE) assert_equal(5, @jByte.valueOf('5')) assert_equal(-6, @jByte.valueOf('-6')) assert_equal(0x7000000000000000, @jLong.valueOf('8070450532247928832')) assert_equal(-9223372036854775807, @jLong.valueOf('-9223372036854775807')) assert_equal("A".sum, @jChar.valueOf("A".sum)) end def test_obj_to_primitive ar = Rjb::import('java.util.ArrayList') a = ar.new a.add @jString.new('abcdef') a.add @jInteger.valueOf('1') a.add @jShort.valueOf('2') a.add @jDouble.valueOf('3.1') a.add @jFloat.valueOf('4.5') a.add @jBoolean.TRUE a.add @jByte.valueOf('5') a.add @jLong.valueOf('8070450532247928832') a.add @jChar.valueOf("A".sum) Rjb::primitive_conversion = true assert_equal 'abcdef', a.get(0) assert_equal 1, a.get(1) assert_equal 2, a.get(2) assert_equal 3.1, a.get(3) assert_equal 4.5, a.get(4) assert a.get(5) assert_equal 5, a.get(6) assert_equal 8070450532247928832, a.get(7) assert_equal "A".sum, a.get(8) end def test_primitive_to_obj Rjb::primitive_conversion = true ar = Rjb::import('java.util.ArrayList') a = ar.new a.add @jString.new('abcdef') a.add @jInteger.valueOf('1') a.add @jShort.valueOf('2') a.add @jDouble.valueOf('3.1') a.add @jFloat.valueOf('4.5') a.add @jBoolean.TRUE a.add @jByte.valueOf('5') a.add @jLong.valueOf('8070450532247928832') a.add @jChar.valueOf("A".sum) assert_equal 'abcdef', a.get(0) assert_equal 1, a.get(1) assert_equal 2, a.get(2) assert_equal 3.1, a.get(3) assert_equal 4.5, a.get(4) assert a.get(5) assert_equal 5, a.get(6) assert_equal 8070450532247928832, a.get(7) assert_equal "A".sum, a.get(8) end def test_enum t = Rjb::import('jp.co.infoseek.hp.arton.rjb.Test$TestTypes') assert t.ONE.equals(t.values()[0]) assert_equal 3, t.values().size assert_equal 2, t.THREE.ordinal assert_equal "TWO", t.TWO.name assert_equal "THREE", t.THREE.toString end #rjb-bugs-15430 rebported by Bryan Duxbury def test_generics_map ctest = import('jp.co.infoseek.hp.arton.rjb.Test') test = ctest.new map = test.sorted_map assert_equal "\0\x1\x2\x3\x4", map.get('abc') assert_equal "\x5\x6\x7\x8\x9", map.get('def') cmap = import('java.util.TreeMap') map = cmap.new map.put('abc', @jString.new('abc').bytes) map.put('012', @jString.new('012').bytes) Rjb::primitive_conversion = true map2 = test.throughSortedMap(map) assert_equal '012', map2.get('012') assert_equal 'abc', map2.get('abc') end def x_test_zzunload # this test should run at the last unload begin load('.') fail 'no exception' rescue assert_equal "can't create Java VM", $!.message end end module TestMixin def test_hello(s) 'hello ' + s end end def test_extend @jString.class_eval do include TestRjb::TestMixin end s = @jString.new assert_equal('hello world', s.test_hello('world')) end def test_extend_with_factory point = import('java.awt.Point') point.class_eval do include TestRjb::TestMixin end p = point.new(11, 12) assert_equal(11, p.x) assert_equal(12, p.y) assert_equal('hello world', p.test_hello('world')) p = p.location assert_equal(11, p.x) assert_equal(12, p.y) assert_equal('hello world', p.test_hello('world')) end def test_fetch_method_signature expected = ['I', 'II', 'Ljava.lang.String;', 'Ljava.lang.String;I'] sig = @jString.sigs('indexOf').sort assert_equal(expected, sig) end def test_fetch_method_without_signature sig = assert_equal([nil], @jString.sigs('toString')) end def test_fetch_static_method_signature expected = ['Ljava.lang.String;[Ljava.lang.Object;', 'Ljava.util.Locale;Ljava.lang.String;[Ljava.lang.Object;'] sig = @jString.static_sigs('format').sort assert_equal(expected, sig) end def test_fetch_ctor_signature expected = ['I', 'Ljava.lang.String;'] sig = @jInteger.ctor_sigs.sort assert_equal(expected, sig) end def test_methods_extension m = @jString.new('').methods assert m.include?('indexOf') end def test_class_methods_extension m = @jString.methods assert m.include?('format') end def test_pmethods_extension m = @jString.new('').public_methods assert m.include?('indexOf') end def test_class_pmethods_extension m = @jString.public_methods assert m.include?('format') end def test_java_methods indexof = @jString.new('').java_methods.find do |m| m =~ /^indexOf/ end args = indexof.match(/\[([^\]]+)\]/)[1] assert_equal('Ljava.lang.String;I, II, I, Ljava.lang.String;'.split(/,\s*/).sort, args.split(/,\s*/).sort) end def test_java_class_methods format = @jString.java_methods.find do |m| m =~ /^format/ end args = format.match(/\[([^\]]+)\]/)[1] assert_equal('Ljava.lang.String;[Ljava.lang.Object;, Ljava.util.Locale;Ljava.lang.String;[Ljava.lang.Object;'.split(/,\s*/).sort, args.split(/,\s*/).sort) end def test_64fixnum big = @jLong.new_with_sig('J', 1230918239495) assert_equal 1230918239495, big.long_value end def test_add_jar add_jar(File.expand_path('./jartest.jar')) jt = import('jp.co.infoseek.hp.arton.rjb.JarTest') assert jt assert_equal 'abcd', jt.new.add('ab', 'cd') end def test_add_jars arg = ['./jartest.jar', './jartest.jar'].map do |e| File.expand_path(e) end add_jar(arg) jt = import('jp.co.infoseek.hp.arton.rjb.JarTest') assert_equal 'abcd', jt.new.add('ab', 'cd') end def test_bothdirection_buffer org = "abcdefghijklmn" baip = import('java.io.ByteArrayInputStream') ba = baip.new(org) buff = "\0" * org.size assert_equal org.size, ba.read(buff) assert_equal -1, ba.read(buff) ba.close assert_equal org, buff end def test_anoninterface arrays = import('java.util.Arrays') a = [3, -4, 5, -6, 8, -10, -14] index = arrays.binary_search(a, 6) do |m, o1, o2| o1.abs - o2.abs end assert_equal 3, index index = arrays.binary_search(a, 7) do |m, o1, o2| o1.abs - o2.abs end assert_equal -5, index end def test_impl two = import('Two') t = two.impl { |m| m.to_s } a = import('TwoCaller').new ret = a.foo(t) assert_equal 'method1', ret[0] assert_equal 'method2', ret[1] end def cause_exception begin @jInteger.parseInt('blabla') rescue NumberFormatException => e raise end end def test_reraise_exception() unless /^1\.8/ =~ RUBY_VERSION begin cause_exception rescue assert($!.to_s =~ /NumberFormatException/) end end end class CbTest def method(l, s, i, d, str) "test_ok:#{l}-#{s}-#{i}-#{d}-#{str}" end end def test_longcallback() cb = bind(CbTest.new, 'jp.co.infoseek.hp.arton.rjb.CallbackTest$Callback') test = import('jp.co.infoseek.hp.arton.rjb.CallbackTest') assert_equal 'test_ok:1234-1234-1234-1234.5-1234', test.callCallback(cb) end class TestIterEx < TestIter def initialize() super @strattr = 'strattr' @numattr = 32 end attr_accessor :strattr, :numattr def multargs(a, b) a + b end end def test_method_otherthan_bound() it = TestIterEx.new it = bind(it, 'java.util.Iterator') test = import('jp.co.infoseek.hp.arton.rjb.Test') a = test.new assert_equal("43210", a.concat(it)) assert(it.respond_to?(:numattr)) assert(it.respond_to?(:multargs)) assert_equal(32, it.numattr) assert_equal('strattr', it.strattr) it.numattr += 1 assert_equal(33, it.numattr) assert_equal(5, it.multargs(3, 2)) end def test_noarg_invoke() str = @jString.new('abc') assert_equal('abc', str._invoke('toString', '')) assert_equal('abc', str._invoke('toString', nil)) assert_equal('abc', str._invoke('toString')) end def test_noarg_sinvoke() sys = import('java.lang.System') cons = sys.console assert_equal(cons._classname, sys._invoke('console', '')._classname) assert_equal(cons._classname, sys._invoke('console', nil)._classname) assert_equal(cons._classname, sys._invoke('console')._classname) end def test_longarg assert_equal(597899502607411822, @jLong.reverse(0x7654321076543210)) begin @jLong.reverse(0x76543210765432101) fail 'no exception for gibnum it doesn\'t convert Java long' rescue RangeError assert true end end def test_bytearg b = @jByte.new(32) assert_equal(32, b.int_value) assert b.compareTo(@jByte.new(32)) assert b.compareTo(@jByte.value_of(32)) b = @jByte.new_with_sig('B', 32) assert_equal(32, b.int_value) assert b.compareTo(@jByte._invoke(:valueOf, 'B', 32)) end def test_typedarray test = import('jp.co.infoseek.hp.arton.rjb.Test').new uri = import('java.net.URI') ret = test.java_typed_array(['a', 'b', 'c'], [1, 2, 3], [uri.new('http://www.artonx.org')]) assert_equal '[Ljava.lang.String;', ret[0] assert_equal '[Ljava.lang.Integer;', ret[1] assert_equal '[Ljava.net.URI;', ret[2] end end rjb-1.4.8/test/Base.java0000644000175000017500000000106712161443611014024 0ustar lunarlunar// $Id$ // this test class was taken from Mr. Micael Weller's bug report package jp.co.infoseek.hp.arton.rjb; public class Base { public String getInstanceVar() { return "hello"; } public static String getSVal() { return "sVal"; } public static String val() { return "val"; } public static String Val() { return "Val"; } public static String intf(Object x) { return x.toString(); } public static final int _NUMBER_FIVE = 5; public static void main(String[] args) { System.out.println(intf(IBase.class)); } } rjb-1.4.8/test/test_osxjvm.rb0000644000175000017500000000057612161443611015225 0ustar lunarlunar#!/usr/local/env ruby -Ku # encoding: utf-8 # $Id:$ begin require 'rjb' rescue LoadError require 'rubygems' require 'rjb' end require 'test/unit' if RUBY_PLATFORM =~ /darwin/ class TestOsxJvm < Test::Unit::TestCase def test_with_javahome ENV['JAVA_HOME'] = `/usr/libexec/java_home` assert_nothing_raised do Rjb::load end end end end rjb-1.4.8/test/JTest.java0000644000175000017500000000324512161443611014203 0ustar lunarlunarimport jp.co.infoseek.hp.arton.rjb.Test; public class JTest { static final String[] rs = new String[] { "a", "b", "c", "d", "e", "f", "g", "h", "i" }; static final Integer[] ri = new Integer[] { new Integer(1), new Integer(2), new Integer(3), new Integer(4), new Integer(5), new Integer(6), new Integer(7), new Integer(8), new Integer(9) }; public static void main(String[] args) { Test t = new Test(); String[] a = t.joinStringArray(new String[][] { {"a", "b", "c"}, {"d", "e", "f"}, {"g", "h", "i"} }); System.out.println(a.length); for (int i = 0; i < a.length; i++) { System.out.print(a[i]); if (rs[i] != a[i]) { System.out.println("bad result !"); System.exit(1); } } System.out.println(""); Integer[] ai = t.joinIntArray(new int[][] { { 1, 2, 3, }, { 4, 5, 6, }, { 7, 8, 9, } }); System.out.println(ai.length); for (int i = 0; i < ai.length; i++) { System.out.print(ai[i]); if (!ri[i].equals(ai[i])) { System.out.println("bad result !"); System.exit(1); } } System.out.println(""); } } rjb-1.4.8/test/CallbackTest.java0000644000175000017500000000047712161443611015512 0ustar lunarlunarpackage jp.co.infoseek.hp.arton.rjb; public class CallbackTest { public interface Callback { String method(long lval, short s, int n, double d, String str); } public static String callCallback(Callback cb) { return cb.method(1234L, (short)1234, 1234, 1234.5, "1234"); } } rjb-1.4.8/test/exttest.rb0000644000175000017500000000140012161443611014323 0ustar lunarlunar#!/usr/local/env ruby -Ku # encoding: utf-8 # $Id:$ begin require 'rjb' rescue LoadError require 'rubygems' require 'rjb' end if Rjb::VERSION < '1.2.2' puts "Rjb #{Rjb::VERSION} does not support rjbextension. exit" exit 0 end require 'rjbextension' require 'test/unit' require 'fileutils' FileUtils.rm_f 'jp/co/infoseek/hp/arton/rjb/Base.class' puts "start RJB(#{Rjb::VERSION}) test" class ExtTestRjb < Test::Unit::TestCase def jp JavaPackage.new('jp') end def test_require_extension assert !Rjb::loaded? $LOAD_PATH << '.' require 'rjbtest.jar' Rjb::load assert Rjb::loaded? base = jp.co.infoseek.hp.arton.rjb.Base.new assert_equal('hello', base.instance_var) end end rjb-1.4.8/test/IBase.java0000644000175000017500000000013012161443611014123 0ustar lunarlunarpackage jp.co.infoseek.hp.arton.rjb; public interface IBase { String getSVal(); } rjb-1.4.8/test/test_osxload.rb0000644000175000017500000000325612161443611015346 0ustar lunarlunar# coding: utf-8 require 'rbconfig' require 'test/unit' class TestOSXLoad < Test::Unit::TestCase def setup ENV['JAVA_HOME'] = '' ENV['JVM_LIB'] = '' @testprog = File.dirname($0) + File::SEPARATOR + 'osx_jvmcheck.rb' end def test_no_java_home skip "no meaning test except for OSX" unless /darwin/ =~ RUBY_PLATFORM javahome = `/usr/libexec/java_home` if javahome =~ /jdk1\.[7-8]\.0/ vendor = /Oracle/ version = /1\.[7-8]\.0/ else vendor = /Apple/ version = /1\.[4-6]\.0/ end test = `#{RbConfig.ruby} #{@testprog}` assert test =~ vendor, expected(vendor, test) assert test =~ version, expected(version, test) end def test_apple_jvm skip "no meaning test except for OSX" unless /darwin/ =~ RUBY_PLATFORM test_specific_jvm('/System/Library/Frameworks/JavaVM.framework/Home', /Apple/) end def test_oracle_jvm skip "no meaning test except for OSX" unless /darwin/ =~ RUBY_PLATFORM test_specific_jvm('/Library/Java/JavaVirtualMachines/***/Contents/Home', /Oracle/) end def test_withjvmlib skip "no meaning test except for OSX" unless /darwin/ =~ RUBY_PLATFORM ENV['JVM_LIB'] = '/usr/lib/libc.dylib' test = `#{RbConfig.ruby} #{@testprog}`.strip assert test == '', "no exception but #{test}" end private def test_specific_jvm(path, vendor) jvms = Dir.glob(path) skip "no #{vendor.inspect} jvm" if jvms.size == 0 ENV['JAVA_HOME'] = jvms[0] test = `#{RbConfig.ruby} #{@testprog}`.strip assert test =~ vendor, expected(vendor, test) end def expected(test, target) "expected #{test.inspect} but #{target}" end end rjb-1.4.8/test/Test.java0000755000175000017500000000755712161443611014106 0ustar lunarlunar// // $Id: Test.java 168 2011-07-15 18:57:04Z arton $ // package jp.co.infoseek.hp.arton.rjb; import java.net.URI; import java.util.ArrayList; import java.util.Iterator; import java.util.Comparator; import java.util.SortedMap; import java.util.TreeMap; import java.math.BigDecimal; public class Test { public String concat(Iterator i) { StringBuffer sb = new StringBuffer(); for (; i.hasNext(); ) { sb.append(i.next()); } return new String(sb); } public int check(Comparator c, int x, int y) { return c.compare(new Integer(x), new Integer(y)); } public String[][] getStringArrayOfArrays() { return new String[][] { { "abc", "def" }, { "123", "456" } }; } public int[][] getIntArrayOfArrays() { return new int[][] { { 1,2,3 }, { 4, 5, 6} }; } public Object[][][] getMixedArray() { return new Object[][][] { { {12, "test", new Integer(15), new BigDecimal("1234.567")}, {} }, { {"a string","another string"}, {1,2,3}, {4,5,6} }, { }, }; } public String[][][][] getSizedArray() { String[][][][] sizedArray = new String[1][2][3][4]; sizedArray[0][1][2][3]="find me"; return sizedArray; } public String[] joinStringArray(String[][] aa) { ArrayList list = new ArrayList(); for (int i = 0; i < aa.length; i++) { for (int j = 0; j < aa[i].length; j++) { list.add(aa[i][j]); } } return list.toArray(new String[list.size()]); } public Integer[] joinIntArray(int[][] aa) { ArrayList list = new ArrayList(); for (int i = 0; i < aa.length; i++) { for (int j = 0; j < aa[i].length; j++) { list.add(aa[i][j]); } } return list.toArray(new Integer[list.size()]); } public int[][][] throughIntArray(int[][][] a) { return a; } public Object getObjectArray() { return new Object[] { new Integer(1), "Hello World !", }; } public Object getObjectArrayOfArray() { return new Object[][] { { new Integer(1), "Hello World !", }, { new Integer(2), "Hello World !!", }, }; } public void callWithArrays(byte[] ab, short[] as, int[] ai, long[] al, double[] ad, float[] af, String[] ax, Object[] ao) { } public enum TestTypes { ONE, TWO, THREE } public SortedMap getSortedMap() { SortedMap map = new TreeMap(); map.put("abc", new byte[]{0,1,2,3,4}); map.put("def", new byte[]{5,6,7,8,9}); return map; } public static SortedMap getSortedMapS() { SortedMap map = new TreeMap(); map.put("abc", new byte[]{0,1,2,3,4}); map.put("def", new byte[]{5,6,7,8,9}); return map; } public SortedMap throughSortedMap(SortedMap map) { SortedMap value = map; return value; } public static void setSortedMapS(SortedMap map) { SortedMap value = map; } public boolean isSameString(String s) { return "貍「蟄励ユ繧ュ繧ケ繝".equals(s); } public String getUmlaut() { return "\u01D6" + "\u00FC\u0304" + "\u0075\u0308\u0304" + "\ud869\udeb2" + "\u304b\u309a"; } public String[] getJavaTypedArray(String[] o, Integer[] n, URI[] u) { return new String[] { o.getClass().getName(), n.getClass().getName(), u.getClass().getName() }; } public String helloData = "Hello World !!"; public static void main(String[] args) { Test test = new Test(); System.out.println(test.getUmlaut()); } } rjb-1.4.8/test/gctest.rb0000644000175000017500000000066112161443611014124 0ustar lunarlunarrequire 'test/unit' require 'rjb' class TestRjbGC < Test::Unit::TestCase include Rjb def setup load(nil, ['-verbose:gc']) end def tearDown unload end def test_gc stringBuffer = import('java.lang.StringBuffer') (0..1000).each do |i| sb = stringBuffer.new (0..1000).each do |j| sb.append(' ') end GC.start end end end rjb-1.4.8/test/TwoCaller.java0000644000175000017500000000027012161443611015041 0ustar lunarlunarpublic class TwoCaller { public String[] foo(Two t) { String[] ret = new String[2]; ret[0] = t.method1(); ret[1] = t.method2(); return ret; } } rjb-1.4.8/test/Two.java0000644000175000017500000000012412161443611013714 0ustar lunarlunarpublic interface Two { public String method1(); public String method2(); } rjb-1.4.8/test/jp/0000755000175000017500000000000012161443611012714 5ustar lunarlunarrjb-1.4.8/test/jp/co/0000755000175000017500000000000012161443611013315 5ustar lunarlunarrjb-1.4.8/test/jp/co/infoseek/0000755000175000017500000000000012161443611015120 5ustar lunarlunarrjb-1.4.8/test/jp/co/infoseek/hp/0000755000175000017500000000000012161443611015527 5ustar lunarlunarrjb-1.4.8/test/jp/co/infoseek/hp/arton/0000755000175000017500000000000012161443611016652 5ustar lunarlunarrjb-1.4.8/test/jp/co/infoseek/hp/arton/rjb/0000755000175000017500000000000012161443611017427 5ustar lunarlunarrjb-1.4.8/test/JarTest.java0000644000175000017500000000023012161443611014515 0ustar lunarlunar// $Id:$ package jp.co.infoseek.hp.arton.rjb; public class JarTest { public String add(String a, String b) { return a + b; } } rjb-1.4.8/test/jartest3.rb0000644000175000017500000000076412161443611014376 0ustar lunarlunar#!/usr/local/env ruby -Ku # encoding: utf-8 begin require 'rjb' rescue LoadError require 'rubygems' require 'rjb' end require 'test/unit' class JarTest < Test::Unit::TestCase include Rjb def setup Rjb::load() end def test_depends add_jar(File.expand_path('./jartest2.jar')) begin Rjb::import('jp.co.infoseek.hp.arton.rjb.JarTest2') fail 'no exception' rescue NoClassDefFoundError assert true end end end rjb-1.4.8/test/ExtBase.java0000644000175000017500000000022612161443611014501 0ustar lunarlunar// $Id$ // this test class was taken from Mr. Micael Weller's bug report package jp.co.infoseek.hp.arton.rjb; public class ExtBase extends Base { } rjb-1.4.8/test/listtest.rb0000644000175000017500000000202712161443611014504 0ustar lunarlunar#!/usr/local/env ruby -Ku # encoding: utf-8 =begin Copyright(c) 2012 arton =end begin require 'rjb/list' rescue LoadError require 'rubygems' require 'rjb/list' end require 'test/unit' require 'fileutils' class ListTest < Test::Unit::TestCase include Rjb def test_create ja = import('java.util.ArrayList') a = ja.new a.add(1) a.add(2) a.add(3) n = 1 a.each do |x| assert_equal n, x.intValue n += 1 end assert_equal 4, n end def test_returned_proxy ja = import('java.util.Arrays') a = ja.as_list([1, 2, 3]) n = 1 a.each do |x| assert_equal n, x.intValue n += 1 end assert_equal 4, n end def test_iterator ja = import('java.util.Arrays') it = ja.as_list([1, 2, 3]).iterator n = 1 it.each do |x| assert_equal n, x.intValue n += 1 end assert_equal 4, n end def test_enumerable ja = import('java.util.Arrays') assert_equal 55, ja.as_list((1..10).to_a).inject(0) {|r, e| r + e.intValue} end end rjb-1.4.8/test/jartest.rb0000644000175000017500000000070612161443611014307 0ustar lunarlunar#!/usr/local/env ruby -Ku # encoding: utf-8 begin require 'rjb' rescue LoadError require 'rubygems' require 'rjb' end require 'test/unit' class JarTest < Test::Unit::TestCase include Rjb def setup Rjb::load() end def test_depends add_jar(File.expand_path('./jartest2.jar')) add_jar(File.expand_path('./jartest.jar')) assert Rjb::import('jp.co.infoseek.hp.arton.rjb.JarTest2') end end rjb-1.4.8/test/test_unload.rb0000755000175000017500000000070412161443611015155 0ustar lunarlunar#!/usr/local/env ruby -Ku # encoding: utf-8 # $Id: test.rb 176 2011-11-09 14:27:28Z arton $ begin require 'rjb' rescue LoadError require 'rubygems' require 'rjb' end require 'test/unit' class TestUnloadRjb < Test::Unit::TestCase include Rjb def setup Rjb::load('.') end def test_unload jString = import('java.lang.String') assert_equal 0, Rjb::unload jString = nil GC.start end end