[libinline-java-perl] 255/398: ok
Jonas Smedegaard
dr at jones.dk
Thu Feb 26 11:43:11 UTC 2015
This is an automated email from the git hooks/post-receive script.
js pushed a commit to tag 0.55
in repository libinline-java-perl.
commit 531f4d1caef770a2f822d426309e4345a91777d1
Author: patrick_leb <>
Date: Sun Nov 30 21:48:08 2003 +0000
ok
---
CHANGES | 1 +
Java.pm | 19 +-
Java.pod | 7 +
Java/JVM.pm | 15 +-
Java/Makefile.PL | 4 +-
Java/Portable.pm | 7 +-
.../org/perl/inline/java/InlineJavaArray.java | 100 ++++
.../org/perl/inline/java/InlineJavaCallback.java | 129 ++++
.../perl/inline/java/InlineJavaCallbackQueue.java | 66 ++
.../perl/inline/java/InlineJavaCastException.java | 7 +
.../org/perl/inline/java/InlineJavaClass.java | 457 ++++++++++++++
.../org/perl/inline/java/InlineJavaException.java | 7 +
.../java/InlineJavaInvocationTargetException.java | 15 +
.../org/perl/inline/java/InlineJavaPerlCaller.java | 115 ++++
.../perl/inline/java/InlineJavaPerlException.java | 19 +
.../org/perl/inline/java/InlineJavaProtocol.java | 661 +++++++++++++++++++++
.../org/perl/inline/java/InlineJavaServer.java | 275 +++++++++
.../perl/inline/java/InlineJavaServerThread.java | 68 +++
.../org/perl/inline/java/InlineJavaThrown.java | 14 +
.../perl/inline/java/InlineJavaUserClassLink.java | 45 ++
.../inline/java/InlineJavaUserClassLoader.java | 190 ++++++
.../org/perl/inline/java/InlineJavaUtils.java | 56 ++
MANIFEST | 32 +-
Makefile.PL | 8 +-
README | 1 +
25 files changed, 2291 insertions(+), 27 deletions(-)
diff --git a/CHANGES b/CHANGES
index 1f65722..8d0c965 100644
--- a/CHANGES
+++ b/CHANGES
@@ -5,6 +5,7 @@ Revision history for Perl extension Inline::Java
- Callbacks from multiple threads are now supported
- Refactored (again...) studying/.jdat/cache stuff
- Added PRIVATE mode for use with SHARED_JVM
+ - Added DEBUGGER mode that launches jdb
- Fixed memory leak in JNI coded (patch submitted by Dave Blob)
0.43 Tue Oct 14 13:18:25 EDT 2003
diff --git a/Java.pm b/Java.pm
index 10bc8f5..529c598 100644
--- a/Java.pm
+++ b/Java.pm
@@ -127,6 +127,7 @@ sub validate {
$o->set_option('EXTRA_JAVA_ARGS', '', 's', 1, \%opts) ;
$o->set_option('EXTRA_JAVAC_ARGS', '', 's', 1, \%opts) ;
+ $o->set_option('DEBUGGER', 0, 'b', 1, \%opts) ;
$o->set_option('PRIVATE', '', 'b', 1, \%opts) ;
@@ -155,11 +156,27 @@ sub validate {
if (($o->get_java_config('JNI'))&&($o->get_java_config('SHARED_JVM'))){
croak("You can't use the 'SHARED_JVM' option in 'JNI' mode") ;
}
+ if (($o->get_java_config('JNI'))&&($o->get_java_config('DEBUGGER'))){
+ croak("You can't invoke the Java debugger ('DEBUGGER' option) in 'JNI' mode") ;
+ }
if ($o->get_java_config('JNI')){
require Inline::Java::JNI ;
}
+ if ($o->get_java_config('DEBUGGER')){
+ # Here we want to tweak a few settings to help debugging...
+ Inline::Java::debug(1, "Debugger mode activated") ;
+ # Add the -g compile option
+ $o->set_java_config('EXTRA_JAVAC_ARGS', $o->get_java_config('EXTRA_JAVAC_ARGS') . " -g ") ;
+ # Add the -sourcepath runtime option
+ $o->set_java_config('EXTRA_JAVA_ARGS', $o->get_java_config('EXTRA_JAVA_ARGS') .
+ " -sourcepath " . $o->get_api('build_dir') .
+ portable("ENV_VAR_PATH_SEP_CP") .
+ get_source_dir()
+ ) ;
+ }
+
my $study = $o->get_java_config('STUDY') ;
if ((defined($study))&&(ref($study) ne 'ARRAY')){
croak "Configuration option 'STUDY' must be an array of Java class names" ;
@@ -352,7 +369,7 @@ sub build {
# Go back and clean up
chdir $cwd ;
- if ($o->get_api('cleanup')){
+ if (($o->get_api('cleanup'))&&(! $o->get_java_config('DEBUGGER'))){
$o->rmpath('', $build_dir) ;
}
diff --git a/Java.pod b/Java.pod
index a3f3700..435ca96 100644
--- a/Java.pod
+++ b/Java.pod
@@ -205,6 +205,13 @@ behavior of C<Inline::Java>:
5 = Data structure dumps
Ex: DEBUG => 2
+ DEBUGGER:
+ Starts jdb, (the Java debugger) instead of the regular Java JVM.
+ This option will also cause the Java code to be compiled using the
+ '-g' switch for extra debugging information. EXTRA_JAVA_ARGS can
+ be used use to pass extra options to the debugger.
+ Ex: DEBUGGER => 1
+
WARN_METHOD_SELECT:
Throws a warning when C<Inline::Java> has to 'choose' between
different method signatures. The warning states the possible
diff --git a/Java/JVM.pm b/Java/JVM.pm
index 8dba017..ac82e40 100644
--- a/Java/JVM.pm
+++ b/Java/JVM.pm
@@ -6,7 +6,6 @@ use Carp ;
use IPC::Open3 ;
use IO::File ;
use IO::Socket ;
-use POSIX qw(setsid) ;
$Inline::Java::JVM::VERSION = '0.43' ;
@@ -34,6 +33,7 @@ sub new {
$this->{owner} = 1 ;
$this->{destroyed} = 0 ;
$this->{private} = $o->get_java_config('PRIVATE') ;
+ $this->{debugger} = $o->get_java_config('DEBUGGER') ;
if ($this->{embedded}){
Inline::Java::debug(1, "using embedded JVM...") ;
@@ -104,7 +104,8 @@ sub new {
}
my $java = File::Spec->catfile($o->get_java_config('J2SDK'), 'bin',
- "java" . Inline::Java::portable("EXE_EXTENSION")) ;
+ ($this->{debugger} ? "jdb" : "java") .
+ Inline::Java::portable("EXE_EXTENSION")) ;
my $shared = ($this->{shared} ? "true" : "false") ;
my $priv = ($this->{private} ? "true" : "false") ;
@@ -132,7 +133,8 @@ sub new {
$this->{socket} = $this->setup_socket(
$this->{host},
$this->{port},
- int($o->get_java_config('STARTUP_DELAY')),
+ # Give the user an extra hour's time set breakpoints and the like...
+ ($this->{debugger} ? 3600 : 0) + int($o->get_java_config('STARTUP_DELAY')),
0
) ;
}
@@ -148,7 +150,7 @@ sub launch {
local $SIG{__WARN__} = sub {} ;
my $dn = Inline::Java::portable("DEV_NULL") ;
- my $in = new IO::File("<$dn") ;
+ my $in = ($this->{debugger} ? ">&STDIN" : new IO::File("<$dn")) ;
if (! defined($in)){
croak "Can't open $dn for reading" ;
}
@@ -161,7 +163,9 @@ sub launch {
}
my $pid = open3($in, $out, ">&STDERR", $cmd) ;
- close($in) ;
+ if (! $this->{debugger}){
+ close($in) ;
+ }
if ($this->{shared}){
close($out) ;
}
@@ -267,6 +271,7 @@ sub setup_socket {
if (($socket)||($one_shot)){
last ;
}
+ select(undef, undef, undef, 0.1) ;
}
if ($got_alarm){
diff --git a/Java/Makefile.PL b/Java/Makefile.PL
index c8ac8d8..c8d6bcb 100644
--- a/Java/Makefile.PL
+++ b/Java/Makefile.PL
@@ -136,8 +136,10 @@ else{
NAME => 'Inline::Java::JNI',
VERSION_FROM => 'JNI.pm',
DIR => [],
+ PMLIBDIRS => [File::Spec->catdir('sources', 'org', 'perl', 'inline', 'java')],
XS => {},
- C => []) ;
+ C => []
+ ) ;
}
diff --git a/Java/Portable.pm b/Java/Portable.pm
index 827d7d2..f3a9d26 100644
--- a/Java/Portable.pm
+++ b/Java/Portable.pm
@@ -1,7 +1,7 @@
package Inline::Java::Portable ;
@Inline::Java::Portable::ISA = qw(Exporter) ;
- at EXPORT = qw(portable make_classpath get_server_jar get_user_jar) ;
+ at EXPORT = qw(portable make_classpath get_server_jar get_user_jar get_source_dir) ;
use strict ;
use Exporter ;
@@ -99,6 +99,11 @@ sub get_user_jar {
}
+sub get_source_dir {
+ return File::Spec->catdir(get_jar_dir(), 'sources') ;
+}
+
+
# This maybe could be made more stable
sub find_classes_in_dir {
my $dir = shift ;
diff --git a/Java/sources/org/perl/inline/java/InlineJavaArray.java b/Java/sources/org/perl/inline/java/InlineJavaArray.java
new file mode 100644
index 0000000..c397ab4
--- /dev/null
+++ b/Java/sources/org/perl/inline/java/InlineJavaArray.java
@@ -0,0 +1,100 @@
+package org.perl.inline.java ;
+
+import java.util.* ;
+import java.lang.reflect.Array ;
+
+
+class InlineJavaArray {
+ private InlineJavaClass ijc ;
+
+
+ InlineJavaArray(InlineJavaClass _ijc){
+ ijc = _ijc ;
+ }
+
+
+ Object CreateArray(Class c, StringTokenizer st) throws InlineJavaException {
+ StringBuffer sb = new StringBuffer(st.nextToken()) ;
+ sb.replace(0, 1, "") ;
+ sb.replace(sb.length() - 1, sb.length(), "") ;
+
+ StringTokenizer st2 = new StringTokenizer(sb.toString(), ",") ;
+ ArrayList al = new ArrayList() ;
+ while (st2.hasMoreTokens()){
+ al.add(al.size(), st2.nextToken()) ;
+ }
+
+ int size = al.size() ;
+ int dims[] = new int[size] ;
+ for (int i = 0 ; i < size ; i++){
+ dims[i] = Integer.parseInt((String)al.get(i)) ;
+ InlineJavaUtils.debug(4, "array dimension: " + (String)al.get(i)) ;
+ }
+
+ Object array = null ;
+ try {
+ array = Array.newInstance(c, dims) ;
+
+ ArrayList args = new ArrayList() ;
+ while (st.hasMoreTokens()){
+ args.add(args.size(), st.nextToken()) ;
+ }
+
+ // Now we need to fill it. Since we have an arbitrary number
+ // of dimensions, we can do this recursively.
+
+ PopulateArray(array, c, dims, args) ;
+ }
+ catch (IllegalArgumentException e){
+ throw new InlineJavaException("Arguments to array constructor for class " + c.getName() + " are incompatible: " + e.getMessage()) ;
+ }
+
+ return array ;
+ }
+
+
+ void PopulateArray (Object array, Class elem, int dims[], ArrayList args) throws InlineJavaException {
+ if (dims.length > 1){
+ int nb_args = args.size() ;
+ int nb_sub_dims = dims[0] ;
+ int nb_args_per_sub_dim = nb_args / nb_sub_dims ;
+
+ int sub_dims[] = new int[dims.length - 1] ;
+ for (int i = 1 ; i < dims.length ; i++){
+ sub_dims[i - 1] = dims[i] ;
+ }
+
+ for (int i = 0 ; i < nb_sub_dims ; i++){
+ // We want the args from i*nb_args_per_sub_dim ->
+ ArrayList sub_args = new ArrayList() ;
+ for (int j = (i * nb_args_per_sub_dim) ; j < ((i + 1) * nb_args_per_sub_dim) ; j++){
+ sub_args.add(sub_args.size(), (String)args.get(j)) ;
+ }
+ PopulateArray(((Object [])array)[i], elem, sub_dims, sub_args) ;
+ }
+ }
+ else{
+ String msg = "In creation of array of " + elem.getName() + ": " ;
+ try {
+ for (int i = 0 ; i < dims[0] ; i++){
+ String arg = (String)args.get(i) ;
+
+ Object o = ijc.CastArgument(elem, arg) ;
+ Array.set(array, i, o) ;
+ if (o != null){
+ InlineJavaUtils.debug(4, "setting array element " + String.valueOf(i) + " to " + o.toString()) ;
+ }
+ else{
+ InlineJavaUtils.debug(4, "setting array element " + String.valueOf(i) + " to " + o) ;
+ }
+ }
+ }
+ catch (InlineJavaCastException e){
+ throw new InlineJavaCastException(msg + e.getMessage()) ;
+ }
+ catch (InlineJavaException e){
+ throw new InlineJavaException(msg + e.getMessage()) ;
+ }
+ }
+ }
+}
diff --git a/Java/sources/org/perl/inline/java/InlineJavaCallback.java b/Java/sources/org/perl/inline/java/InlineJavaCallback.java
new file mode 100644
index 0000000..bd1e1c8
--- /dev/null
+++ b/Java/sources/org/perl/inline/java/InlineJavaCallback.java
@@ -0,0 +1,129 @@
+package org.perl.inline.java ;
+
+import java.util.* ;
+import java.io.* ;
+
+
+/*
+ Callback to Perl...
+*/
+class InlineJavaCallback {
+ private InlineJavaServer ijs = InlineJavaServer.GetInstance() ;
+ private String pkg = null ;
+ private String method = null ;
+ private Object args[] = null ;
+ private String cast = null ;
+ private Object response = null ;
+ private boolean response_set = false ;
+
+
+ InlineJavaCallback(String _pkg, String _method, Object _args[], String _cast) {
+ pkg = _pkg ;
+ method = _method ;
+ args = _args ;
+ cast = _cast ;
+ }
+
+
+ private String GetCommand(InlineJavaProtocol ijp) throws InlineJavaException {
+ StringBuffer cmdb = new StringBuffer("callback " + pkg + " " + method + " " + cast) ;
+ if (args != null){
+ for (int i = 0 ; i < args.length ; i++){
+ cmdb.append(" " + ijp.SerializeObject(args[i])) ;
+ }
+ }
+ return cmdb.toString() ;
+ }
+
+
+ void ClearResponse(){
+ response = null ;
+ response_set = false ;
+ }
+
+
+ Object GetResponse(){
+ return response ;
+ }
+
+
+ synchronized Object WaitForResponse(Thread t){
+ while (! response_set){
+ try {
+ InlineJavaUtils.debug(3, "waiting for callback response in " + t.getName() + "...") ;
+ wait() ;
+ }
+ catch (InterruptedException ie){
+ // Do nothing, return and wait() some more...
+ }
+ }
+ InlineJavaUtils.debug(3, "got callback response") ;
+ Object resp = response ;
+ response = null ;
+ response_set = false ;
+ return resp ;
+ }
+
+
+ synchronized void NotifyOfResponse(Thread t){
+ InlineJavaUtils.debug(3, "notifying that callback has completed in " + t.getName()) ;
+ notify() ;
+ }
+
+
+ synchronized void Process() throws InlineJavaException, InlineJavaPerlException {
+ Object ret = null ;
+ try {
+ InlineJavaProtocol ijp = new InlineJavaProtocol(ijs, null) ;
+ String cmd = GetCommand(ijp) ;
+ InlineJavaUtils.debug(2, "callback command: " + cmd) ;
+
+ Thread t = Thread.currentThread() ;
+ String resp = null ;
+ while (true) {
+ InlineJavaUtils.debug(3, "packet sent (callback) is " + cmd) ;
+ if (! ijs.IsJNI()){
+ // Client-server mode.
+ InlineJavaServerThread ijt = (InlineJavaServerThread)t ;
+ ijt.GetWriter().write(cmd + "\n") ;
+ ijt.GetWriter().flush() ;
+
+ resp = ijt.GetReader().readLine() ;
+ }
+ else{
+ // JNI mode
+ resp = ijs.jni_callback(cmd) ;
+ }
+ InlineJavaUtils.debug(3, "packet recv (callback) is " + resp) ;
+
+ StringTokenizer st = new StringTokenizer(resp, " ") ;
+ String c = st.nextToken() ;
+ if (c.equals("callback")){
+ boolean thrown = new Boolean(st.nextToken()).booleanValue() ;
+ String arg = st.nextToken() ;
+ InlineJavaClass ijc = new InlineJavaClass(ijs, ijp) ;
+ ret = ijc.CastArgument(java.lang.Object.class, arg) ;
+
+ if (thrown){
+ throw new InlineJavaPerlException(ret) ;
+ }
+
+ break ;
+ }
+ else{
+ // Pass it on through the regular channel...
+ InlineJavaUtils.debug(3, "packet is not callback response: " + resp) ;
+ cmd = ijs.ProcessCommand(resp, false) ;
+
+ continue ;
+ }
+ }
+ }
+ catch (IOException e){
+ throw new InlineJavaException("IO error: " + e.getMessage()) ;
+ }
+
+ response = ret ;
+ response_set = true ;
+ }
+}
diff --git a/Java/sources/org/perl/inline/java/InlineJavaCallbackQueue.java b/Java/sources/org/perl/inline/java/InlineJavaCallbackQueue.java
new file mode 100644
index 0000000..10695f5
--- /dev/null
+++ b/Java/sources/org/perl/inline/java/InlineJavaCallbackQueue.java
@@ -0,0 +1,66 @@
+package org.perl.inline.java ;
+
+import java.util.* ;
+import java.io.* ;
+
+
+/*
+ Queue for callbacks to Perl...
+*/
+class InlineJavaCallbackQueue {
+ // private InlineJavaServer ijs = InlineJavaServer.GetInstance() ;
+ private ArrayList queue = new ArrayList() ;
+ private boolean stop_loop = false ;
+
+
+ InlineJavaCallbackQueue() {
+ }
+
+
+ synchronized void EnqueueCallback(InlineJavaCallback ijc) {
+ queue.add(ijc) ;
+ notify() ;
+ }
+
+
+ synchronized private InlineJavaCallback DequeueCallback() {
+ if (queue.size() > 0){
+ return (InlineJavaCallback)queue.remove(0) ;
+ }
+ return null ;
+ }
+
+
+ synchronized InlineJavaCallback WaitForCallback(){
+ while (IsEmpty()){
+ try {
+ wait() ;
+ }
+ catch (InterruptedException ie){
+ // Do nothing, return and wait() some more...
+ }
+ }
+ return DequeueCallback() ;
+ }
+
+
+ private boolean IsEmpty(){
+ return (queue.size() == 0) ;
+ }
+
+
+ void StartLoop(){
+ stop_loop = false ;
+ }
+
+
+ synchronized void StopLoop(){
+ stop_loop = true ;
+ notify() ;
+ }
+
+
+ boolean IsLoopStopped(){
+ return stop_loop ;
+ }
+}
diff --git a/Java/sources/org/perl/inline/java/InlineJavaCastException.java b/Java/sources/org/perl/inline/java/InlineJavaCastException.java
new file mode 100644
index 0000000..b799689
--- /dev/null
+++ b/Java/sources/org/perl/inline/java/InlineJavaCastException.java
@@ -0,0 +1,7 @@
+package org.perl.inline.java ;
+
+class InlineJavaCastException extends InlineJavaException {
+ InlineJavaCastException(String m){
+ super(m) ;
+ }
+}
diff --git a/Java/sources/org/perl/inline/java/InlineJavaClass.java b/Java/sources/org/perl/inline/java/InlineJavaClass.java
new file mode 100644
index 0000000..68d3812
--- /dev/null
+++ b/Java/sources/org/perl/inline/java/InlineJavaClass.java
@@ -0,0 +1,457 @@
+package org.perl.inline.java ;
+
+import java.util.* ;
+
+
+class InlineJavaClass {
+ private InlineJavaServer ijs ;
+ private InlineJavaProtocol ijp ;
+
+
+ InlineJavaClass(InlineJavaServer _ijs, InlineJavaProtocol _ijp){
+ ijs = _ijs ;
+ ijp = _ijp ;
+ }
+
+
+ /*
+ Makes sure a class exists
+ */
+ Class ValidateClass(String name) throws InlineJavaException {
+ Class pc = FindType(name) ;
+ if (pc != null){
+ return pc ;
+ }
+
+ try {
+ Class c = Class.forName(name, true, InlineJavaServer.GetInstance().GetUserClassLoader()) ;
+ return c ;
+ }
+ catch (ClassNotFoundException e){
+ throw new InlineJavaException("Class " + name + " not found") ;
+ }
+ }
+
+ /*
+ This is the monster method that determines how to cast arguments
+ */
+ Object [] CastArguments (Class [] params, ArrayList args) throws InlineJavaException {
+ Object ret[] = new Object [params.length] ;
+
+ for (int i = 0 ; i < params.length ; i++){
+ // Here the args are all strings or objects (or undef)
+ // we need to match them to the prototype.
+ Class p = params[i] ;
+ InlineJavaUtils.debug(4, "arg " + String.valueOf(i) + " of signature is " + p.getName()) ;
+
+ ret[i] = CastArgument(p, (String)args.get(i)) ;
+ }
+
+ return ret ;
+ }
+
+
+ /*
+ This is the monster method that determines how to cast arguments
+ */
+ Object CastArgument (Class p, String argument) throws InlineJavaException {
+ Object ret = null ;
+
+ ArrayList tokens = new ArrayList() ;
+ StringTokenizer st = new StringTokenizer(argument, ":") ;
+ for (int j = 0 ; st.hasMoreTokens() ; j++){
+ tokens.add(j, st.nextToken()) ;
+ }
+ if (tokens.size() == 1){
+ tokens.add(1, "") ;
+ }
+ String type = (String)tokens.get(0) ;
+
+ // We need to separate the primitive types from the
+ // reference types.
+ boolean num = ClassIsNumeric(p) ;
+ if ((num)||(ClassIsString(p))){
+ Class ap = p ;
+ if (ap == java.lang.Number.class){
+ InlineJavaUtils.debug(4, "specializing java.lang.Number to java.lang.Double") ;
+ ap = java.lang.Double.class ;
+ }
+
+ if (type.equals("undef")){
+ if (num){
+ InlineJavaUtils.debug(4, "args is undef -> forcing to " + ap.getName() + " 0") ;
+ ret = ijp.CreateObject(ap, new Object [] {"0"}, new Class [] {String.class}) ;
+ InlineJavaUtils.debug(4, " result is " + ret.toString()) ;
+ }
+ else{
+ ret = null ;
+ InlineJavaUtils.debug(4, "args is undef -> forcing to " + ap.getName() + " " + ret) ;
+ InlineJavaUtils.debug(4, " result is " + ret) ;
+ }
+ }
+ else if (type.equals("scalar")){
+ String arg = ijp.Decode((String)tokens.get(1)) ;
+ InlineJavaUtils.debug(4, "args is scalar -> forcing to " + ap.getName()) ;
+ try {
+ ret = ijp.CreateObject(ap, new Object [] {arg}, new Class [] {String.class}) ;
+ InlineJavaUtils.debug(4, " result is " + ret.toString()) ;
+ }
+ catch (NumberFormatException e){
+ throw new InlineJavaCastException("Can't convert " + arg + " to " + ap.getName()) ;
+ }
+ }
+ else{
+ throw new InlineJavaCastException("Can't convert reference to " + p.getName()) ;
+ }
+ }
+ else if (ClassIsBool(p)){
+ if (type.equals("undef")){
+ InlineJavaUtils.debug(4, "args is undef -> forcing to bool false") ;
+ ret = new Boolean("false") ;
+ InlineJavaUtils.debug(4, " result is " + ret.toString()) ;
+ }
+ else if (type.equals("scalar")){
+ String arg = ijp.Decode(((String)tokens.get(1)).toLowerCase()) ;
+ InlineJavaUtils.debug(4, "args is scalar -> forcing to bool") ;
+ if ((arg.equals(""))||(arg.equals("0"))){
+ arg = "false" ;
+ }
+ else{
+ arg = "true" ;
+ }
+ ret = new Boolean(arg) ;
+ InlineJavaUtils.debug(4, " result is " + ret.toString()) ;
+ }
+ else{
+ throw new InlineJavaCastException("Can't convert reference to " + p.getName()) ;
+ }
+ }
+ else if (ClassIsChar(p)){
+ if (type.equals("undef")){
+ InlineJavaUtils.debug(4, "args is undef -> forcing to char '\0'") ;
+ ret = new Character('\0') ;
+ InlineJavaUtils.debug(4, " result is " + ret.toString()) ;
+ }
+ else if (type.equals("scalar")){
+ String arg = ijp.Decode((String)tokens.get(1)) ;
+ InlineJavaUtils.debug(4, "args is scalar -> forcing to char") ;
+ char c = '\0' ;
+ if (arg.length() == 1){
+ c = arg.toCharArray()[0] ;
+ }
+ else if (arg.length() > 1){
+ throw new InlineJavaCastException("Can't convert " + arg + " to " + p.getName()) ;
+ }
+ ret = new Character(c) ;
+ InlineJavaUtils.debug(4, " result is " + ret.toString()) ;
+ }
+ else{
+ throw new InlineJavaCastException("Can't convert reference to " + p.getName()) ;
+ }
+ }
+ else {
+ InlineJavaUtils.debug(4, "class " + p.getName() + " is reference") ;
+ // We know that what we expect here is a real object
+ if (type.equals("undef")){
+ InlineJavaUtils.debug(4, "args is undef -> forcing to null") ;
+ ret = null ;
+ }
+ else if (type.equals("scalar")){
+ // Here if we need a java.lang.Object.class, it's probably
+ // because we can store anything, so we use a String object.
+ if (p == java.lang.Object.class){
+ String arg = ijp.Decode((String)tokens.get(1)) ;
+ ret = arg ;
+ }
+ else{
+ throw new InlineJavaCastException("Can't convert primitive type to " + p.getName()) ;
+ }
+ }
+ else{
+ // We need an object and we got an object...
+ InlineJavaUtils.debug(4, "class " + p.getName() + " is reference") ;
+
+ String c_name = (String)tokens.get(1) ;
+ String objid = (String)tokens.get(2) ;
+
+ Class c = ValidateClass(c_name) ;
+
+ if (DoesExtend(c, p) > -1){
+ InlineJavaUtils.debug(4, " " + c.getName() + " is a kind of " + p.getName()) ;
+ // get the object from the hash table
+ int id = Integer.parseInt(objid) ;
+ Object o = ijs.GetObject(id) ;
+ ret = o ;
+ }
+ else{
+ throw new InlineJavaCastException("Can't cast a " + c.getName() + " to a " + p.getName()) ;
+ }
+ }
+ }
+
+ return ret ;
+ }
+
+
+ /*
+ Returns the number of levels that separate a from b
+ */
+ int DoesExtend(Class a, Class b){
+ return DoesExtend(a, b, 0) ;
+ }
+
+
+ int DoesExtend(Class a, Class b, int level){
+ InlineJavaUtils.debug(4, "checking if " + a.getName() + " extends " + b.getName()) ;
+
+ if (a == b){
+ return level ;
+ }
+
+ Class parent = a.getSuperclass() ;
+ if (parent != null){
+ InlineJavaUtils.debug(4, " parent is " + parent.getName()) ;
+ int ret = DoesExtend(parent, b, level + 1) ;
+ if (ret != -1){
+ return ret ;
+ }
+ }
+
+ // Maybe b is an interface a implements it?
+ Class inter[] = a.getInterfaces() ;
+ for (int i = 0 ; i < inter.length ; i++){
+ InlineJavaUtils.debug(4, " interface is " + inter[i].getName()) ;
+ int ret = DoesExtend(inter[i], b, level + 1) ;
+ if (ret != -1){
+ return ret ;
+ }
+ }
+
+ return -1 ;
+ }
+
+
+ /*
+ Finds the wrapper class for the passed primitive type.
+ */
+ Class FindWrapper (Class p){
+ Class [] list = {
+ byte.class,
+ short.class,
+ int.class,
+ long.class,
+ float.class,
+ double.class,
+ boolean.class,
+ char.class,
+ } ;
+ Class [] listw = {
+ java.lang.Byte.class,
+ java.lang.Short.class,
+ java.lang.Integer.class,
+ java.lang.Long.class,
+ java.lang.Float.class,
+ java.lang.Double.class,
+ java.lang.Boolean.class,
+ java.lang.Character.class,
+ } ;
+
+ for (int i = 0 ; i < list.length ; i++){
+ if (p == list[i]){
+ return listw[i] ;
+ }
+ }
+
+ return p ;
+ }
+
+
+ /*
+ Finds the primitive type class for the passed primitive type name.
+ */
+ Class FindType (String name){
+ String [] list = {
+ "byte",
+ "short",
+ "int",
+ "long",
+ "float",
+ "double",
+ "boolean",
+ "char",
+ "B",
+ "S",
+ "I",
+ "J",
+ "F",
+ "D",
+ "Z",
+ "C",
+ } ;
+ Class [] listc = {
+ byte.class,
+ short.class,
+ int.class,
+ long.class,
+ float.class,
+ double.class,
+ boolean.class,
+ char.class,
+ byte.class,
+ short.class,
+ int.class,
+ long.class,
+ float.class,
+ double.class,
+ boolean.class,
+ char.class,
+ } ;
+
+ for (int i = 0 ; i < list.length ; i++){
+ if (name.equals(list[i])){
+ return listc[i] ;
+ }
+ }
+
+ return null ;
+ }
+
+
+ boolean ClassIsPrimitive (Class p){
+ String name = p.getName() ;
+
+ if ((ClassIsNumeric(p))||(ClassIsString(p))||(ClassIsChar(p))||(ClassIsBool(p))){
+ return true ;
+ }
+
+ InlineJavaUtils.debug(4, "class " + name + " is reference") ;
+ return false ;
+ }
+
+
+ /*
+ Determines if class is of numerical type.
+ */
+ boolean ClassIsNumeric (Class p){
+ String name = p.getName() ;
+
+ Class [] list = {
+ java.lang.Byte.class,
+ java.lang.Short.class,
+ java.lang.Integer.class,
+ java.lang.Long.class,
+ java.lang.Float.class,
+ java.lang.Double.class,
+ java.lang.Number.class,
+ byte.class,
+ short.class,
+ int.class,
+ long.class,
+ float.class,
+ double.class,
+ } ;
+
+ for (int i = 0 ; i < list.length ; i++){
+ if (p == list[i]){
+ InlineJavaUtils.debug(4, "class " + name + " is primitive numeric") ;
+ return true ;
+ }
+ }
+
+ return false ;
+ }
+
+
+ /*
+ Class is String or StringBuffer
+ */
+ boolean ClassIsString (Class p){
+ String name = p.getName() ;
+
+ Class [] list = {
+ java.lang.String.class,
+ java.lang.StringBuffer.class,
+ } ;
+
+ for (int i = 0 ; i < list.length ; i++){
+ if (p == list[i]){
+ InlineJavaUtils.debug(4, "class " + name + " is primitive string") ;
+ return true ;
+ }
+ }
+
+ return false ;
+ }
+
+
+ /*
+ Class is Char
+ */
+ boolean ClassIsChar (Class p){
+ String name = p.getName() ;
+
+ Class [] list = {
+ java.lang.Character.class,
+ char.class,
+ } ;
+
+ for (int i = 0 ; i < list.length ; i++){
+ if (p == list[i]){
+ InlineJavaUtils.debug(4, "class " + name + " is primitive char") ;
+ return true ;
+ }
+ }
+
+ return false ;
+ }
+
+
+ /*
+ Class is Bool
+ */
+ boolean ClassIsBool (Class p){
+ String name = p.getName() ;
+
+ Class [] list = {
+ java.lang.Boolean.class,
+ boolean.class,
+ } ;
+
+ for (int i = 0 ; i < list.length ; i++){
+ if (p == list[i]){
+ InlineJavaUtils.debug(4, "class " + name + " is primitive bool") ;
+ return true ;
+ }
+ }
+
+ return false ;
+ }
+
+
+ /*
+ Determines if a class is not of a primitive type or of a
+ wrapper class.
+ */
+ boolean ClassIsReference (Class p){
+ String name = p.getName() ;
+
+ if (ClassIsPrimitive(p)){
+ return false ;
+ }
+
+ InlineJavaUtils.debug(4, "class " + name + " is reference") ;
+
+ return true ;
+ }
+
+ boolean ClassIsArray (Class p){
+ String name = p.getName() ;
+
+ if ((ClassIsReference(p))&&(name.startsWith("["))){
+ InlineJavaUtils.debug(4, "class " + name + " is array") ;
+ return true ;
+ }
+
+ return false ;
+ }
+}
\ No newline at end of file
diff --git a/Java/sources/org/perl/inline/java/InlineJavaException.java b/Java/sources/org/perl/inline/java/InlineJavaException.java
new file mode 100644
index 0000000..7e2f3cd
--- /dev/null
+++ b/Java/sources/org/perl/inline/java/InlineJavaException.java
@@ -0,0 +1,7 @@
+package org.perl.inline.java ;
+
+public class InlineJavaException extends Exception {
+ public InlineJavaException(String s) {
+ super(s) ;
+ }
+}
diff --git a/Java/sources/org/perl/inline/java/InlineJavaInvocationTargetException.java b/Java/sources/org/perl/inline/java/InlineJavaInvocationTargetException.java
new file mode 100644
index 0000000..768bb1a
--- /dev/null
+++ b/Java/sources/org/perl/inline/java/InlineJavaInvocationTargetException.java
@@ -0,0 +1,15 @@
+package org.perl.inline.java ;
+
+class InlineJavaInvocationTargetException extends InlineJavaException {
+ private Throwable t ;
+
+
+ InlineJavaInvocationTargetException(String m, Throwable _t){
+ super(m) ;
+ t = _t ;
+ }
+
+ Throwable GetThrowable(){
+ return t ;
+ }
+}
diff --git a/Java/sources/org/perl/inline/java/InlineJavaPerlCaller.java b/Java/sources/org/perl/inline/java/InlineJavaPerlCaller.java
new file mode 100644
index 0000000..67a802f
--- /dev/null
+++ b/Java/sources/org/perl/inline/java/InlineJavaPerlCaller.java
@@ -0,0 +1,115 @@
+package org.perl.inline.java ;
+
+import java.util.* ;
+import java.io.* ;
+
+
+/*
+ Callback to Perl...
+*/
+public class InlineJavaPerlCaller {
+ private InlineJavaServer ijs = InlineJavaServer.GetInstance() ;
+ private Thread creator = null ;
+ static private HashMap thread_callback_queues = new HashMap() ;
+
+
+ /*
+ Only thread that communicate with Perl are allowed to create PerlCallers because
+ this is where we get the thread that needs to be notified when the callbacks come in.
+ */
+ public InlineJavaPerlCaller() throws InlineJavaException {
+ Thread t = Thread.currentThread() ;
+ if (ijs.IsThreadPerlContact(t)){
+ creator = t ;
+ }
+ else{
+ throw new InlineJavaException("InlineJavaPerlCaller objects can only be created by threads that communicate directly with Perl") ;
+ }
+ }
+
+
+ public Object CallPerl(String pkg, String method, Object args[]) throws InlineJavaException, InlineJavaPerlException {
+ return CallPerl(pkg, method, args, null) ;
+ }
+
+
+ public Object CallPerl(String pkg, String method, Object args[], String cast) throws InlineJavaException, InlineJavaPerlException {
+ InlineJavaCallback ijc = new InlineJavaCallback(pkg, method, args, cast) ;
+ return CallPerl(ijc) ;
+ }
+
+
+ public Object CallPerl(InlineJavaCallback ijc) throws InlineJavaException, InlineJavaPerlException {
+ Thread t = Thread.currentThread() ;
+ if (t == creator){
+ ijc.Process() ;
+ return ijc.GetResponse() ;
+ }
+ else{
+ // Enqueue the callback into the creator thread's queue and notify it
+ // that there is some work for him.
+ ijc.ClearResponse() ;
+ InlineJavaCallbackQueue q = GetQueue(creator) ;
+ InlineJavaUtils.debug(3, "enqueing callback for processing for " + creator.getName() + " in " + t.getName() + "...") ;
+ q.EnqueueCallback(ijc) ;
+ InlineJavaUtils.debug(3, "notifying that a callback request is available for " + creator.getName() + " in " + t.getName()) ;
+
+ // Now we must wait until the callback is processed and get back the result...
+ return ijc.WaitForResponse(t) ;
+ }
+ }
+
+
+ public void StartCallbackLoop() throws InlineJavaException, InlineJavaPerlException {
+ Thread t = Thread.currentThread() ;
+ if (! ijs.IsThreadPerlContact(t)){
+ throw new InlineJavaException("InlineJavaPerlCaller.StartCallbackLoop() can only be called by threads that communicate directly with Perl") ;
+ }
+
+ InlineJavaCallbackQueue q = GetQueue(t) ;
+ q.StartLoop() ;
+ while (! q.IsLoopStopped()){
+ InlineJavaUtils.debug(3, "waiting for callback request in " + t.getName() + "...") ;
+ InlineJavaCallback ijc = q.WaitForCallback() ;
+ InlineJavaUtils.debug(3, "waiting for callback request finished " + t.getName() + "...") ;
+ InlineJavaUtils.debug(3, "processing callback request in " + t.getName() + "...") ;
+ // The callback object can be null if the wait() is interrupted by StopCallbackLoop
+ if (ijc != null){
+ ijc.Process() ;
+ ijc.NotifyOfResponse(t) ;
+ }
+ }
+ }
+
+
+ public void StopCallbackLoop() throws InlineJavaException {
+ Thread t = Thread.currentThread() ;
+ InlineJavaCallbackQueue q = GetQueue(creator) ;
+ InlineJavaUtils.debug(3, "interrupting callback loop for " + creator.getName() + " in " + t.getName()) ;
+ q.StopLoop() ;
+ }
+
+
+ /*
+ Here the prototype accepts Threads because the JNI thread
+ calls this method also.
+ */
+ static synchronized void AddThread(Thread t){
+ thread_callback_queues.put(t, new InlineJavaCallbackQueue()) ;
+ }
+
+
+ static synchronized void RemoveThread(InlineJavaServerThread t){
+ thread_callback_queues.remove(t) ;
+ }
+
+
+ static private InlineJavaCallbackQueue GetQueue(Thread t) throws InlineJavaException {
+ InlineJavaCallbackQueue q = (InlineJavaCallbackQueue)thread_callback_queues.get(t) ;
+
+ if (q == null){
+ throw new InlineJavaException("Can't find thread " + t.getName() + "!") ;
+ }
+ return q ;
+ }
+}
diff --git a/Java/sources/org/perl/inline/java/InlineJavaPerlException.java b/Java/sources/org/perl/inline/java/InlineJavaPerlException.java
new file mode 100644
index 0000000..a8bf663
--- /dev/null
+++ b/Java/sources/org/perl/inline/java/InlineJavaPerlException.java
@@ -0,0 +1,19 @@
+package org.perl.inline.java ;
+
+
+public class InlineJavaPerlException extends Exception {
+ private Object obj ;
+
+
+ public InlineJavaPerlException(Object o){
+ obj = o ;
+ }
+
+ public Object GetObject(){
+ return obj ;
+ }
+
+ public String GetString(){
+ return (String)obj ;
+ }
+}
diff --git a/Java/sources/org/perl/inline/java/InlineJavaProtocol.java b/Java/sources/org/perl/inline/java/InlineJavaProtocol.java
new file mode 100644
index 0000000..b16eea6
--- /dev/null
+++ b/Java/sources/org/perl/inline/java/InlineJavaProtocol.java
@@ -0,0 +1,661 @@
+package org.perl.inline.java ;
+
+import java.util.* ;
+import java.lang.reflect.* ;
+
+
+/*
+ This is where most of the work of Inline Java is done. Here determine
+ the request type and then we proceed to serve it.
+*/
+class InlineJavaProtocol {
+ private InlineJavaServer ijs ;
+ private InlineJavaClass ijc ;
+ private InlineJavaArray ija ;
+ private String cmd ;
+ private String response = null ;
+
+ static private HashMap member_cache = new HashMap() ;
+
+ InlineJavaProtocol(InlineJavaServer _ijs, String _cmd) {
+ ijs = _ijs ;
+ ijc = new InlineJavaClass(ijs, this) ;
+ ija = new InlineJavaArray(ijc) ;
+
+ cmd = _cmd ;
+ }
+
+
+ /*
+ Starts the analysis of the command line
+ */
+ void Do() throws InlineJavaException {
+ StringTokenizer st = new StringTokenizer(cmd, " ") ;
+ String c = st.nextToken() ;
+
+ if (c.equals("call_method")){
+ CallJavaMethod(st) ;
+ }
+ else if (c.equals("set_member")){
+ SetJavaMember(st) ;
+ }
+ else if (c.equals("get_member")){
+ GetJavaMember(st) ;
+ }
+ else if (c.equals("add_classpath")){
+ AddClassPath(st) ;
+ }
+ else if (c.equals("server_type")){
+ ServerType(st) ;
+ }
+ else if (c.equals("report")){
+ Report(st) ;
+ }
+ else if (c.equals("isa")){
+ IsA(st) ;
+ }
+ else if (c.equals("create_object")){
+ CreateJavaObject(st) ;
+ }
+ else if (c.equals("delete_object")){
+ DeleteJavaObject(st) ;
+ }
+ else if (c.equals("obj_cnt")){
+ ObjectCount(st) ;
+ }
+ else if (c.equals("die")){
+ InlineJavaUtils.debug(1, "received a request to die...") ;
+ System.exit(0) ;
+ }
+ else {
+ throw new InlineJavaException("Unknown command " + c) ;
+ }
+ }
+
+ /*
+ Returns a report on the Java classes, listing all public methods
+ and members
+ */
+ void Report(StringTokenizer st) throws InlineJavaException {
+ StringBuffer pw = new StringBuffer() ;
+
+ StringTokenizer st2 = new StringTokenizer(st.nextToken(), ":") ;
+ st2.nextToken() ;
+
+ StringTokenizer st3 = new StringTokenizer(Decode(st2.nextToken()), " ") ;
+
+ ArrayList class_list = new ArrayList() ;
+ while (st3.hasMoreTokens()){
+ String c = st3.nextToken() ;
+ class_list.add(class_list.size(), c) ;
+ }
+
+ for (int i = 0 ; i < class_list.size() ; i++){
+ String name = (String)class_list.get(i) ;
+ Class c = ijc.ValidateClass(name) ;
+
+ InlineJavaUtils.debug(3, "reporting for " + c) ;
+
+ pw.append("class " + c.getName() + "\n") ;
+ Constructor constructors[] = c.getConstructors() ;
+ Method methods[] = c.getMethods() ;
+ Field fields[] = c.getFields() ;
+
+ int pub = c.getModifiers() & Modifier.PUBLIC ;
+ if (pub != 0){
+ // If the class is public and has no constructors,
+ // we provide a default no-arg constructors.
+ if (c.getDeclaredConstructors().length == 0){
+ String noarg_sign = InlineJavaUtils.CreateSignature(new Class [] {}) ;
+ pw.append("constructor " + noarg_sign + "\n") ;
+ }
+ }
+ for (int j = 0 ; j < constructors.length ; j++){
+ Constructor x = constructors[j] ;
+ Class params[] = x.getParameterTypes() ;
+ String sign = InlineJavaUtils.CreateSignature(params) ;
+ Class decl = x.getDeclaringClass() ;
+ pw.append("constructor " + sign + "\n") ;
+ }
+
+ for (int j = 0 ; j < methods.length ; j++){
+ Method x = methods[j] ;
+ String stat = (Modifier.isStatic(x.getModifiers()) ? " static " : " instance ") ;
+ String sign = InlineJavaUtils.CreateSignature(x.getParameterTypes()) ;
+ Class decl = x.getDeclaringClass() ;
+ pw.append("method" + stat + decl.getName() + " " + x.getName() + sign + "\n") ;
+ }
+
+ for (int j = 0 ; j < fields.length ; j++){
+ Field x = fields[(InlineJavaUtils.ReverseMembers() ? (fields.length - 1 - j) : j)] ;
+ String stat = (Modifier.isStatic(x.getModifiers()) ? " static " : " instance ") ;
+ Class decl = x.getDeclaringClass() ;
+ Class type = x.getType() ;
+ pw.append("field" + stat + decl.getName() + " " + x.getName() + " " + type.getName() + "\n") ;
+ }
+ }
+
+ SetResponse(pw.toString()) ;
+ }
+
+
+ void AddClassPath(StringTokenizer st) throws InlineJavaException {
+ while (st.hasMoreTokens()){
+ String path = Decode(st.nextToken()) ;
+ InlineJavaServer.GetInstance().GetUserClassLoader().AddClassPath(path) ;
+ }
+ SetResponse(null) ;
+ }
+
+
+ void ServerType(StringTokenizer st) throws InlineJavaException {
+ SetResponse(ijs.GetType()) ;
+ }
+
+
+ void IsA(StringTokenizer st) throws InlineJavaException {
+ String class_name = st.nextToken() ;
+ Class c = ijc.ValidateClass(class_name) ;
+
+ String is_it_a = st.nextToken() ;
+ Class d = ijc.ValidateClass(is_it_a) ;
+
+ SetResponse(new Integer(ijc.DoesExtend(c, d))) ;
+ }
+
+
+ void ObjectCount(StringTokenizer st) throws InlineJavaException {
+ SetResponse(new Integer(ijs.ObjectCount())) ;
+ }
+
+
+ /*
+ Creates a Java Object with the specified arguments.
+ */
+ void CreateJavaObject(StringTokenizer st) throws InlineJavaException {
+ String class_name = st.nextToken() ;
+ Class c = ijc.ValidateClass(class_name) ;
+
+ if (! ijc.ClassIsArray(c)){
+ ArrayList f = ValidateMethod(true, c, class_name, st) ;
+ Object p[] = (Object [])f.get(1) ;
+ Class clist[] = (Class [])f.get(2) ;
+
+ try {
+ Object o = CreateObject(c, p, clist) ;
+ SetResponse(o) ;
+ }
+ catch (InlineJavaInvocationTargetException ite){
+ Throwable t = ite.GetThrowable() ;
+ if (t instanceof InlineJavaException){
+ InlineJavaException ije = (InlineJavaException)t ;
+ throw ije ;
+ }
+ else{
+ SetResponse(new InlineJavaThrown(t)) ;
+ }
+ }
+ }
+ else{
+ // Here we send the type of array we want, but CreateArray
+ // exception the element type.
+ StringBuffer sb = new StringBuffer(class_name) ;
+ // Remove the ['s
+ while (sb.toString().startsWith("[")){
+ sb.replace(0, 1, "") ;
+ }
+ // remove the L and the ;
+ if (sb.toString().startsWith("L")){
+ sb.replace(0, 1, "") ;
+ sb.replace(sb.length() - 1, sb.length(), "") ;
+ }
+
+ Class ec = ijc.ValidateClass(sb.toString()) ;
+
+ InlineJavaUtils.debug(4, "array elements: " + ec.getName()) ;
+ Object o = ija.CreateArray(ec, st) ;
+ SetResponse(o) ;
+ }
+ }
+
+
+ /*
+ Calls a Java method
+ */
+ void CallJavaMethod(StringTokenizer st) throws InlineJavaException {
+ int id = Integer.parseInt(st.nextToken()) ;
+
+ String class_name = st.nextToken() ;
+ Object o = null ;
+ if (id > 0){
+ o = ijs.GetObject(id) ;
+
+ // Use the class of the object
+ class_name = o.getClass().getName() ;
+ }
+
+ Class c = ijc.ValidateClass(class_name) ;
+ String method = st.nextToken() ;
+
+ if ((ijc.ClassIsArray(c))&&(method.equals("getLength"))){
+ int length = Array.getLength(o) ;
+ SetResponse(new Integer(length)) ;
+ }
+ else{
+ ArrayList f = ValidateMethod(false, c, method, st) ;
+ Method m = (Method)f.get(0) ;
+ String name = m.getName() ;
+ Object p[] = (Object [])f.get(1) ;
+
+ try {
+ Object ret = InlineJavaServer.GetInstance().GetUserClassLoader().invoke(m, o, p) ;
+ SetResponse(ret) ;
+ }
+ catch (IllegalAccessException e){
+ throw new InlineJavaException("You are not allowed to invoke method " + name + " in class " + class_name + ": " + e.getMessage()) ;
+ }
+ catch (IllegalArgumentException e){
+ throw new InlineJavaException("Arguments for method " + name + " in class " + class_name + " are incompatible: " + e.getMessage()) ;
+ }
+ catch (InvocationTargetException e){
+ Throwable t = e.getTargetException() ;
+ String type = t.getClass().getName() ;
+ String msg = t.getMessage() ;
+ InlineJavaUtils.debug(1, "method " + name + " in class " + class_name + " threw exception " + type + ": " + msg) ;
+ if (t instanceof InlineJavaException){
+ InlineJavaException ije = (InlineJavaException)t ;
+ throw ije ;
+ }
+ else{
+ SetResponse(new InlineJavaThrown(t)) ;
+ }
+ }
+ }
+ }
+
+
+ /*
+ Sets a Java member variable
+ */
+ void SetJavaMember(StringTokenizer st) throws InlineJavaException {
+ int id = Integer.parseInt(st.nextToken()) ;
+
+ String class_name = st.nextToken() ;
+ Object o = null ;
+ if (id > 0){
+ o = ijs.GetObject(id) ;
+
+ // Use the class of the object
+ class_name = o.getClass().getName() ;
+ }
+
+ Class c = ijc.ValidateClass(class_name) ;
+ String member = st.nextToken() ;
+
+ if (ijc.ClassIsArray(c)){
+ int idx = Integer.parseInt(member) ;
+ Class type = ijc.ValidateClass(st.nextToken()) ;
+ String arg = st.nextToken() ;
+
+ String msg = "For array of type " + c.getName() + ", element " + member + ": " ;
+ try {
+ Object elem = ijc.CastArgument(type, arg) ;
+ InlineJavaServer.GetInstance().GetUserClassLoader().array_set(o, idx, elem) ;
+ SetResponse(null) ;
+ }
+ catch (InlineJavaCastException e){
+ throw new InlineJavaCastException(msg + e.getMessage()) ;
+ }
+ catch (InlineJavaException e){
+ throw new InlineJavaException(msg + e.getMessage()) ;
+ }
+ }
+ else{
+ ArrayList fl = ValidateMember(c, member, st) ;
+ Field f = (Field)fl.get(0) ;
+ String name = f.getName() ;
+ Object p = (Object)fl.get(1) ;
+
+ try {
+ InlineJavaServer.GetInstance().GetUserClassLoader().set(f, o, p) ;
+ SetResponse(null) ;
+ }
+ catch (IllegalAccessException e){
+ throw new InlineJavaException("You are not allowed to set member " + name + " in class " + class_name + ": " + e.getMessage()) ;
+ }
+ catch (IllegalArgumentException e){
+ throw new InlineJavaException("Argument for member " + name + " in class " + class_name + " is incompatible: " + e.getMessage()) ;
+ }
+ }
+ }
+
+
+ /*
+ Gets a Java member variable
+ */
+ void GetJavaMember(StringTokenizer st) throws InlineJavaException {
+ int id = Integer.parseInt(st.nextToken()) ;
+
+ String class_name = st.nextToken() ;
+ Object o = null ;
+ if (id > 0){
+ o = ijs.GetObject(id) ;
+
+ // Use the class of the object
+ class_name = o.getClass().getName() ;
+ }
+
+ Class c = ijc.ValidateClass(class_name) ;
+ String member = st.nextToken() ;
+
+ if (ijc.ClassIsArray(c)){
+ int idx = Integer.parseInt(member) ;
+ Object ret = InlineJavaServer.GetInstance().GetUserClassLoader().array_get(o, idx) ;
+ SetResponse(ret) ;
+ }
+ else{
+ ArrayList fl = ValidateMember(c, member, st) ;
+
+ Field f = (Field)fl.get(0) ;
+ String name = f.getName() ;
+ try {
+ Object ret = InlineJavaServer.GetInstance().GetUserClassLoader().get(f, o) ;
+ SetResponse(ret) ;
+ }
+ catch (IllegalAccessException e){
+ throw new InlineJavaException("You are not allowed to set member " + name + " in class " + class_name + ": " + e.getMessage()) ;
+ }
+ catch (IllegalArgumentException e){
+ throw new InlineJavaException("Argument for member " + name + " in class " + class_name + " is incompatible: " + e.getMessage()) ;
+ }
+ }
+ }
+
+
+ /*
+ Deletes a Java object
+ */
+ void DeleteJavaObject(StringTokenizer st) throws InlineJavaException {
+ int id = Integer.parseInt(st.nextToken()) ;
+
+ Object o = ijs.DeleteObject(id) ;
+
+ SetResponse(null) ;
+ }
+
+
+ /*
+ Creates a Java Object with the specified arguments.
+ */
+ Object CreateObject(Class p, Object args[], Class proto[]) throws InlineJavaException {
+ p = ijc.FindWrapper(p) ;
+
+ String name = p.getName() ;
+ Object ret = null ;
+ try {
+ ret = InlineJavaServer.GetInstance().GetUserClassLoader().create(p, args, proto) ;
+ }
+ catch (NoSuchMethodException e){
+ throw new InlineJavaException("Constructor for class " + name + " with signature " + InlineJavaUtils.CreateSignature(proto) + " not found: " + e.getMessage()) ;
+ }
+ catch (InstantiationException e){
+ throw new InlineJavaException("You are not allowed to instantiate object of class " + name + ": " + e.getMessage()) ;
+ }
+ catch (IllegalAccessException e){
+ throw new InlineJavaException("You are not allowed to instantiate object of class " + name + " using the constructor with signature " + InlineJavaUtils.CreateSignature(proto) + ": " + e.getMessage()) ;
+ }
+ catch (IllegalArgumentException e){
+ throw new InlineJavaException("Arguments to constructor for class " + name + " with signature " + InlineJavaUtils.CreateSignature(proto) + " are incompatible: " + e.getMessage()) ;
+ }
+ catch (InvocationTargetException e){
+ Throwable t = e.getTargetException() ;
+ String type = t.getClass().getName() ;
+ String msg = t.getMessage() ;
+ throw new InlineJavaInvocationTargetException(
+ "Constructor for class " + name + " with signature " + InlineJavaUtils.CreateSignature(proto) + " threw exception " + type + ": " + msg,
+ t) ;
+ }
+
+ return ret ;
+ }
+
+
+ /*
+ Makes sure a method exists
+ */
+ ArrayList ValidateMethod(boolean constructor, Class c, String name, StringTokenizer st) throws InlineJavaException {
+ ArrayList ret = new ArrayList() ;
+
+ // Extract signature
+ String signature = st.nextToken() ;
+
+ // Extract the arguments
+ ArrayList args = new ArrayList() ;
+ while (st.hasMoreTokens()){
+ args.add(args.size(), st.nextToken()) ;
+ }
+
+ String key = c.getName() + "." + name + signature ;
+ ArrayList ml = new ArrayList() ;
+ Class params[] = null ;
+
+ Member cached = (Member)member_cache.get(key) ;
+ if (cached != null){
+ InlineJavaUtils.debug(3, "method was cached") ;
+ ml.add(ml.size(), cached) ;
+ }
+ else{
+ Member ma[] = (constructor ? (Member [])c.getConstructors() : (Member [])c.getMethods()) ;
+ for (int i = 0 ; i < ma.length ; i++){
+ Member m = ma[i] ;
+
+ if (m.getName().equals(name)){
+ InlineJavaUtils.debug(3, "found a " + name + (constructor ? " constructor" : " method")) ;
+
+ if (constructor){
+ params = ((Constructor)m).getParameterTypes() ;
+ }
+ else{
+ params = ((Method)m).getParameterTypes() ;
+ }
+
+ // Now we check if the signatures match
+ String sign = InlineJavaUtils.CreateSignature(params, ",") ;
+ InlineJavaUtils.debug(3, sign + " = " + signature + "?") ;
+
+ if (signature.equals(sign)){
+ InlineJavaUtils.debug(3, "has matching signature " + sign) ;
+ ml.add(ml.size(), m) ;
+ member_cache.put(key, m) ;
+ break ;
+ }
+ }
+ }
+ }
+
+ // Now we got a list of matching methods (actually 0 or 1).
+ // We have to figure out which one we will call.
+ if (ml.size() == 0){
+ // Nothing matched. Maybe we got a default constructor
+ if ((constructor)&&(signature.equals("()"))){
+ ret.add(0, null) ;
+ ret.add(1, new Object [] {}) ;
+ ret.add(2, new Class [] {}) ;
+ }
+ else{
+ throw new InlineJavaException(
+ (constructor ? "Constructor " : "Method ") +
+ name + " for class " + c.getName() + " with signature " +
+ signature + " not found") ;
+ }
+ }
+ else if (ml.size() == 1){
+ // Now we need to force the arguments received to match
+ // the methods signature.
+ Member m = (Member)ml.get(0) ;
+ if (constructor){
+ params = ((Constructor)m).getParameterTypes() ;
+ }
+ else{
+ params = ((Method)m).getParameterTypes() ;
+ }
+
+ String msg = "In method " + name + " of class " + c.getName() + ": " ;
+ try {
+ ret.add(0, m) ;
+ ret.add(1, ijc.CastArguments(params, args)) ;
+ ret.add(2, params) ;
+ }
+ catch (InlineJavaCastException e){
+ throw new InlineJavaCastException(msg + e.getMessage()) ;
+ }
+ catch (InlineJavaException e){
+ throw new InlineJavaException(msg + e.getMessage()) ;
+ }
+ }
+
+ return ret ;
+ }
+
+
+ /*
+ Makes sure a member exists
+ */
+ ArrayList ValidateMember(Class c, String name, StringTokenizer st) throws InlineJavaException {
+ ArrayList ret = new ArrayList() ;
+
+ // Extract member type
+ String type = st.nextToken() ;
+
+ // Extract the argument
+ String arg = st.nextToken() ;
+
+ String key = type + " " + c.getName() + "." + name ;
+ ArrayList fl = new ArrayList() ;
+ Class param = null ;
+
+ Member cached = (Member)member_cache.get(key) ;
+ if (cached != null){
+ InlineJavaUtils.debug(3, "member was cached") ;
+ fl.add(fl.size(), cached) ;
+ }
+ else {
+ Field fa[] = c.getFields() ;
+ for (int i = 0 ; i < fa.length ; i++){
+ Field f = fa[(InlineJavaUtils.ReverseMembers() ? (fa.length - 1 - i) : i)] ;
+
+ if (f.getName().equals(name)){
+ InlineJavaUtils.debug(3, "found a " + name + " member") ;
+
+ param = f.getType() ;
+ String t = param.getName() ;
+ if (type.equals(t)){
+ InlineJavaUtils.debug(3, "has matching type " + t) ;
+ fl.add(fl.size(), f) ;
+ }
+ }
+ }
+ }
+
+ // Now we got a list of matching members.
+ // We have to figure out which one we will call.
+ if (fl.size() == 0){
+ throw new InlineJavaException(
+ "Member " + name + " of type " + type + " for class " + c.getName() +
+ " not found") ;
+ }
+ else {
+ // Now we need to force the arguments received to match
+ // the methods signature.
+
+ // If we have more that one, we use the last one, which is the most
+ // specialized
+ Field f = (Field)fl.get(fl.size() - 1) ;
+ member_cache.put(key, f) ;
+ param = f.getType() ;
+
+ String msg = "For member " + name + " of class " + c.getName() + ": " ;
+ try {
+ ret.add(0, f) ;
+ ret.add(1, ijc.CastArgument(param, arg)) ;
+ ret.add(2, param) ;
+ }
+ catch (InlineJavaCastException e){
+ throw new InlineJavaCastException(msg + e.getMessage()) ;
+ }
+ catch (InlineJavaException e){
+ throw new InlineJavaException(msg + e.getMessage()) ;
+ }
+ }
+
+ return ret ;
+ }
+
+
+ /*
+ This sets the response that will be returned to the Perl
+ script
+ */
+ void SetResponse (Object o) throws InlineJavaException {
+ response = "ok " + SerializeObject(o) ;
+ }
+
+
+ String SerializeObject(Object o) throws InlineJavaException {
+ if (o == null){
+ return "undef:" ;
+ }
+ else if ((ijc.ClassIsNumeric(o.getClass()))||(ijc.ClassIsChar(o.getClass()))||(ijc.ClassIsString(o.getClass()))){
+ return "scalar:" + Encode(o.toString()) ;
+ }
+ else if (ijc.ClassIsBool(o.getClass())){
+ String b = o.toString() ;
+ return "scalar:" + Encode((b.equals("true") ? "1" : "0")) ;
+ }
+ else {
+ // Here we need to register the object in order to send
+ // it back to the Perl script.
+ boolean thrown = false ;
+ if (o instanceof InlineJavaThrown){
+ thrown = true ;
+ o = ((InlineJavaThrown)o).GetThrowable() ;
+ }
+ int id = ijs.PutObject(o) ;
+ return "object:" + (thrown ? "1" : "0") + ":" + String.valueOf(id) +
+ ":" + o.getClass().getName() ;
+ }
+ }
+
+
+ String Decode(String s){
+ StringTokenizer st = new StringTokenizer(s, ".") ;
+ StringBuffer sb = new StringBuffer() ;
+ while (st.hasMoreTokens()){
+ String ss = st.nextToken() ;
+ char c = (char)Integer.parseInt(ss) ;
+ sb.append(new String(new char [] {c})) ;
+ }
+
+ return sb.toString() ;
+ }
+
+
+ String Encode(String s){
+ char c[] = new char[s.length()] ;
+ s.getChars(0, c.length, c, 0) ;
+ StringBuffer sb = new StringBuffer() ;
+ for (int i = 0 ; i < c.length ; i++){
+ if (i > 0){
+ sb.append(".") ;
+ }
+ sb.append((int)c[i]) ;
+ }
+
+ return sb.toString() ;
+ }
+
+
+ String GetResponse(){
+ return response ;
+ }
+}
diff --git a/Java/sources/org/perl/inline/java/InlineJavaServer.java b/Java/sources/org/perl/inline/java/InlineJavaServer.java
new file mode 100644
index 0000000..0ed1829
--- /dev/null
+++ b/Java/sources/org/perl/inline/java/InlineJavaServer.java
@@ -0,0 +1,275 @@
+package org.perl.inline.java ;
+
+import java.net.* ;
+import java.io.* ;
+import java.util.* ;
+
+
+/*
+ This is the server that will answer all the requests for and on Java
+ objects.
+*/
+public class InlineJavaServer {
+ private static InlineJavaServer instance = null ;
+ private int port = 0 ;
+ private boolean shared_jvm = false ;
+ private boolean priv = false ;
+
+ private InlineJavaUserClassLoader ijucl = null ;
+ private HashMap thread_objects = new HashMap() ;
+ private int objid = 1 ;
+ private boolean jni = false ;
+ private Thread creator = null ;
+ private int thread_count = 0 ;
+
+
+ // This constructor is used in JNI mode
+ private InlineJavaServer(int d){
+ init(d) ;
+
+ jni = true ;
+ AddThread(creator) ;
+ }
+
+
+ // This constructor is used in server mode
+ private InlineJavaServer(String[] argv){
+ init(new Integer(argv[0]).intValue()) ;
+
+ jni = false ;
+ port = Integer.parseInt(argv[1]) ;
+ shared_jvm = new Boolean(argv[2]).booleanValue() ;
+ priv = new Boolean(argv[3]).booleanValue() ;
+
+ ServerSocket ss = null ;
+ try {
+ ss = new ServerSocket(port) ;
+ }
+ catch (IOException e){
+ InlineJavaUtils.Fatal("Can't open server socket on port " + String.valueOf(port) +
+ ": " + e.getMessage()) ;
+ }
+
+ while (true){
+ try {
+ String name = "IJST-#" + thread_count++ ;
+ InlineJavaServerThread ijt = new InlineJavaServerThread(name, this, ss.accept(),
+ (priv ? new InlineJavaUserClassLoader() : ijucl)) ;
+ ijt.start() ;
+ if (! shared_jvm){
+ try {
+ ijt.join() ;
+ }
+ catch (InterruptedException e){
+ }
+ break ;
+ }
+ }
+ catch (IOException e){
+ System.err.println("IO error: " + e.getMessage()) ;
+ System.err.flush() ;
+ }
+ }
+
+ System.exit(1) ;
+ }
+
+
+ private void init(int debug){
+ instance = this ;
+ creator = Thread.currentThread() ;
+ InlineJavaUtils.debug = debug ;
+
+ ijucl = new InlineJavaUserClassLoader() ;
+ }
+
+
+ static InlineJavaServer GetInstance(){
+ if (instance == null){
+ InlineJavaUtils.Fatal("No instance of InlineJavaServer has been created!") ;
+ }
+
+ return instance ;
+ }
+
+
+ InlineJavaUserClassLoader GetUserClassLoader(){
+ Thread t = Thread.currentThread() ;
+ if (t instanceof InlineJavaServerThread){
+ return ((InlineJavaServerThread)t).GetUserClassLoader() ;
+ }
+ else{
+ return ijucl ;
+ }
+ }
+
+
+ String GetType(){
+ return (shared_jvm ? "shared" : "private") ;
+ }
+
+
+ boolean IsJNI(){
+ return jni ;
+ }
+
+
+ /*
+ Since this function is also called from the JNI XS extension,
+ it's best if it doesn't throw any exceptions.
+ */
+ String ProcessCommand(String cmd) {
+ return ProcessCommand(cmd, true) ;
+ }
+
+
+ String ProcessCommand(String cmd, boolean addlf) {
+ InlineJavaUtils.debug(3, "packet recv is " + cmd) ;
+
+ String resp = null ;
+ if (cmd != null){
+ InlineJavaProtocol ijp = new InlineJavaProtocol(this, cmd) ;
+ try {
+ ijp.Do() ;
+ InlineJavaUtils.debug(3, "packet sent is " + ijp.GetResponse()) ;
+ resp = ijp.GetResponse() ;
+ }
+ catch (InlineJavaException e){
+ String err = "error scalar:" + ijp.Encode(e.getMessage()) ;
+ InlineJavaUtils.debug(3, "packet sent is " + err) ;
+ resp = err ;
+ }
+ }
+ else{
+ if (! shared_jvm){
+ // Probably connection dropped...
+ InlineJavaUtils.debug(1, "lost connection with client in single client mode. Exiting.") ;
+ System.exit(1) ;
+ }
+ else{
+ InlineJavaUtils.debug(1, "lost connection with client in shared JVM mode.") ;
+ return null ;
+ }
+ }
+
+ if (addlf){
+ resp = resp + "\n" ;
+ }
+
+ return resp ;
+ }
+
+
+ /*
+ This method really has no business here, but for historical reasons
+ it will remain here.
+ */
+ native String jni_callback(String cmd) ;
+
+
+ boolean IsThreadPerlContact(Thread t){
+ if (((jni)&&(t == creator))||
+ ((! jni)&&(t instanceof InlineJavaServerThread))){
+ return true ;
+ }
+
+ return false ;
+ }
+
+
+ synchronized Object GetObject(int id) throws InlineJavaException {
+ Object o = null ;
+ HashMap h = (HashMap)thread_objects.get(Thread.currentThread()) ;
+
+ if (h == null){
+ throw new InlineJavaException("Can't find thread " + Thread.currentThread().getName() + "!") ;
+ }
+ else{
+ o = h.get(new Integer(id)) ;
+ if (o == null){
+ throw new InlineJavaException("Can't find object " + id + " for thread " +Thread.currentThread().getName()) ;
+ }
+ }
+
+ return o ;
+ }
+
+
+ synchronized int PutObject(Object o) throws InlineJavaException {
+ HashMap h = (HashMap)thread_objects.get(Thread.currentThread()) ;
+
+ int id = objid ;
+ if (h == null){
+ throw new InlineJavaException("Can't find thread " + Thread.currentThread().getName() + "!") ;
+ }
+ else{
+ h.put(new Integer(objid), o) ;
+ objid++ ;
+ }
+
+ return id ;
+ }
+
+
+ synchronized Object DeleteObject(int id) throws InlineJavaException {
+ Object o = null ;
+ HashMap h = (HashMap)thread_objects.get(Thread.currentThread()) ;
+
+ if (h == null){
+ throw new InlineJavaException("Can't find thread " + Thread.currentThread().getName() + "!") ;
+ }
+ else{
+ o = h.remove(new Integer(id)) ;
+ if (o == null){
+ throw new InlineJavaException("Can't find object " + id + " for thread " + Thread.currentThread().getName()) ;
+ }
+ }
+
+ return o ;
+ }
+
+
+ synchronized int ObjectCount() throws InlineJavaException {
+ int i = -1 ;
+ HashMap h = (HashMap)thread_objects.get(Thread.currentThread()) ;
+
+ if (h == null){
+ throw new InlineJavaException("Can't find thread " + Thread.currentThread().getName() + "!") ;
+ }
+ else{
+ i = h.values().size() ;
+ }
+
+ return i ;
+ }
+
+
+ /*
+ Here the prototype accepts Threads because the JNI thread
+ calls this method also.
+ */
+ synchronized void AddThread(Thread t){
+ thread_objects.put(t, new HashMap()) ;
+ InlineJavaPerlCaller.AddThread(t) ;
+ }
+
+
+ synchronized void RemoveThread(InlineJavaServerThread t){
+ thread_objects.remove(t) ;
+ InlineJavaPerlCaller.RemoveThread(t) ;
+ }
+
+
+
+ /*
+ Startup
+ */
+ public static void main(String[] argv){
+ new InlineJavaServer(argv) ;
+ }
+
+
+ public static InlineJavaServer jni_main(int debug){
+ return new InlineJavaServer(debug) ;
+ }
+}
diff --git a/Java/sources/org/perl/inline/java/InlineJavaServerThread.java b/Java/sources/org/perl/inline/java/InlineJavaServerThread.java
new file mode 100644
index 0000000..7c0248f
--- /dev/null
+++ b/Java/sources/org/perl/inline/java/InlineJavaServerThread.java
@@ -0,0 +1,68 @@
+package org.perl.inline.java ;
+
+import java.io.* ;
+import java.net.* ;
+import java.util.* ;
+
+
+class InlineJavaServerThread extends Thread {
+ private InlineJavaServer ijs ;
+ private Socket client ;
+ private BufferedReader br ;
+ private BufferedWriter bw ;
+ private InlineJavaUserClassLoader ijucl ;
+
+
+ InlineJavaServerThread(String name, InlineJavaServer _ijs, Socket _client, InlineJavaUserClassLoader _ijucl) throws IOException {
+ super(name) ;
+ client = _client ;
+ ijs = _ijs ;
+ ijucl = _ijucl ;
+
+ br = new BufferedReader(
+ new InputStreamReader(client.getInputStream())) ;
+ bw = new BufferedWriter(
+ new OutputStreamWriter(client.getOutputStream())) ;
+ }
+
+
+ BufferedReader GetReader(){
+ return br ;
+ }
+
+
+ BufferedWriter GetWriter(){
+ return bw ;
+ }
+
+
+ InlineJavaUserClassLoader GetUserClassLoader(){
+ return ijucl ;
+ }
+
+
+ public void run(){
+ try {
+ ijs.AddThread(this) ;
+
+ while (true){
+ String cmd = br.readLine() ;
+
+ String resp = ijs.ProcessCommand(cmd) ;
+ if (resp != null){
+ bw.write(resp) ;
+ bw.flush() ;
+ }
+ else {
+ break ;
+ }
+ }
+ }
+ catch (IOException e){
+ System.err.println("IO error: " + e.getMessage()) ;
+ }
+ finally {
+ ijs.RemoveThread(this) ;
+ }
+ }
+}
diff --git a/Java/sources/org/perl/inline/java/InlineJavaThrown.java b/Java/sources/org/perl/inline/java/InlineJavaThrown.java
new file mode 100644
index 0000000..38bee49
--- /dev/null
+++ b/Java/sources/org/perl/inline/java/InlineJavaThrown.java
@@ -0,0 +1,14 @@
+package org.perl.inline.java ;
+
+
+class InlineJavaThrown {
+ Throwable t ;
+
+ InlineJavaThrown(Throwable _t){
+ t = _t ;
+ }
+
+ Throwable GetThrowable(){
+ return t ;
+ }
+}
diff --git a/Java/sources/org/perl/inline/java/InlineJavaUserClassLink.java b/Java/sources/org/perl/inline/java/InlineJavaUserClassLink.java
new file mode 100644
index 0000000..0f2d97a
--- /dev/null
+++ b/Java/sources/org/perl/inline/java/InlineJavaUserClassLink.java
@@ -0,0 +1,45 @@
+import java.util.* ;
+import java.lang.reflect.* ;
+
+
+public class InlineJavaUserClassLink {
+ public InlineJavaUserClassLink(){
+ }
+
+
+ public Object invoke(Method m, Object o, Object p[]) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+ return m.invoke(o, p) ;
+ }
+
+
+ public Object get(Field f, Object o) throws IllegalAccessException, IllegalArgumentException {
+ return f.get(o) ;
+ }
+
+
+ public void set(Field f, Object o, Object p) throws IllegalAccessException, IllegalArgumentException {
+ f.set(o, p) ;
+ }
+
+
+ public Object array_get(Object o, Integer idx){
+ return Array.get(o, idx.intValue()) ;
+ }
+
+
+ public void array_set(Object o, Integer idx, Object elem) throws IllegalArgumentException {
+ Array.set(o, idx.intValue(), elem) ;
+ }
+
+
+ public Object create(Class p, Object args[], Class proto[]) throws NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+ // This will allow usage of the default no-arg constructor
+ if (proto.length == 0){
+ return p.newInstance() ;
+ }
+ else{
+ Constructor con = (Constructor)p.getConstructor(proto) ;
+ return con.newInstance(args) ;
+ }
+ }
+}
diff --git a/Java/sources/org/perl/inline/java/InlineJavaUserClassLoader.java b/Java/sources/org/perl/inline/java/InlineJavaUserClassLoader.java
new file mode 100644
index 0000000..2b2756d
--- /dev/null
+++ b/Java/sources/org/perl/inline/java/InlineJavaUserClassLoader.java
@@ -0,0 +1,190 @@
+package org.perl.inline.java ;
+
+import java.net.* ;
+import java.util.* ;
+import java.io.* ;
+import java.lang.reflect.* ;
+
+
+/*
+ This is the ClassLoader that loads the users code. It is also
+ used to pass reflection calls to the InlineJavaUserClassLink
+ so that it will execute them.
+*/
+class InlineJavaUserClassLoader extends URLClassLoader {
+ private HashMap urls = new HashMap() ;
+
+ private Object link = null ;
+ private Method invoke = null ;
+ private Method get = null ;
+ private Method set = null ;
+ private Method array_get = null ;
+ private Method array_set = null ;
+ private Method create = null ;
+
+
+ public InlineJavaUserClassLoader(){
+ super(new URL [] {}) ;
+ }
+
+
+ public void AddClassPath(String path) throws InlineJavaException {
+ try {
+ File p = new File(path) ;
+ URL u = p.toURL() ;
+ if (urls.get(u) == null){
+ urls.put(u, "1") ;
+ addURL(u) ;
+ InlineJavaUtils.debug(2, "added " + u + " to classpath") ;
+ }
+ }
+ catch (MalformedURLException e){
+ throw new InlineJavaException("Can't add invalid classpath entry '" + path + "'") ;
+ }
+ }
+
+
+ synchronized private void check_link() throws InlineJavaException {
+ if (link == null){
+ try {
+ InlineJavaUtils.debug(1, "loading InlineJavaUserClassLink via InlineJavaUserClassLoader") ;
+ Class c = Class.forName("InlineJavaUserClassLink", true, this) ;
+ link = c.newInstance() ;
+
+ invoke = find_method(c, "invoke") ;
+ get = find_method(c, "get") ;
+ set = find_method(c, "set") ;
+ array_get = find_method(c, "array_get") ;
+ array_set = find_method(c, "array_set") ;
+ create = find_method(c, "create") ;
+ }
+ catch (Exception e){
+ throw new InlineJavaException("InlineJavaUserClassLoader can't load InlineJavaUserClassLink: invalid classpath setup (" +
+ e.getClass().getName() + ": " + e.getMessage() + ")") ;
+ }
+ }
+ }
+
+
+ private Method find_method(Class c, String name) throws InlineJavaException {
+ Method ml[] = c.getMethods() ;
+ for (int i = 0 ; i < ml.length ; i++){
+ if (ml[i].getName().equals(name)){
+ return ml[i] ;
+ }
+ }
+
+ throw new InlineJavaException("Can't find method '" + name +
+ "' in class InlineJavaUserClassLink") ;
+ }
+
+
+ private Object invoke_via_link(Method m, Object p[]) throws NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InlineJavaException {
+ try {
+ return m.invoke(link, p) ;
+ }
+ catch (IllegalAccessException e){
+ throw new InlineJavaException("Can't invoke method from class InlineJavaUserClassLink: IllegalAccessException") ;
+ }
+ catch (IllegalArgumentException e){
+ throw new InlineJavaException("Can't invoke method from class InlineJavaUserClassLink: IllegalArgumentException") ;
+ }
+ catch (InvocationTargetException e){
+ Throwable t = e.getTargetException() ;
+ if (t instanceof NoSuchMethodException){
+ throw (NoSuchMethodException)t ;
+ }
+ else if (t instanceof InstantiationException){
+ throw (InstantiationException)t ;
+ }
+ else if (t instanceof IllegalAccessException){
+ throw (IllegalAccessException)t ;
+ }
+ if (t instanceof IllegalAccessException){
+ throw (IllegalAccessException)t ;
+ }
+ else if (t instanceof IllegalArgumentException){
+ throw (IllegalArgumentException)t ;
+ }
+ else if (t instanceof InvocationTargetException){
+ throw (InvocationTargetException)t ;
+ }
+ // Not sure if this is really necessary, but...
+ else if (t instanceof RuntimeException){
+ RuntimeException re = (RuntimeException)t ;
+ throw re ;
+ }
+ else{
+ // In theory this case is impossible.
+ throw new InlineJavaException("Unexpected exception of type '" +
+ t.getClass().getName() + "': " + t.getMessage()) ;
+ }
+ }
+ }
+
+
+ public Object invoke(Method m, Object o, Object p[]) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InlineJavaException {
+ check_link() ;
+ try {
+ return invoke_via_link(invoke, new Object [] {m, o, p}) ;
+ }
+ catch (NoSuchMethodException me){/* Impossible */}
+ catch (InstantiationException ie){/* Impossible */}
+ return null ;
+ }
+
+
+ public Object get(Field f, Object o) throws IllegalAccessException, IllegalArgumentException, InlineJavaException {
+ check_link() ;
+ try {
+ return invoke_via_link(get, new Object [] {f, o}) ;
+ }
+ catch (NoSuchMethodException me){/* Impossible */}
+ catch (InstantiationException ie){/* Impossible */}
+ catch (InvocationTargetException e){/* Impossible */}
+ return null ;
+ }
+
+
+ public void set(Field f, Object o, Object p) throws IllegalAccessException, IllegalArgumentException, InlineJavaException {
+ check_link() ;
+ try {
+ invoke_via_link(set, new Object [] {f, o, p}) ;
+ }
+ catch (NoSuchMethodException me){/* Impossible */}
+ catch (InstantiationException ie){/* Impossible */}
+ catch (InvocationTargetException e){/* Impossible */}
+ }
+
+
+ public Object array_get(Object o, int idx) throws InlineJavaException {
+ check_link() ;
+ try {
+ return invoke_via_link(array_get, new Object [] {o, new Integer(idx)}) ;
+ }
+ catch (NoSuchMethodException me){/* Impossible */}
+ catch (InstantiationException ie){/* Impossible */}
+ catch (IllegalAccessException iae){/* Impossible */}
+ catch (IllegalArgumentException iae){/* Impossible */}
+ catch (InvocationTargetException e){/* Impossible */}
+ return null ;
+ }
+
+
+ public void array_set(Object o, int idx, Object elem) throws IllegalArgumentException, InlineJavaException {
+ check_link() ;
+ try {
+ invoke_via_link(array_set, new Object [] {o, new Integer(idx), elem}) ;
+ }
+ catch (NoSuchMethodException me){/* Impossible */}
+ catch (InstantiationException ie){/* Impossible */}
+ catch (IllegalAccessException iae){/* Impossible */}
+ catch (InvocationTargetException e){/* Impossible */}
+ }
+
+
+ public Object create(Class p, Object args[], Class proto[]) throws NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InlineJavaException {
+ check_link() ;
+ return invoke_via_link(create, new Object [] {p, args, proto}) ;
+ }
+}
diff --git a/Java/sources/org/perl/inline/java/InlineJavaUtils.java b/Java/sources/org/perl/inline/java/InlineJavaUtils.java
new file mode 100644
index 0000000..0459f01
--- /dev/null
+++ b/Java/sources/org/perl/inline/java/InlineJavaUtils.java
@@ -0,0 +1,56 @@
+package org.perl.inline.java ;
+
+import java.util.* ;
+
+
+/*
+ Creates a string representing a method signature
+*/
+class InlineJavaUtils {
+ static int debug = 0 ;
+
+
+ static String CreateSignature(Class param[]){
+ return CreateSignature(param, ", ") ;
+ }
+
+
+ static String CreateSignature(Class param[], String del){
+ StringBuffer ret = new StringBuffer() ;
+ for (int i = 0 ; i < param.length ; i++){
+ if (i > 0){
+ ret.append(del) ;
+ }
+ ret.append(param[i].getName()) ;
+ }
+
+ return "(" + ret.toString() + ")" ;
+ }
+
+
+ synchronized static void debug(int level, String s) {
+ if ((debug > 0)&&(debug >= level)){
+ StringBuffer sb = new StringBuffer() ;
+ for (int i = 0 ; i < level ; i++){
+ sb.append(" ") ;
+ }
+ System.err.println("[java][" + level + "]" + sb.toString() + s) ;
+ System.err.flush() ;
+ }
+ }
+
+
+ static void Fatal(String msg){
+ System.err.println(msg) ;
+ System.err.flush() ;
+ System.exit(1) ;
+ }
+
+
+ static boolean ReverseMembers() {
+ String v = System.getProperty("java.version") ;
+ boolean no_rev = ((v.startsWith("1.2"))||(v.startsWith("1.3"))) ;
+
+ return (! no_rev) ;
+ }
+}
diff --git a/MANIFEST b/MANIFEST
index 742effa..f8aef93 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -17,22 +17,22 @@ Java/JVM.pm
Java/JNI.pm
Java/JNI.xs
Java/typemap
-Java/sources/InlineJavaArray.java
-Java/sources/InlineJavaCastException.java
-Java/sources/InlineJavaClass.java
-Java/sources/InlineJavaException.java
-Java/sources/InlineJavaInvocationTargetException.java
-Java/sources/InlineJavaPerlCaller.java
-Java/sources/InlineJavaPerlException.java
-Java/sources/InlineJavaProtocol.java
-Java/sources/InlineJavaServer.java
-Java/sources/InlineJavaServerThread.java
-Java/sources/InlineJavaThrown.java
-Java/sources/InlineJavaUserClassLink.java
-Java/sources/InlineJavaUserClassLoader.java
-Java/sources/InlineJavaUtils.java
-Java/sources/InlineJavaCallback.java
-Java/sources/InlineJavaCallbackQueue.java
+Java/sources/org/perl/inline/java/InlineJavaArray.java
+Java/sources/org/perl/inline/java/InlineJavaCastException.java
+Java/sources/org/perl/inline/java/InlineJavaClass.java
+Java/sources/org/perl/inline/java/InlineJavaException.java
+Java/sources/org/perl/inline/java/InlineJavaInvocationTargetException.java
+Java/sources/org/perl/inline/java/InlineJavaPerlCaller.java
+Java/sources/org/perl/inline/java/InlineJavaPerlException.java
+Java/sources/org/perl/inline/java/InlineJavaProtocol.java
+Java/sources/org/perl/inline/java/InlineJavaServer.java
+Java/sources/org/perl/inline/java/InlineJavaServerThread.java
+Java/sources/org/perl/inline/java/InlineJavaThrown.java
+Java/sources/org/perl/inline/java/InlineJavaUserClassLink.java
+Java/sources/org/perl/inline/java/InlineJavaUserClassLoader.java
+Java/sources/org/perl/inline/java/InlineJavaUtils.java
+Java/sources/org/perl/inline/java/InlineJavaCallback.java
+Java/sources/org/perl/inline/java/InlineJavaCallbackQueue.java
t/01_init.t
t/02_primitives.t
t/03_objects.t
diff --git a/Makefile.PL b/Makefile.PL
index dbf4341..c0b4af4 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -90,12 +90,14 @@ SAVE_J2SDK
# We will now add the building of our Java files to the Makefile.
my $javac = File::Spec->catfile($jdk_dir, 'bin', 'javac' . $ext) ;
-my $jar = File::Spec->catfile($jdk_dir, 'bin', 'jar' . $ext) ;
-my $src_dir = File::Spec->catdir('Java', 'sources') ;
+my $jar = File::Spec->catfile($jdk_dir, 'bin', 'jar' . $ext) ;
+my $src_dir = File::Spec->catdir('Java', 'sources', 'org', 'perl', 'inline', 'java') ;
my $src = File::Spec->catfile($src_dir, '*.java') ;
my $obj_dir = File::Spec->catdir('Java', 'classes') ;
my $server_arch = File::Spec->catfile('Java', 'InlineJavaServer.jar') ;
my $user_arch = File::Spec->catfile('Java', 'InlineJavaUser.jar') ;
+my $src_arch = File::Spec->catfile('Java', 'InlineJavaSource.jar') ;
+
sub MY::top_targets {
my $this = shift ;
@@ -116,7 +118,7 @@ sub MY::postamble {
# Added by Inline::Java installation
java ::
\@\$(MKPATH) $obj_dir
- "$javac" -d $obj_dir $src
+ "$javac" -g -d $obj_dir $src
"$jar" cf $server_arch -C $obj_dir org
"$jar" cf $user_arch -C $obj_dir InlineJavaUserClassLink.class
MAKE
diff --git a/README b/README
index 9ccd91b..d830943 100644
--- a/README
+++ b/README
@@ -74,6 +74,7 @@ Inline::Java version 0.44 is a major upgrade that includes:
+ Callbacks from multiple threads are now supported
+ Refactored (again...) studying/.jdat/cache stuff
+ Added PRIVATE mode for use with SHARED_JVM
++ Added DEBUGGER mode that launches jdb
+ Fixed memory leak in JNI coded (patch submitted by Dave Blob)
Inline::Java version 0.43 is a minor upgrade that includes:
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/libinline-java-perl.git
More information about the Pkg-perl-cvs-commits
mailing list