rjb-1.5.3/0000755000175000017500000000000012447020465011325 5ustar lunarlunarrjb-1.5.3/rjb.rake0000644000175000017500000000355112447020465012752 0ustar lunarlunarrequire 'rubygems' begin require 'rake/gempackagetask' $package_task = Rake::GemPackageTask rescue require 'rubygems/package_task' $package_task = Gem::PackageTask end 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://www.artonx.org/collabo/backyard/?RubyJavaBridge' s.rubyforge_project = 'rjb' s.version = read_version s.requirements << 'none' s.require_path = 'lib' s.requirements << 'JDK 5.0' s.license = 'LGPL' files = FileList['ext/*.java', 'ext/*.c', 'ext/*.h', 'ext/depend', 'data/rjb/**/*.class', 'lib/*.rb', 'lib/rjb/*.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 = < 1.5.3 select preferable constructor if argument is an array (for java.lang.String) *test/test.rb change literals to constants for kanji strings Sun Dec 14 2014 arton *lib/rjb.rb FakeDL for Rubinius *ext/riconv.c Change variable name for avoiding conflicion (Runinius) *ext/rjb.c RJB_VERSION -> 1.5.2 Support Rubinius (Rubinius's block is T_OBJECT instead of T_DATA -> affected to anonclass) *test/test.rb skip fixnum range test if Rubinius Tue Sep 23 2014 arton *ext/rjb.c RJB_VERSION -> 1.5.1 more weight for array and true/false Sat Sep 20 2014 arton *ext/rjb.c RJB_VERSION -> 1.5.0 fix ctor_sigs with non argment ctor (represented by '') select preferable constructor *ext/riconv.c restruct encoding function *test/test.rb add constructor selection test (Ljava.lang.String; vs [B) Wed Jan 15 2014 arton *rjb.rake add lib/rjb/*.rb into gem Fri Jan 4 2014 arton *test/Test.java *test/rjbtest.jar add inner exception test *test/test.java add inner exception test Fri Jan 3 2014 arton *ext/rjb.c RJB_VERSION -> 1.4.9 *ext/rjbexception.c make J#cause to the instance method for resolving Ruby 2.1 confliction. Sun 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.5.3/readme.sj0000644000175000017500000000213412447020465013120 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.5.3/readme.txt0000644000175000017500000000172712447020465013332 0ustar lunarlunarRjb is Ruby-Java bridge using Java Native Interface. http://www.slideshare.net/artonx/j-ruby-kaigi-2010 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/view_bug.do?bug_id=4733494 (Thanks Paul for this information). artonx@yahoo.co.jp rjb-1.5.3/COPYING0000644000175000017500000006347612447020465012400 0ustar lunarlunar GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. 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.5.3/ext/0000755000175000017500000000000012447020465012125 5ustar lunarlunarrjb-1.5.3/ext/rjb.c0000755000175000017500000026130212447020465013055 0ustar lunarlunar/* * Rjb - Ruby <-> Java Bridge * Copyright(c) 2004,2005,2006,2007,2008,2009,2010,2011,2012,2014 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. * */ #define RJB_VERSION "1.5.3" #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 defined(DEBUG) { VALUE v = rb_funcall(val, rb_intern("inspect"), 0); fprintf(stderr, "rtype:%d, sig=%s\n", TYPE(val), psig); fprintf(stderr, "obj:%s\n", StringValueCStr(v)); 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; } #define IS_BYTE(b) (!((b) & 0xffffff00)) #define IS_SHORT(b) (!((b) & 0xffff0000)) /* * temporary signature check * return !0 if found */ #define UNMATCHED 0 #define SATISFIED 1 #define SOSO 2 #define PREFERABLE 3 static int check_rtype(JNIEnv* jenv, VALUE* pv, char* p) { size_t i; 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 SATISFIED; } switch (TYPE(*pv)) { case T_FIXNUM: if (strchr("IJ", *p)) return SOSO; return strchr("BCDFS", *p) != NULL; case T_BIGNUM: return strchr("BCDFIJS", *p) != NULL; case T_FLOAT: if (*p == 'D') return SOSO; if (*p == 'F') return SATISFIED; return UNMATCHED; case T_STRING: if (pcls && (!strcmp("java.lang.String", pcls) || !strcmp("java.lang.CharSequence", pcls))) { return PREFERABLE; } else if (*p == '[' && *(p + 1) == 'B') { return SATISFIED; } return UNMATCHED; case T_TRUE: case T_FALSE: return (*p == 'Z') ? SOSO : UNMATCHED; case T_ARRAY: if (*p == '[') { int weight = (*(p + 1) == 'C') ? SOSO : PREFERABLE; size_t len = RARRAY_LEN(*pv); VALUE* ppv = RARRAY_PTR(*pv); unsigned long ul; if (!strchr("BCSI", *(p + 1))) return SOSO; // verify later if (len > 32) len = 32; for (i = 0; i < len; i++, ppv++) { if (!FIXNUM_P(*ppv)) { return UNMATCHED; } ul = (unsigned long)FIX2LONG(*ppv); if (*(p + 1) == 'B') { if (!IS_BYTE(ul)) return UNMATCHED; } else if (*(p + 1) == 'C' || *(p + 1) == 'S') { if (!IS_SHORT(ul)) return UNMATCHED; } } return weight; } return UNMATCHED; case T_DATA: case T_OBJECT: if (IS_RJB_OBJECT(*pv) && pcls) { /* imported object */ jclass cls; struct jvi_data* ptr; int result = 0; if (!strcmp("java.lang.String", pcls)) return SATISFIED; 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) ? PREFERABLE : UNMATCHED; } 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 */ default: if (pcls || *p == '[') { return SATISFIED; } return UNMATCHED; } } /* * 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; struct cls_constructor** found_pc = NULL; int found = 0; int weight = 0; int cweight; 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++) { found = 0; if ((*pc)->arg_count == argc) { found = 1; cweight = 0; psig = (*pc)->method_signature; for (i = 0; i < argc; i++) { int w = check_rtype(jenv, argv + i, psig); if (!w) { found = 0; break; } cweight += w; psig = next_sig(psig); } } if (found) { if (cweight > weight || weight == 0) { found_pc = pc; weight = cweight; } } } if (found_pc) { #if defined(DEBUG) fprintf(stderr, "ctr sig=%s\n", (*found_pc)->method_signature); fflush(stderr); #endif ret = createinstance(jenv, argc, argv, self, *found_pc); } } if (!found_pc) { 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++) { const char* sig = (*pc)->method_signature; rb_ary_push(ret, rb_str_new2(sig ? sig : "")); } } 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, cweight; jvalue jv; jvalue* args; char* psig; struct cls_method* orgpm = pm; struct cls_method* prefer_pm = NULL; int weight = 0; 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 (; pm; pm = pm->next) { found = 0; if (argc == pm->basic.arg_count) { if (sig && pm->basic.method_signature) { if (!strcmp(sig, pm->basic.method_signature)) { found = 1; prefer_pm = pm; break; } } else { found = 1; cweight = 0; psig = pm->basic.method_signature; for (i = 0; i < argc; i++) { int w = check_rtype(jenv, argv + i, psig); if (!w) { found = 0; break; } cweight += w; psig = next_sig(psig); } } } if (found) { if (cweight > weight || weight == 0) { prefer_pm = pm; weight = cweight; } } } if (!prefer_pm) { 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 = prefer_pm->basic.method_signature; for (i = 0; i < argc; i++) { R2J pr2j = *(prefer_pm->basic.arg_convert + i); pr2j(jenv, argv[i], args + i, psig, 0); psig = next_sig(psig); } switch (prefer_pm->basic.result_signature) { case 'D': { INVOKEAD voked = *(INVOKEAD*)(((char*)*jenv) + prefer_pm->method); jv.d = voked(jenv, ptr->obj, prefer_pm->basic.id, args); } break; case 'Z': case 'B': { INVOKEAZ vokez = *(INVOKEAZ*)(((char*)*jenv) + prefer_pm->method); jv.z = vokez(jenv, ptr->obj, prefer_pm->basic.id, args); } break; case 'F': { INVOKEAF vokef = *(INVOKEAF*)(((char*)*jenv) + prefer_pm->method); jv.f = vokef(jenv, ptr->obj, prefer_pm->basic.id, args); } break; case 'C': case 'S': { INVOKEAS vokes = *(INVOKEAS*)(((char*)*jenv) + prefer_pm->method); jv.s = vokes(jenv, ptr->obj, prefer_pm->basic.id, args); } break; #if HAVE_LONG_LONG case 'J': { INVOKEAL vokel = *(INVOKEAL*)(((char*)*jenv) + prefer_pm->method); jv.j = vokel(jenv, ptr->obj, prefer_pm->basic.id, args); } break; #endif default: { INVOKEA voke = *(INVOKEA*)(((char*)*jenv) + prefer_pm->method); jv.l = voke(jenv, ptr->obj, prefer_pm->basic.id, args); } break; } rjb_check_exception(jenv, 1); psig = prefer_pm->basic.method_signature; for (i = 0; i < argc; i++) { R2J pr2j = *(prefer_pm->basic.arg_convert + i); pr2j(jenv, argv[i], args + i, psig, 1); psig = next_sig(psig); } if (prefer_pm->basic.result_arraydepth) { return ja2r(prefer_pm->result_convert, jenv, jv, prefer_pm->basic.result_arraydepth); } else { return prefer_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.5.3/ext/riconv.h0000644000175000017500000000141012447020465013572 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.5.3/ext/depend0000644000175000017500000000360212447020465013310 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.5.3/ext/rjb.h0000644000175000017500000001030212447020465013047 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.5.3/ext/MANIFEST0000644000175000017500000000014612447020465013257 0ustar lunarlunarMANIFEST rjb.h riconv.h riconv.c rjb.c load.c rjbexception.c extconf.rb RBridge.java depend jniwrap.h rjb-1.5.3/ext/rjbexception.c0000644000175000017500000001074512447020465014774 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 get_cause(VALUE self) { return rb_funcall(rb_ivar_get(self, rb_intern("@cause")), rb_intern("cause"), 0); } 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, "cause", get_cause, 0); 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.5.3/ext/extconf.h0000755000175000017500000000025512447020465013751 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.5.3/ext/RBridge.java0000644000175000017500000000251612447020465014312 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.5.3/ext/extconf.rb0000644000175000017500000000323412447020465014122 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.5.3/ext/load.c0000644000175000017500000002765512447020465013227 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.5.3/ext/jniwrap.h0000644000175000017500000000172612447020465013756 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.5.3/ext/riconv.c0000644000175000017500000001415112447020465013573 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 #if defined(DEBUG) static void debug_out(VALUE v) { char* p = StringValuePtr(v); printf("-- %d, %d, %s\n", rb_num2long(rb_funcall(v, rb_intern("size"), 0)), strlen(p), p); fflush(stdout); } #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 cEncoding, encoding, utf8; cEncoding = rb_const_get(rb_cObject, rb_intern("Encoding")); encoding = rb_funcall(local_string, rb_intern("encoding"), 0); utf8 = rb_const_get(cEncoding, rb_intern("UTF_8")); if (encoding != utf8) { VALUE ret = rb_funcall(local_string, rb_intern("encode"), 2, utf8, encoding); #if defined(DEBUG) debug_out(local_string); debug_out(ret); #endif return ret; } 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_const_get(rb_cEncoding, rb_intern("UTF_8"))); #endif } rjb-1.5.3/lib/0000755000175000017500000000000012447020465012073 5ustar lunarlunarrjb-1.5.3/lib/rjb/0000755000175000017500000000000012447020465012650 5ustar lunarlunarrjb-1.5.3/lib/rjb/list.rb0000644000175000017500000000120412447020465014145 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.5.3/lib/rjb/extension.rb0000644000175000017500000000710412447020465015213 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.5.3/lib/rjbextension.rb0000644000175000017500000000003112447020465015124 0ustar lunarlunarrequire 'rjb/extension' rjb-1.5.3/lib/rjb.rb0000755000175000017500000000630412447020465013203 0ustar lunarlunar=begin Copyright(c) 2006-2010,2012 arton =end require 'rbconfig' begin require 'rubinius/ffi' module DL extend FFI::Library class FakeDL def initialize(lib) @lib = lib end def [](fun) f = @lib.find_function(fun) if f f.to_i else nil end end end def self.dlopen(lib) a = ffi_lib(lib) if Array === a && a.size >= 1 FakeDL.new(a[0]) else nil end end end rescue LoadError end 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.5.3/pre-install.rb0000644000175000017500000000031612447020465014104 0ustar lunarlunar=begin Copyright (c) 2006,2014 arton =end require 'rbconfig' if File.exist?(File.join(RbConfig::CONFIG['sitearchdir'], 'rjb.so')) File.delete(File.join(RbConfig::CONFIG['sitearchdir'], 'rjb.so')) end rjb-1.5.3/data/0000755000175000017500000000000012447020465012236 5ustar lunarlunarrjb-1.5.3/data/rjb/0000755000175000017500000000000012447020465013013 5ustar lunarlunarrjb-1.5.3/data/rjb/jp/0000755000175000017500000000000012447020465013424 5ustar lunarlunarrjb-1.5.3/data/rjb/jp/co/0000755000175000017500000000000012447020465014025 5ustar lunarlunarrjb-1.5.3/data/rjb/jp/co/infoseek/0000755000175000017500000000000012447020465015630 5ustar lunarlunarrjb-1.5.3/data/rjb/jp/co/infoseek/hp/0000755000175000017500000000000012447020465016237 5ustar lunarlunarrjb-1.5.3/data/rjb/jp/co/infoseek/hp/arton/0000755000175000017500000000000012447020465017362 5ustar lunarlunarrjb-1.5.3/data/rjb/jp/co/infoseek/hp/arton/rjb/0000755000175000017500000000000012447020465020137 5ustar lunarlunarrjb-1.5.3/setup.rb0000644000175000017500000007114712447020465013024 0ustar lunarlunar# # setup.rb # # Copyright (c) 2000-2004 Minero Aoki # Copyright (c) 2014 arton # # 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 = ::RbConfig::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| /\.#{::RbConfig::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.5.3/test/0000755000175000017500000000000012447020465012304 5ustar lunarlunarrjb-1.5.3/test/jp/0000755000175000017500000000000012447020465012715 5ustar lunarlunarrjb-1.5.3/test/jp/co/0000755000175000017500000000000012447020465013316 5ustar lunarlunarrjb-1.5.3/test/jp/co/infoseek/0000755000175000017500000000000012447020465015121 5ustar lunarlunarrjb-1.5.3/test/jp/co/infoseek/hp/0000755000175000017500000000000012447020465015530 5ustar lunarlunarrjb-1.5.3/test/jp/co/infoseek/hp/arton/0000755000175000017500000000000012447020465016653 5ustar lunarlunarrjb-1.5.3/test/jp/co/infoseek/hp/arton/rjb/0000755000175000017500000000000012447020465017430 5ustar lunarlunarrjb-1.5.3/test/test_osxjvm.rb0000644000175000017500000000057612447020465015226 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.5.3/test/Base.java0000644000175000017500000000106712447020465014025 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.5.3/test/readme.txt0000644000175000017500000000040512447020465014301 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.5.3/test/jartest2.rb0000644000175000017500000000066712447020465014400 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.5.3/test/JarTest2.java0000755000175000017500000000026712447020465014615 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.5.3/test/osx_jvmcheck.rb0000644000175000017500000000031012447020465015306 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.5.3/test/JTest.java0000644000175000017500000000324512447020465014204 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.5.3/test/JarTest.java0000644000175000017500000000023012447020465014516 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.5.3/test/jartest.rb0000644000175000017500000000070612447020465014310 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.5.3/test/test.rb0000755000175000017500000006776112447020465013634 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_with_sig('Ljava.lang.String;', 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_with_sig('Ljava.lang.String;', 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_with_sig('Ljava.lang.String;', 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_with_sig('Ljava.lang.String;', 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() skip('1.8 does not support reraise') if /^1\.8/ =~ RUBY_VERSION begin cause_exception rescue assert($!.inspect =~ /NumberFormatException/) end end def test_inner_exception test = import('jp.co.infoseek.hp.arton.rjb.Test').new begin test.cause_exception flunk("no exception") rescue IllegalStateException => e ia = e.cause assert_equal('bad argument', ia.message) assert_equal('java.lang.IllegalArgumentException', ia._classname) 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 skip('rbx can handle 64bits long') if RUBY_ENGINE == 'rbx' assert_equal(597899502607411822, @jLong.reverse(0x7654321076543210)) begin @jLong.reverse(0x76543210765432101) fail 'no exception for bigbnum 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 SJIS_STR = "\x8a\xbf\x8e\x9a\x83\x65\x83\x4c\x83\x58\x83\x67" EUCJP_STR = "\xb4\xc1\xbb\xfa\xa5\xc6\xa5\xad\xa5\xb9\xa5\xc8" UTF8_STR = "\xE6\xBC\xA2\xE5\xAD\x97\xE3\x83\x86\xE3\x82\xAD\xE3\x82\xB9\xE3\x83\x88" def test_auto_constructor_selection skip 'no encoding' unless Object::const_defined?(:Encoding) sys = import('java.lang.System') encoding = sys.property('file.encoding') s = @jString.new(SJIS_STR.force_encoding Encoding::SHIFT_JIS) e = @jString.new(EUCJP_STR.force_encoding Encoding::EUC_JP) u = @jString.new(UTF8_STR.force_encoding Encoding::UTF_8) if encoding == 'MS932' s1 = @jString.new(SJIS_STR.bytes) elsif encoding.upcase == 'EUC-JP' s1 = @jString.new(EUCJP_STR.bytes) elsif encoding.upcase == 'UTF-8' s1 = @jString.new(UTF8_STR.bytes) else skip 'no checkable encoding' end assert_equal s1.toString, s.toString assert_equal s1.toString, e.toString assert_equal s1.toString, u.toString end end rjb-1.5.3/test/test_osxload.rb0000644000175000017500000000325612447020465015347 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.5.3/test/gctest.rb0000644000175000017500000000066112447020465014125 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.5.3/test/exttest.rb0000644000175000017500000000140012447020465014324 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.5.3/test/listtest.rb0000644000175000017500000000202712447020465014505 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.5.3/test/jartest3.rb0000644000175000017500000000076412447020465014377 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.5.3/test/test_unload.rb0000755000175000017500000000070412447020465015156 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 rjb-1.5.3/test/Two.java0000644000175000017500000000012412447020465013715 0ustar lunarlunarpublic interface Two { public String method1(); public String method2(); } rjb-1.5.3/test/Test.java0000755000175000017500000001007112447020465014070 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 void causeException() { try { throw new IllegalArgumentException("bad argument"); } catch (Exception e) { throw new IllegalStateException("outer exception", e); } } public String helloData = "Hello World !!"; public static void main(String[] args) { Test test = new Test(); System.out.println(test.getUmlaut()); } } rjb-1.5.3/test/TwoCaller.java0000644000175000017500000000027012447020465015042 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.5.3/test/CallbackTest.java0000644000175000017500000000047712447020465015513 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.5.3/test/ExtBase.java0000644000175000017500000000022612447020465014502 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.5.3/test/IBase.java0000644000175000017500000000013012447020465014124 0ustar lunarlunarpackage jp.co.infoseek.hp.arton.rjb; public interface IBase { String getSVal(); } rjb-1.5.3/samples/0000755000175000017500000000000012447020465012771 5ustar lunarlunarrjb-1.5.3/samples/filechooser.rb0000644000175000017500000000111612447020465015617 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.5.3/samples/unzip.rb0000644000175000017500000000230012447020465014456 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