[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