[libinline-java-perl] 215/398: First step towards re-factoring.

Jonas Smedegaard dr at jones.dk
Thu Feb 26 11:43:05 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 3ae432211c1f37588d692325c3fe0e22c01625b9
Author: patrick_leb <>
Date:   Sat Mar 15 02:57:04 2003 +0000

    First step towards re-factoring.
---
 Java.pm                                            | 673 ++++++---------------
 Java.pod                                           |   6 +-
 Java/Array.pm                                      | 112 +---
 Java/Callback.pm                                   |  70 +--
 Java/Class.pm                                      | 462 +-------------
 Java/Init.pm                                       | 486 ---------------
 Java/JNI.pm                                        |   2 +-
 Java/JVM.pm                                        |  15 +-
 Java/Makefile.PL                                   |  77 +--
 Java/Object.pm                                     |  10 +-
 Java/Portable.pm                                   |  75 ++-
 Java/Protocol.pm                                   | 665 ++------------------
 Java/sources/InlineJavaArray.java                  |  98 +++
 Java/sources/InlineJavaCastException.java          |   5 +
 Java/sources/InlineJavaClass.java                  | 455 ++++++++++++++
 Java/sources/InlineJavaException.java              |   5 +
 .../InlineJavaInvocationTargetException.java       |  13 +
 Java/sources/InlineJavaPerlCaller.java             |  19 +
 Java/sources/InlineJavaPerlException.java          |  21 +
 .../InlineJavaProtocol.java}                       | 506 ++--------------
 Java/sources/InlineJavaServer.java                 | 288 +++++++++
 Java/sources/InlineJavaServerThread.java           |  48 ++
 Java/sources/InlineJavaTest.java                   |   8 +
 Java/sources/InlineJavaThrown.java                 |  11 +
 Java/sources/InlineJavaUserClassLoader.java        |  20 +
 Java/sources/InlineJavaUtils.java                  |  47 ++
 MANIFEST                                           |   1 -
 Makefile.PL                                        | 121 +++-
 TODO                                               |   4 +
 t/01_init.t                                        |   6 +-
 t/no_const.class                                   | Bin 231 -> 231 bytes
 t/types.class                                      | Bin 489 -> 15 bytes
 32 files changed, 1536 insertions(+), 2793 deletions(-)

diff --git a/Java.pm b/Java.pm
index db46841..71fb12b 100644
--- a/Java.pm
+++ b/Java.pm
@@ -7,7 +7,7 @@ package Inline::Java ;
 
 use strict ;
 
-$Inline::Java::VERSION = '0.34' ;
+$Inline::Java::VERSION = '0.40' ;
 
 
 # DEBUG is set via the DEBUG config
@@ -24,12 +24,10 @@ require Inline ;
 use Carp ;
 use Config ;
 use File::Copy ;
+use File::Spec ;
 use Cwd ;
 use Data::Dumper ;
 
-use IO::Socket ;
-use File::Spec ;
-
 use Inline::Java::Portable ;
 use Inline::Java::Class ;
 use Inline::Java::Object ;
@@ -37,8 +35,9 @@ use Inline::Java::Array ;
 use Inline::Java::Protocol ;
 use Inline::Java::Callback ;
 # Must be last.
-use Inline::Java::Init ;
 use Inline::Java::JVM ;
+# Our default J2SK
+require File::Spec->catfile('Java', 'DefaultJ2SDK.pl') ;
 
 
 # This is set when the script is over.
@@ -53,6 +52,10 @@ my $JVM = undef ;
 my $INLINES = {} ;
 
 
+# Add the directory where our jar file is to the classpath
+$ENV{CLASSPATH} = Inline::Java::Portable::make_classpath(get_jar()) ;
+
+
 # This stuff is to control the termination of the Java Interpreter
 sub done {
 	my $signal = shift ;
@@ -71,9 +74,7 @@ sub done {
 	}
 
 	shutdown_JVM() ;
-	
 	Inline::Java::debug(1, "exiting with $ec") ;
-
 	CORE::exit($ec) ;
 }
 
@@ -112,131 +113,87 @@ sub register {
 sub validate {
 	my $o = shift ;
 
-	if (! exists($o->{ILSM}->{PORT})){
-		$o->{ILSM}->{PORT} = 7890 ;
-	}
-	if (! exists($o->{ILSM}->{STARTUP_DELAY})){
-		$o->{ILSM}->{STARTUP_DELAY} = 15 ;
-	}
-	if (! exists($o->{ILSM}->{SHARED_JVM})){
-		$o->{ILSM}->{SHARED_JVM} = 0 ;
-	}
-	if (! exists($o->{ILSM}->{DEBUG})){
-		$o->{ILSM}->{DEBUG} = 0 ;
-	}
-	if (! exists($o->{ILSM}->{JNI})){
-		$o->{ILSM}->{JNI} = 0 ;
-	}
-	if (! exists($o->{ILSM}->{EMBEDDED_JNI})){
-		$o->{ILSM}->{EMBEDDED_JNI} = 0 ;
-	}
-	if (! exists($o->{ILSM}->{CLASSPATH})){
-		$o->{ILSM}->{CLASSPATH} = '' ;
-	}
-	if (! exists($o->{ILSM}->{WARN_METHOD_SELECT})){
-		$o->{ILSM}->{WARN_METHOD_SELECT} = '' ;
-	}
-	if (! exists($o->{ILSM}->{AUTOSTUDY})){
-		$o->{ILSM}->{AUTOSTUDY} = 0 ;
-	}
+	# This might not print since debug is set further down...
+	Inline::Java::debug(1, "Starting validate.") ;
+	
+	my $jdk = Inline::Java::get_default_j2sdk() ;
+	my %opts = @_ ;
+	$o->set_option('DEBUG',					0,		'i', 1, \%opts) ;
+	$o->set_option('J2SDK',					$jdk,	's', 1, \%opts) ;
+	$o->set_option('CLASSPATH',				'',		's', 1, \%opts) ;
 
-	while (@_) {
-		my ($key, $value) = (shift, shift) ;
-		if ($key eq 'BIN'){
-		    $o->{ILSM}->{$key} = $value ;
-		}
-		elsif ($key eq 'CLASSPATH'){
-		    $o->{ILSM}->{$key} = $value ;
-		}
-		elsif ($key eq 'WARN_METHOD_SELECT'){
-		    $o->{ILSM}->{$key} = $value ;
-		}
-		elsif (
-			($key eq 'PORT')||
-			($key eq 'STARTUP_DELAY')){
+	$o->set_option('PORT',					7890,	'i', 1, \%opts) ;
+	$o->set_option('STARTUP_DELAY',			15,		'i', 1, \%opts) ;
+	$o->set_option('SHARED_JVM',			0,		'b', 1, \%opts) ;
+	$o->set_option('JNI',					0,		'b', 1, \%opts) ;
+	$o->set_option('EMBEDDED_JNI',			0,		'b', 1, \%opts) ;
 
-			if ($value !~ /^\d+$/){
-				croak "config '$key' must be an integer" ;
-			}
-			if (! $value){
-				croak "config '$key' can't be zero" ;
-			}
-			$o->{ILSM}->{$key} = $value ;
-		}
-		elsif ($key eq 'SHARED_JVM'){
-			$o->{ILSM}->{$key} = $value ;
-		}
-		elsif ($key eq 'DEBUG'){
-			$o->{ILSM}->{$key} = $value ;
-			$Inline::Java::DEBUG = $value ;
-		}
-		elsif ($key eq 'JNI'){
-			$o->{ILSM}->{$key} = $value ;
-		}
-		elsif ($key eq 'AUTOSTUDY'){
-			$o->{ILSM}->{$key} = $value ;
-		}
-		elsif ($key eq 'STUDY'){
-			$o->{ILSM}->{$key} = $o->check_config_array(
-				$key, $value,
-				"Java class names") ;
-		}
-	}
+	$o->set_option('WARN_METHOD_SELECT',	0,		'b', 1, \%opts) ;
+	$o->set_option('STUDY',					undef,	'a', 0, \%opts) ;
+	$o->set_option('AUTOSTUDY',				0,		'b', 1, \%opts) ;
 
-	if (defined($ENV{PERL_INLINE_JAVA_DEBUG})){
-		$Inline::Java::DEBUG = $ENV{PERL_INLINE_JAVA_DEBUG} ;
+	my @left_overs = keys(%opts) ;
+	if (scalar(@left_overs)){
+		croak "'$left_overs[0]' is not a valid configuration option for Inline::Java" ;
 	}
-	$Inline::Java::DEBUG = int($Inline::Java::DEBUG) ;
 
-	if (defined($ENV{PERL_INLINE_JAVA_JNI})){
-		$o->{ILSM}->{JNI} = $ENV{PERL_INLINE_JAVA_JNI} ;
-	}
-	
-	if (defined($ENV{PERL_INLINE_JAVA_EMBEDDED_JNI})){
-		$o->{ILSM}->{EMBEDDED_JNI} = $ENV{PERL_INLINE_JAVA_EMBEDDED_JNI} ;
-	}
+	# Now for the post processing
+	$Inline::Java::DEBUG = $o->get_java_config('DEBUG') ;
 
 	# Embedded JNI turns on regular JNI
-	if ($o->{ILSM}->{EMBEDDED_JNI}){
-		$o->{ILSM}->{JNI} = $o->{ILSM}->{EMBEDDED_JNI} ;
-	}
-
-	if (defined($ENV{PERL_INLINE_JAVA_SHARED_JVM})){
-		$o->{ILSM}->{SHARED_JVM} = $ENV{PERL_INLINE_JAVA_SHARED_JVM} ;
+	if ($o->get_java_config('EMBEDDED_JNI')){
+		$o->set_java_config('JNI', 1) ;
 	}
 
-	if (($o->{ILSM}->{JNI})&&($o->{ILSM}->{SHARED_JVM})){
+	if (($o->get_java_config('JNI'))&&($o->get_java_config('SHARED_JVM'))){
 		croak("You can't use the 'SHARED_JVM' option in 'JNI' mode") ;
 	}
 
-	$o->set_java_bin() ;
-
-	if ($o->{ILSM}->{JNI}){
+	if ($o->get_java_config('JNI')){
 		require Inline::Java::JNI ;
 	}
 
+	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" ;
+	}
+
 	Inline::Java::debug(1, "validate done.") ;
 }
 
 
-sub check_config_array {
+sub set_option {
 	my $o = shift ;
-	my $key = shift ;
-	my $value = shift ;
+	my $name = shift ;
+	my $default = shift ;
+	my $type = shift ;
+	my $env_or = shift ;
+	my $opts = shift ;
 	my $desc = shift ;
 
-	if (ref($value) eq 'ARRAY'){
-		foreach my $c (@{$value}){
-			if (ref($c)){
-				croak "config '$key' must be an array of $desc" ;
-			}
+	if (! exists($o->{ILSM}->{$name})){
+		my $val = undef ;
+		if (($env_or)&&(exists($ENV{"PERL_INLINE_JAVA_$name"}))){
+			$val = $ENV{"PERL_INLINE_JAVA_$name"} || '' ;
 		}
-	}
-	else{
-		croak "config '$key' must be an array of $desc" ;
+		elsif (exists($opts->{$name})){
+			$val = $opts->{$name} || '' ;
+		}
+		else{
+			$val = $default ;
+		}
+
+		if ($type eq 'b'){
+			$val = ($val ? 1 : 0) ;
+		}
+		elsif ($type eq 'i'){
+			$val = int($val) ;
+		}
+
+		$o->set_java_config($name, $val) ;
 	}
 
-	return $value ;
+	delete $opts->{$name} ;
 }
 
 
@@ -248,101 +205,30 @@ sub get_java_config {
 }
 
 
-# In theory we shouldn't need to use this, but it seems
-# it's not all accessible by the API yet.
-sub get_config {
+sub set_java_config {
 	my $o = shift ;
 	my $param = shift ;
+	my $value = shift ;
 
-	if (defined($param)){
-		return $o->{CONFIG}->{$param} ;
-	}
-	else{
-		return %{$o->{CONFIG}} ;
-	}
+	return $o->{ILSM}->{$param} = $value ;
 }
 
 
-sub get_api {
+# In theory we shouldn't need to use this, but it seems
+# it's not all accessible by the API yet.
+sub get_config {
 	my $o = shift ;
 	my $param = shift ;
 
-	return $o->{API}->{$param} ;
+	return $o->{CONFIG}->{$param} ;
 }
 
 
-sub set_java_bin {
-	my $o = shift ;
-
-	my $cjb = $o->{ILSM}->{BIN} ;
-	my $ejb = $ENV{PERL_INLINE_JAVA_BIN} ;
-	if ($cjb){
-		return $o->find_java_bin([$cjb]) ;
-	}
-	elsif ($ejb) {
-		$o->{ILSM}->{BIN} = $ejb ;
-		return $o->find_java_bin([$ejb]) ;
-	}
-
-	# Java binaries are assumed to be in $ENV{PATH} ;
-	return $o->find_java_bin() ;
-}
-
-
-sub find_java_bin {
-	my $o = shift ;
-	my $paths = shift ;
-
-	my $java =  "java" . portable("EXE_EXTENSION") ;
-	my $javac = "javac" . portable("EXE_EXTENSION") ;
-
-	my $path = $o->find_file_in_path([$java, $javac], $paths) ;
-	if (defined($path)){
-		$o->{ILSM}->{BIN} = $path ;
-	}
-	else{
-		croak
-			"Can't locate your java binaries ('$java' and '$javac'). Please set one of the following to the proper directory:\n" .
-			"  - The BIN config option;\n" .
-			"  - The PERL_INLINE_JAVA_BIN environment variable;\n" .
-			"  - The PATH environment variable.\n" ;
-	}
-}
-
-
-sub find_file_in_path {
+sub get_api {
 	my $o = shift ;
-	my $files = shift ;
-	my $paths = shift ;
-
-	if (! defined($paths)){
-		$paths = [File::Spec->path()] ;
-	}
-
-	Inline::Java::debug_obj($paths) ;
-
-	foreach my $p (@{$paths}){
-		$p =~ s/^\s+// ;
-		$p =~ s/\s+$// ;
-		Inline::Java::debug(4, "path element: $p") ;
-		if ($p !~ /^\s*$/){
-			my $found = 0 ;
-			foreach my $file (@{$files}){
-				my $f = File::Spec->catfile($p, $file) ;
-				Inline::Java::debug(4, " candidate: $f\n") ;
-
-				if (-f $f){
-					Inline::Java::debug(4, " found file $file in $p") ;
-					$found++ ;
-				}
-			}
-			if ($found == scalar(@{$files})){	
-				return $p ;
-			}
-		}
-	}
+	my $param = shift ;
 
-	return undef ;
+	return $o->{API}->{$param} ;
 }
 
 
@@ -350,139 +236,85 @@ sub find_file_in_path {
 sub build {
 	my $o = shift ;
 
-	if ($o->{ILSM}->{built}){
+	if ($o->get_java_config('built')){
 		return ;
 	}
 
-	my $code = $o->get_api('code') ;
-	my $study_only = ($code =~ /^(STUDY|SERVER)$/) ;
-
-	$o->write_java($study_only, $code) ;
-	$o->compile($study_only) ;
-
-	$o->{ILSM}->{built} = 1 ;
-}
-
+	Inline::Java::debug(1, "Starting build.") ;
 
-# Writes the java code.
-sub write_java {
-	my $o = shift ;
-	my $study_only = shift ;
-	my $code = shift ;
-
-	my $build_dir = $o->get_api('build_dir') ;
-	my $modfname = $o->get_api('modfname') ;
-
-	Inline::Java::Portable::mkpath($o, $build_dir) ;
-
-	if (! $study_only){
-		my $p = File::Spec->catfile($build_dir, "$modfname.java") ;
-		open(Inline::Java::JAVA, ">$p") or
-			croak "Can't open $p: $!" ;
-		Inline::Java::Init::DumpUserJavaCode(\*Inline::Java::JAVA, $code) ;
-		close(Inline::Java::JAVA) ;
+	# Grab and untaint the current directory
+	my $cwd = Cwd::cwd() ;
+	if ($o->get_config('UNTAINT')){
+		($cwd) = $cwd =~ /(.*)/ ;
 	}
 
-	my $p = File::Spec->catfile($build_dir, "InlineJavaServer.java") ;
-	open(Inline::Java::JAVA, ">$p") or
-		croak "Can't open $p: $!" ;
-	Inline::Java::Init::DumpServerJavaCode(\*Inline::Java::JAVA) ;
-	close(Inline::Java::JAVA) ;
-
-	$p = File::Spec->catfile($build_dir, "InlineJavaPerlCaller.java") ;
-	open(Inline::Java::JAVA, ">$p") or
-		croak "Can't open $p: $!" ;
-	Inline::Java::Init::DumpCallbackJavaCode(\*Inline::Java::JAVA) ;
-	close(Inline::Java::JAVA) ;
-
-	Inline::Java::debug(1, "write_java done.") ;
-}
-
-
-# Run the build process.
-sub compile {
-	my $o = shift ;
-	my $study_only = shift ;
-
+	# Create the build dir and go there
 	my $build_dir = $o->get_api('build_dir') ;
-	my $modpname = $o->get_api('modpname') ;
-	my $modfname = $o->get_api('modfname') ;
-	my $suffix = $o->get_api('suffix') ;
-	my $install_lib = $o->get_api('install_lib') ;
-
-	my $install = File::Spec->catdir($install_lib, "auto", $modpname) ;
+	$o->mkpath($build_dir) ;
+	chdir $build_dir ;
 
-	Inline::Java::Portable::mkpath($o, $install) ;
-	$o->set_classpath($install) ;
+	my $code = $o->get_api('code') ;
+	my $study_only = ($code =~ /^(STUDY|SERVER)$/) ;
+	my $source = ($study_only ? '' : $o->get_api('modfname') . ".java") ;
+	my $install_dir = File::Spec->catdir($o->get_api('install_lib'), 
+		'auto', $o->get_api('modpname')) ;
+	$o->mkpath($install_dir) ;
+
+	if ($source){
+		# Dump the source code...
+		open(Inline::Java::JAVA, ">$source") or
+			croak "Can't open $source: $!" ;
+		print Inline::Java::JAVA $code ;
+		close(Inline::Java::JAVA) ;
 
-	my $javac = File::Spec->catfile($o->{ILSM}->{BIN}, 
+		# ... and compile it.
+		my $javac = File::Spec->catfile($o->get_java_config('J2SDK'), 'bin', 
 		"javac" . portable("EXE_EXTENSION")) ;
+		my $redir = portable("IO_REDIR") ;
 
-	my $predir = portable("IO_REDIR") ;
-
-	my $cwd = Cwd::cwd() ;
-	if ($o->get_config('UNTAINT')){
-		($cwd) = $cwd =~ /(.*)/ ;
-	}
-
-	my $source = ($study_only ? '' : "$modfname.java") ;
-
-	# When we run the commands, we quote them because in WIN32 you need it if
-	# the programs are in directories which contain spaces. Unfortunately, in
-	# WIN9x, when you quote a command, it masks it's exit value, and 0 is always
-	# returned. Therefore a command failure is not detected.
-	# copy_classes will take care of checking whether there are actually files
-	# to be copied, and if not will exit the script.
-	foreach my $cmd (
-		"\"$javac\" InlineJavaServer.java $source > cmd.out $predir",
-		["copy_classes", $o, $install],
-		["touch_file", $o, File::Spec->catfile($install, "$modfname.$suffix")],
-		) {
-
-		if ($cmd){
-
-			chdir $build_dir ;
-			if (ref($cmd)){
-				Inline::Java::debug_obj($cmd) ;
-				my $func = shift @{$cmd} ;
-				my @args = @{$cmd} ;
-
-				Inline::Java::debug(3, "$func" . "(" . join(", ", @args) . ")") ;
-
-				no strict 'refs' ;
-				my $ret = $func->(@args) ;
-				if ($ret){
-					croak $ret ;
-				}
+		my $cmd = "\"$javac\" -d \"$install_dir\" $source > cmd.out $redir" ;
+		if ($o->get_config('UNTAINT')){
+			($cmd) = $cmd =~ /(.*)/ ;
+		}
+		Inline::Java::debug(2, "$cmd") ;
+		my $res = system($cmd) ;
+		$res and do {
+			croak $o->compile_error_msg($cmd) ;
+		} ;
+
+		# When we run the commands, we quote them because in WIN32 you need it if
+		# the programs are in directories which contain spaces. Unfortunately, in
+		# WIN9x, when you quote a command, it masks it's exit value, and 0 is always
+		# returned. Therefore a command failure is not detected.
+		# We need to take care of checking whether there are actually files
+		# to be copied, and if not will exit the script.
+		if (portable('COMMAND_COM')){
+			my @flist= Inline::Java::Portable::find_classes_in_dir($install_dir) ;
+		 	if (! scalar(@flist)){
+				croak "No class files produced. Previous command failed under command.com?" ;
 			}
-			else{
-				if ($o->get_config('UNTAINT')){
-					($cmd) = $cmd =~ /(.*)/ ;
+		 	foreach my $file (@flist){
+				if (! (-s $file)){
+					croak "File $file has size zero. Previous command failed under command.com?" ;
 				}
-
-				Inline::Java::debug(3, "$cmd") ;
-				my $res = system($cmd) ;
-				$res and do {
-					croak $o->compile_error_msg($cmd, $cwd) ;
-				} ;
 			}
-
-			chdir $cwd ;
 		}
 	}
 
+	# Go back and clean up
+	chdir $cwd ;
 	if ($o->get_api('cleanup')){
-		Inline::Java::Portable::rmpath($o, '', $build_dir) ;
+		$o->rmpath('', $build_dir) ;
 	}
 
-	Inline::Java::debug(1, "compile done.") ;
+	$o->set_java_config('built', 1) ;
+	Inline::Java::debug(1, "build done.") ;
 }
 
 
 sub compile_error_msg {
 	my $o = shift ;
 	my $cmd = shift ;
-	my $cwd = shift ;
 
 	my $build_dir = $o->get_api('build_dir') ;
 	my $error = '' ;
@@ -511,78 +343,29 @@ MSG
 }
 
 
-sub copy_classes {
-	my $o = shift ;
-	my $install = shift ;
-
-	my $build_dir = $o->get_api('build_dir') ;
-	my $modpname = $o->get_api('modpname') ;
-	my $install_lib = $o->get_api('install_lib') ;
-
-	my $src_dir = $build_dir ;
-	my $dest_dir = $install ;
-
-	my @flist = Inline::Java::Portable::find_classes_in_dir(".") ;
-	if (portable('COMMAND_COM')){
-		if (! scalar(@flist)){
-			croak "No files to copy. Previous command failed under command.com?" ;
-		}
-		foreach my $file (@flist){
-			if (! (-s $file)){
-				croak "File $file has size zero. Previous command failed under command.com?" ;
-			}
-		}
-	}
-
-	foreach my $file (@flist){
-		if ($o->get_config('UNTAINT')){
-			($file) = $file =~ /(.*)/ ;
-		}
-		my $f = File::Spec->catfile($src_dir, $file) ;
-		my $t = File::Spec->catfile($dest_dir, $file) ;
-		Inline::Java::debug(4, "copy_classes: $file, $t") ;
-		if (! File::Copy::copy($file, $t)){
-			return "Can't copy $f to $t: $!" ;
-		}
-	}
-
-	return '' ;
-}
-
-
-sub touch_file {
-	my $o = shift ;
-	my $file = shift ;
-
-	if (! open(Inline::Java::TOUCH, ">$file")){
-		croak "Can't create file $file" ;
-	}
-	close(Inline::Java::TOUCH) ;
-
-	return '' ;
-}
-
-
 # Load and Run the Java Code.
 sub load {
 	my $o = shift ;
 
-	if ($o->{ILSM}->{loaded}){
+	if ($o->get_java_config('loaded')){
 		return ;
 	}
 
-	my $install_lib = $o->get_api('install_lib') ;
-	my $modfname = $o->get_api('modfname') ;
-	my $modpname = $o->get_api('modpname') ;
-	my $install = File::Spec->catdir($install_lib, "auto", $modpname) ;
+	Inline::Java::debug(1, "Starting load.") ;
 
-	# Make sure the default options are set.
-	# $o->_validate(1, $o->get_config()) ;
+	my $modfname = $o->get_api('modfname') ;
+	my $install_dir = File::Spec->catdir($o->get_api('install_lib'), 
+		'auto', $o->get_api('modpname')) ;
 
 	# If the JVM is not running, we need to start it here.
+	my $cp = $ENV{CLASSPATH} ;
+	my @cp = make_classpath() ;
 	if (! $JVM){
-		$o->set_classpath($install) ;
+		$ENV{CLASSPATH} = '' ;
+		$ENV{CLASSPATH} = make_classpath(get_jar()) ;
 		$JVM = new Inline::Java::JVM($o) ;
+	
+		# Add classpath entries + install to the JVM
 
 		my $pc = new Inline::Java::Protocol(undef, $o) ;
 		my $st = $pc->ServerType() ;
@@ -591,6 +374,9 @@ sub load {
 			croak "JVM type mismatch on port " . $o->get_java_config('PORT') ;
 		}
 	}
+	else{
+		# Add $install entry to the JVM.
+	}
 
 	# Add our Inline object to the list.
 	my $prev_o = $INLINES->{$modfname} ;
@@ -604,83 +390,17 @@ sub load {
 
 	$INLINES->{$modfname} = $o ;
 
-	$o->_study() ;
-	if ((defined($o->{ILSM}->{STUDY}))&&(scalar($o->{ILSM}->{STUDY}))){
-		$o->_study($o->{ILSM}->{STUDY}) ;
-	}
-
-	$o->{ILSM}->{loaded} = 1 ;
-}
-
-
-# This function builds the CLASSPATH environment variable for the JVM
-sub set_classpath {
-	my $o = shift ;
-	my $path = shift ;
-
-	my @list = () ;
-	if (defined($ENV{CLASSPATH})){
-		push @list, $ENV{CLASSPATH} ;
-	}
-	if (defined($o->{ILSM}->{CLASSPATH})){
-		push @list, $o->{ILSM}->{CLASSPATH} ;
+	my $classes = [] ;
+	if ((defined($o->get_java_config('STUDY')))&&(scalar($o->get_java_config('STUDY')))){
+		$classes = $o->_study($o->get_java_config('STUDY')) ;
 	}
-	if (defined($path)){
-		push @list, portable("SUB_FIX_CLASSPATH", $path) ;
-	}
-
-	my $sep = portable("ENV_VAR_PATH_SEP_CP") ;
-	my $cpall = join($sep, @list) ;
-	
-
-	$cpall =~ s/\s*\[PERL_INLINE_JAVA\s*=\s*(.*?)\s*\]\s*/{
-		my $modules = $1 ;
-		Inline::Java::debug(1, "found special CLASSPATH entry: $modules") ;
-	
-		my @modules = split(m#\s*,\s*#, $modules) ;
-		my $dir = File::Spec->catdir($o->get_config('DIRECTORY'), "lib", "auto") ;
-
-		my %paths = () ;
-		foreach my $m (@modules){
-			$m = File::Spec->catdir(split(m#::#, $m)) ;
-
-			# Here we must make sure that the directory exists, or
-			# else it is removed from the CLASSPATH by Java
-			my $path = File::Spec->catdir($dir, $m) ;
-			Inline::Java::Portable::mkpath($o, $path) ;
-
-			$paths{portable("SUB_FIX_CLASSPATH", $path)} = 1 ;
-		}
-
-		join($sep, keys %paths) ;
-	}/ge ;
+	$o->_study($classes, 1) ;
 
-	my @cp = split(/$sep+/, $cpall) ;
-
-	# Add dot to CLASSPATH, required when building
-	push @cp, '.' ;
-
-	foreach my $p (@cp){
-		$p =~ s/^\s+// ;
-		$p =~ s/\s+$// ;
-	}
-
-	my @fcp = () ;
-	my %cp = map {$_ => 1} @cp ;
-	foreach my $p (@cp){
-		if ($cp{$p}){
-			push @fcp, $p ;
-			delete $cp{$p} ;
-		}
-	}
-
-	$ENV{CLASSPATH} = join($sep, @fcp) ;
-
-	Inline::Java::debug(1, "classpath: " . $ENV{CLASSPATH}) ;
+	$o->set_java_config('loaded', 1) ;
+	Inline::Java::debug(1, "load done.") ;
 }
 
 
-
 # This function 'studies' the specified classes and binds them to 
 # Perl
 sub _study {
@@ -692,9 +412,7 @@ sub _study {
 	my @lines = $o->report($classes) ;
 
 	# Now we read up the symbols and bind them to Perl.
-	$o->bind_jdat(
-		$o->load_jdat(@lines)
-	) ;
+	$o->bind_jdat($o->load_jdat(@lines)) ;
 }
 
 
@@ -703,27 +421,38 @@ sub _study {
 sub report {
 	my $o = shift ;
 	my $classes = shift ;
+	my $load = shift || 0 ;
 
-	my $install_lib = $o->get_api('install_lib') ;
-	my $modpname = $o->get_api('modpname') ;
-	my $modfname = $o->get_api('modfname') ;
-	my $suffix = $o->get_api('suffix') ;
-	my $install = File::Spec->catdir($install_lib, "auto", $modpname) ;
-
-	my $use_cache = 0 ;
-	if (! defined($classes)){
-		$classes = [] ;
+	my $install_dir = File::Spec->catdir($o->get_api('install_lib'), 
+		'auto', $o->get_api('modpname')) ;
+	my $cache = $o->get_api('modfname') . '.' . $o->get_api('suffix') ;
 
-		$use_cache = 1 ;
+	# If search_dir is valid that means that we are really at module load time,
+	# or else we are just studying a specific class via AUTOSTUDY.
+	if (($load)&&(! $o->get_java_config('built'))){
+		# Since we didn't build the module, this means that 
+		# it was up to date. We can therefore use the data 
+		# from the cache
+		Inline::Java::debug(1, "using jdat cache") ;
+		my $p = File::Spec->catfile($install_dir, $cache) ;
+		if (open(Inline::Java::CACHE, "<$p")){
+			my $resp = join("", <Inline::Java::CACHE>) ;
+			close(Inline::Java::CACHE) ;
+			return split("\n", $resp) ;
+		}
+		else{
+			croak "Can't open $p for reading: $!" ;
+		}
+	}
 
-		# We need to take the classes that are in the directory...
-		my @cl = Inline::Java::Portable::find_classes_in_dir($install) ;
+	# Ok, we really have some classes to study.
+	if ($load){
+		# We need to add the classes that are in the directory or under...
+		my @cl = Inline::Java::Portable::find_classes_in_dir($install_dir) ;
 		foreach my $class (@cl){
 			if ($class =~ s/([\w\$]+)\.class$/$1/){
 				my $f = $1 ;
-				if ($f !~ /^InlineJava(Server|Perl)/){
-					push @{$classes}, $f ;
-				}
+				push @{$classes}, $f ;
 			}
 		}
 	}
@@ -731,49 +460,28 @@ sub report {
 	my @new_classes = () ;
 	foreach my $class (@{$classes}){
 		$class = Inline::Java::Class::ValidateClass($class) ;
-
 		if (! Inline::Java::known_to_perl($o->get_api('pkg'), $class)){
 			push @new_classes, $class ;
 		}
 	}
-
 	if (! scalar(@new_classes)){
 		return () ;
 	}
 
-	my $resp = undef ;
-	if (($use_cache)&&(! $o->{ILSM}->{built})){
-		# Since we didn't build the module, this means that 
-		# it was up to date. We can therefore use the data 
-		# from the cache
-		Inline::Java::debug(1, "using jdat cache") ;
-		my $p = File::Spec->catfile($install, "$modfname.$suffix") ;
-		my $size = (-s $p) || 0 ;
-		if ($size > 0){
-			if (open(Inline::Java::CACHE, "<$p")){
-				$resp = join("", <Inline::Java::CACHE>) ;
-				close(Inline::Java::CACHE) ;
-			}
-			else{
-				croak "Can't open $modfname.$suffix file for reading" ;
-			}
-		}
-	}
-
-	if (! defined($resp)){
-		my $pc = new Inline::Java::Protocol(undef, $o) ;
-		$resp = $pc->Report(join(" ", @new_classes)) ;
-	}
+	# Ask for the info on the classes
+	my $pc = new Inline::Java::Protocol(undef, $o) ;
+	my $resp = $pc->Report(join(" ", @new_classes)) ;
 
-	if (($use_cache)&&($o->{ILSM}->{built})){
+	if (($load)&&($o->get_java_config('built'))){
 		# Update the cache.
 		Inline::Java::debug(1, "updating jdat cache") ;
-		if (open(Inline::Java::CACHE, ">$install/$modfname.$suffix")){
+		my $p = File::Spec->catfile($install_dir, $cache) ;
+		if (open(Inline::Java::CACHE, ">$p")){
 			print Inline::Java::CACHE $resp ;
 			close(Inline::Java::CACHE) ;
 		}
 		else{
-			croak "Can't open $modfname.$suffix file for writing" ;
+			croak "Can't open $p file for writing" ;
 		}
 	}
 
@@ -781,7 +489,6 @@ sub report {
 }
 
 
-
 # Load the jdat code information file.
 sub load_jdat {
 	my $o = shift ;
@@ -1031,12 +738,12 @@ sub get_fields {
 sub info {
 	my $o = shift ;
 
-	if (! (($o->{INLINE}->{object_ready})||($o->{ILSM}->{built}))){
-		$o->build ;
+	if (! (($o->{INLINE}->{object_ready})||($o->get_java_config('built')))){
+		$o->build() ;
 	}
 
-	if (! $o->{ILSM}->{loaded}){
-		$o->load ;
+	if (! $o->get_java_config('loaded')){
+		$o->load() ;
 	}
 
 	my $info = '' ;
@@ -1146,6 +853,11 @@ sub get_INLINE_nb {
 }
 
 
+sub get_INLINE_modules {
+	return keys %{$INLINES} ;
+}
+
+
 sub get_DEBUG {
 	return $Inline::Java::DEBUG ;
 }
@@ -1288,7 +1000,4 @@ sub caught {
 }
 
 
-1 ;
-
-__END__
-
+1 ;
\ No newline at end of file
diff --git a/Java.pod b/Java.pod
index 0b1e7cb..bc26ff0 100644
--- a/Java.pod
+++ b/Java.pod
@@ -176,12 +176,12 @@ behavior of C<Inline::Java>:
    STUDY:
       Takes an array of Java classes that you wish to have 
       C<Inline::Java> learn about so that you can use them inside Perl.
-      Ex: STUDY => ['java.lang.HashMap', 'my.class'] ;
+      Ex: STUDY => ['java.lang.HashMap', 'my.class']
 
    AUTOSTUDY:
       Makes C<Inline::Java> automatically study unknown classes it 
-      encounters.
-      Ex: STUDY => ['java.lang.HashMap', 'my.class'] ;
+      encounters them.
+      Ex: AUTOSTUDY => 1
 
 
 =head1 ENVIRONMENT VARIABLES
diff --git a/Java/Array.pm b/Java/Array.pm
index 3df6480..81f3f78 100644
--- a/Java/Array.pm
+++ b/Java/Array.pm
@@ -4,7 +4,7 @@ package Inline::Java::Array ;
 
 use strict ;
 
-$Inline::Java::Array::VERSION = '0.31' ;
+$Inline::Java::Array::VERSION = '0.40' ;
 
 use Carp ;
 
@@ -631,112 +631,4 @@ sub MakeElementList {
 }
 
 
-
-package Inline::Java::Array ;
-
-
-1 ; 
-
-
-__DATA__
-
-
-class InlineJavaArray {
-	private InlineJavaServer ijs ;
-	private InlineJavaClass ijc ;
-
-
-	InlineJavaArray(InlineJavaServer _ijs, InlineJavaClass _ijc){
-		ijs = _ijs ;
-		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)) ;
-			ijs.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){
-						ijs.debug(4, "setting array element " + String.valueOf(i) + " to " + o.toString()) ;
-					}
-					else{
-						ijs.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()) ;
-			}
-		}
-	}
-}
-	
-	
-
+1 ; 
\ No newline at end of file
diff --git a/Java/Callback.pm b/Java/Callback.pm
index 97a5f6a..90936b8 100644
--- a/Java/Callback.pm
+++ b/Java/Callback.pm
@@ -3,7 +3,7 @@ package Inline::Java::Callback ;
 
 use strict ;
 
-$Inline::Java::Callback::VERSION = '0.31' ;
+$Inline::Java::Callback::VERSION = '0.40' ;
 
 
 use Carp ;
@@ -84,70 +84,4 @@ sub ProcessCallback {
 
 
 
-1 ;
-
-
-__DATA__
-
-/*
-	Callback to Perl...
-*/
-public class InlineJavaPerlCaller {
-	public InlineJavaPerlCaller(){
-	}
-
-
-	class InlineJavaException extends Exception {
-		private InlineJavaServer.InlineJavaException ije = null ;
-		
-		InlineJavaException(InlineJavaServer.InlineJavaException e) {
-			ije = e ;
-		}
-
-		public InlineJavaServer.InlineJavaException GetException(){
-			return ije ;
-		}
-	}
-
-
-	class PerlException extends Exception {
-		private Object obj = null ;
-
-		PerlException(Object o) {
-			obj = o ;
-		}
-
-		public Object GetObject(){
-			return obj ;
-		}
-
-		public String GetString(){
-			return (String)obj ;
-		}
-	}
-
-
-	public Object CallPerl(String pkg, String method, Object args[]) throws InlineJavaException, PerlException {
-		return CallPerl(pkg, method, args, null) ;
-	}
-
-
-	public Object CallPerl(String pkg, String method, Object args[], String cast) throws InlineJavaException, PerlException {
-		if (InlineJavaServer.instance == null){
-			System.err.println("Can't use InlineJavaPerlCaller outside of an Inline::Java context") ;
-			System.err.flush() ;
-			System.exit(1) ;
-		}
-
-		try {
-			return InlineJavaServer.instance.Callback(pkg, method, args, cast) ;
-		}
-		catch (InlineJavaServer.InlineJavaException e){
-			throw new InlineJavaException(e) ;
-		}
-		catch (InlineJavaServer.InlineJavaPerlException e){
-			throw new PerlException(e.GetObject()) ;
-		}
-	}
-}
-
+1 ;
\ No newline at end of file
diff --git a/Java/Class.pm b/Java/Class.pm
index 28e0ed3..ee7a19b 100644
--- a/Java/Class.pm
+++ b/Java/Class.pm
@@ -3,7 +3,7 @@ package Inline::Java::Class ;
 
 use strict ;
 
-$Inline::Java::Class::VERSION = '0.31' ;
+$Inline::Java::Class::VERSION = '0.40' ;
 
 $Inline::Java::Class::MAX_SCORE = 10 ;
 
@@ -484,464 +484,4 @@ sub matches {
 }
 
 
-package Inline::Java::Class ;
-
-
 1 ;
-
-
-__DATA__
-
-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) ;
-			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] ;
-			ijs.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){
-				ijs.debug(4, "specializing java.lang.Number to java.lang.Double") ;
-				ap = java.lang.Double.class ;
-			}
-
-			if (type.equals("undef")){
-				if (num){
-					ijs.debug(4, "args is undef -> forcing to " + ap.getName() + " 0") ;
-					ret = ijp.CreateObject(ap, new Object [] {"0"}, new Class [] {String.class}) ;
-					ijs.debug(4, " result is " + ret.toString()) ;
-				}
-				else{
-					ret = null ;
-					ijs.debug(4, "args is undef -> forcing to " + ap.getName() + " " + ret) ;
-					ijs.debug(4, " result is " + ret) ;
-				}
-			}
-			else if (type.equals("scalar")){
-				String arg = ijp.decode((String)tokens.get(1)) ;
-				ijs.debug(4, "args is scalar -> forcing to " + ap.getName()) ;
-				try	{
-					ret = ijp.CreateObject(ap, new Object [] {arg}, new Class [] {String.class}) ;
-					ijs.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")){
-				ijs.debug(4, "args is undef -> forcing to bool false") ;
-				ret = new Boolean("false") ;
-				ijs.debug(4, " result is " + ret.toString()) ;
-			}
-			else if (type.equals("scalar")){
-				String arg = ijp.decode(((String)tokens.get(1)).toLowerCase()) ;
-				ijs.debug(4, "args is scalar -> forcing to bool") ;
-				if ((arg.equals(""))||(arg.equals("0"))){
-					arg = "false" ;
-				}
-				else{
-					arg = "true" ;
-				}
-				ret = new Boolean(arg) ;
-				ijs.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")){
-				ijs.debug(4, "args is undef -> forcing to char '\0'") ;
-				ret = new Character('\0') ;
-				ijs.debug(4, " result is " + ret.toString()) ;
-			}
-			else if (type.equals("scalar")){
-				String arg = ijp.decode((String)tokens.get(1)) ;
-				ijs.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) ;
-				ijs.debug(4, " result is " + ret.toString()) ;
-			}
-			else{
-				throw new InlineJavaCastException("Can't convert reference to " + p.getName()) ;
-			}
-		}
-		else {
-			ijs.debug(4, "class " + p.getName() + " is reference") ;
-			// We know that what we expect here is a real object
-			if (type.equals("undef")){
-				ijs.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...
-				ijs.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){
-					ijs.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){
-		ijs.debug(4, "checking if " + a.getName() + " extends " + b.getName()) ;
-
-		if (a == b){
-			return level ;
-		}
-
-		Class parent = a.getSuperclass() ;
-		if (parent != null){
-			ijs.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++){
-			ijs.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 ;
-		}
-
-		ijs.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]){
-				ijs.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]){
-				ijs.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]){
-				ijs.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]){
-				ijs.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 ;
-		}
-
-		ijs.debug(4, "class " + name + " is reference") ;
-
-		return true ;
-	}
-
-	boolean ClassIsArray (Class p){
-		String name = p.getName() ;
-
-		if ((ClassIsReference(p))&&(name.startsWith("["))){
-			ijs.debug(4, "class " + name + " is array") ;
-			return true ;
-		}
-
-		return false ;
-	}
-
-}
-
diff --git a/Java/Init.pm b/Java/Init.pm
deleted file mode 100644
index 8f21487..0000000
--- a/Java/Init.pm
+++ /dev/null
@@ -1,486 +0,0 @@
-package Inline::Java::Init ;
-
-
-use strict ;
-
-$Inline::Java::Init::VERSION = '0.31' ;
-
-my $DATA = join('', <DATA>) ;
-my $OBJECT_DATA = join('', <Inline::Java::Object::DATA>) ;
-my $ARRAY_DATA = join('', <Inline::Java::Array::DATA>) ;
-my $CLASS_DATA = join('', <Inline::Java::Class::DATA>) ;
-my $PROTO_DATA = join('', <Inline::Java::Protocol::DATA>) ;
-
-my $CALLBACK_DATA = join('', <Inline::Java::Callback::DATA>) ;
-
-
-sub DumpUserJavaCode {
-	my $fh = shift ;
-	my $code = shift ;
-
-	print $fh $code ;
-}
-
-
-sub DumpServerJavaCode {
-	my $fh = shift ;
-
-	my $java = $DATA ;
-	my $java_obj = $OBJECT_DATA ;
-	my $java_array = $ARRAY_DATA ;
-	my $java_class = $CLASS_DATA ;
-	my $java_proto = $PROTO_DATA ;
-
-	$java =~ s/<INLINE_JAVA_OBJECT>/$java_obj/g ;
-	$java =~ s/<INLINE_JAVA_ARRAY>/$java_array/g ;
-	$java =~ s/<INLINE_JAVA_CLASS>/$java_class/g ;
-	$java =~ s/<INLINE_JAVA_PROTOCOL>/$java_proto/g ;
-
-	print $fh $java ;
-}
-
-
-sub DumpCallbackJavaCode {
-	my $fh = shift ;
-
-	my $java = $CALLBACK_DATA ;
-
-	print $fh $java ;
-}
-
-
-
-1 ;
-
-
-
-__DATA__
-import java.net.* ;
-import java.io.* ;
-import java.util.* ;
-import java.lang.reflect.* ;
-
-
-/*
-	This is the server that will answer all the requests for and on Java
-	objects.
-*/
-public class InlineJavaServer {
-	static public InlineJavaServer instance = null ;
-	private int debug ;
-	private int port = 0 ;
-	private boolean shared_jvm = false ;
-
-	private HashMap thread_objects = new HashMap() ;
-	private int objid = 1 ;
-
-	// This constructor is used in JNI mode
-	InlineJavaServer(int d) {
-		init() ;
-		debug = d ;
-
-		thread_objects.put(Thread.currentThread().getName(), new HashMap()) ;
-	}
-
-
-	// This constructor is used in server mode
-	InlineJavaServer(String[] argv) {
-		init() ;
-
-		debug = new Integer(argv[0]).intValue() ;
-		port = Integer.parseInt(argv[1]) ;
-		shared_jvm = new Boolean(argv[2]).booleanValue() ;
-
-		ServerSocket ss = null ;
-		try {
-			ss = new ServerSocket(port) ;	
-		}
-		catch (IOException e){
-			System.err.println("Can't open server socket on port " + String.valueOf(port) +
-				": " + e.getMessage()) ;
-			System.err.flush() ;
-			System.exit(1) ;
-		}
-
-		while (true){
-			try {
-				InlineJavaThread ijt = new InlineJavaThread(this, ss.accept()) ;
-				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(){
-		instance = this ;
-	}
-
-	
-	public String GetType(){
-		return (shared_jvm ? "shared" : "private") ;
-	}
-
-
-	/*
-		Since this function is also called from the JNI XS extension,
-		it's best if it doesn't throw any exceptions.
-	*/
-	private String ProcessCommand(String cmd) {
-		return ProcessCommand(cmd, true) ;
-	}
-
-	private String ProcessCommand(String cmd, boolean addlf) {
-		debug(3, "packet recv is " + cmd) ;
-
-		String resp = null ;
-		if (cmd != null){
-			InlineJavaProtocol ijp = new InlineJavaProtocol(this, cmd) ;
-			try {
-				ijp.Do() ;
-				debug(3, "packet sent is " + ijp.response) ;
-				resp = ijp.response ;
-			}
-			catch (InlineJavaException e){
-				String err = "error scalar:" + ijp.encode(e.getMessage()) ;
-				debug(3, "packet sent is " + err) ;
-				resp = err ;
-			}
-		}
-		else{
-			if (! shared_jvm){
-				// Probably connection dropped...
-				debug(1, "lost connection with client in single client mode. Exiting.") ;
-				System.exit(1) ;
-			}
-			else{
-				debug(1, "lost connection with client in shared JVM mode.") ;
-				return null ;
-			}
-		}
-
-		if (addlf){
-			resp = resp + "\n" ;
-		}
-
-		return resp ;
-	}
-
-	
-	public Object GetObject(int id) throws InlineJavaException {
-		Object o = null ;
-		String name = Thread.currentThread().getName() ;
-		HashMap h = (HashMap)thread_objects.get(name) ;
-
-		if (h == null){
-			throw new InlineJavaException("Can't find thread " + name + "!") ;
-		}
-		else{
-			o = h.get(new Integer(id)) ;
-			if (o == null){
-				throw new InlineJavaException("Can't find object " + id + " for thread " + name) ;
-			}
-		}
-
-		return o ;
-	}
-
-
-	synchronized public void PutObject(int id, Object o) throws InlineJavaException {
-		String name = Thread.currentThread().getName() ;
-		HashMap h = (HashMap)thread_objects.get(name) ;
-
-		if (h == null){
-			throw new InlineJavaException("Can't find thread " + name + "!") ;
-		}
-		else{
-			h.put(new Integer(id), o) ;
-			objid++ ;
-		}
-	}
-
-
-	public Object DeleteObject(int id) throws InlineJavaException {
-		Object o = null ;
-		String name = Thread.currentThread().getName() ;
-		HashMap h = (HashMap)thread_objects.get(name) ;
-
-		if (h == null){
-			throw new InlineJavaException("Can't find thread " + name + "!") ;
-		}
-		else{
-			o = h.remove(new Integer(id)) ;
-			if (o == null){
-				throw new InlineJavaException("Can't find object " + id + " for thread " + name) ;
-			}
-		}
-
-		return o ;
-	}
-
-
-	public int ObjectCount() throws InlineJavaException {
-		int i = -1 ;
-		String name = Thread.currentThread().getName() ;
-		HashMap h = (HashMap)thread_objects.get(name) ;
-
-		if (h == null){
-			throw new InlineJavaException("Can't find thread " + name + "!") ;
-		}
-		else{
-			i = h.values().size() ;
-		}
-
-		return i ;
-	}
-
-
-	public Object Callback(String pkg, String method, Object args[], String cast) throws InlineJavaException, InlineJavaPerlException {
-		Object ret = null ;
-
-		try {
-			InlineJavaProtocol ijp = new InlineJavaProtocol(this, null) ;
-			InlineJavaClass ijc = new InlineJavaClass(this, ijp) ;
-			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])) ;
-				}
-			}
-			String cmd = cmdb.toString() ;
-			debug(2, "callback command: " + cmd) ;
-
-			Thread t = Thread.currentThread() ;
-			String resp = null ;
-			while (true) {			
-				debug(3, "packet sent (callback) is " + cmd) ;
-				if (t instanceof InlineJavaThread){
-					// Client-server mode
-					InlineJavaThread ijt = (InlineJavaThread)t ;
-					ijt.bw.write(cmd + "\n") ;
-					ijt.bw.flush() ;
-
-					resp = ijt.br.readLine() ;
-				}
-				else{
-					// JNI mode
-					resp = jni_callback(cmd) ;
-				}
-				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() ;
-					ret = ijc.CastArgument(java.lang.Object.class, arg) ;
-
-					if (thrown){
-						throw new InlineJavaPerlException(ret) ;
-					}
-
-					break ;
-				}	
-				else{
-					// Pass it on through the regular channel...
-					debug(3, "packet is not callback response: " + resp) ;
-					cmd = ProcessCommand(resp, false) ;
-
-					continue ;
-				}
-			}
-		}
-		catch (IOException e){
-			throw new InlineJavaException("IO error: " + e.getMessage()) ;
-		}
-
-		return ret ;
-	}
-
-
-	native private String jni_callback(String cmd) ;
-
-
-	/*
-		Creates a string representing a method signature
-	*/
-	public String CreateSignature(Class param[]){
-		return CreateSignature(param, ", ") ;
-	}
-
-
-	public 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 public 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() ;
-		}
-	}
-
-
-	boolean reverse_members() {
-		String v = System.getProperty("java.version") ;
-		boolean no_rev = ((v.startsWith("1.2"))||(v.startsWith("1.3"))) ;
-
-		return (! no_rev) ;
-	}
-
-
-	/*
-		Startup
-	*/
-	public static void main(String[] argv) {
-		new InlineJavaServer(argv) ;
-	}
-
-
-	public static InlineJavaServer jni_main(int debug) {
-		return new InlineJavaServer(debug) ;
-	}
-	
-	<INLINE_JAVA_OBJECT>
-
-	<INLINE_JAVA_ARRAY>
-
-	<INLINE_JAVA_CLASS>
-
-	<INLINE_JAVA_PROTOCOL>
-
-	/*
-		Exception thrown by this code.
-	*/
-	class InlineJavaException extends Exception {
-		InlineJavaException(String s) {
-			super(s) ;
-		}
-	}
-
-
-	/*
-		Exception thrown by Perl callbacks.
-	*/
-	class InlineJavaPerlException extends Exception {
-		private Object obj = null ;
-
-
-		InlineJavaPerlException(Object o) {
-			obj = o ;
-		}
-
-		public Object GetObject(){
-			return obj ;
-		}
-	}
-
-
-	/*
-		Exception thrown by this code while trying to cast arguments
-	*/
-	class InlineJavaCastException extends InlineJavaException {
-		InlineJavaCastException(String m){
-			super(m) ;
-		}
-	}
-
-
-
-	class InlineJavaInvocationTargetException extends InlineJavaException {
-		Throwable t = null ;
-
-		InlineJavaInvocationTargetException(String m, Throwable _t){
-			super(m) ;
-			t = _t ;
-		}
-
-		public Throwable GetThrowable(){
-			return t ;
-		}
-	}
-
-	
-	class InlineJavaThread extends Thread {
-		InlineJavaServer ijs ;
-		Socket client ;
-		BufferedReader br ;
-		BufferedWriter bw ;
-
-		InlineJavaThread(InlineJavaServer _ijs, Socket _client) throws IOException {
-			super() ;
-			client = _client ;
-			ijs = _ijs ;
-
-			br = new BufferedReader(
-				new InputStreamReader(client.getInputStream())) ;
-			bw = new BufferedWriter(
-				new OutputStreamWriter(client.getOutputStream())) ;
-		}
-
-
-		public void run(){
-			try {
-				ijs.thread_objects.put(getName(), new HashMap()) ;
-
-				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.thread_objects.remove(getName()) ;
-			}
-		}
-	}
-}
-
-
-class InlineJavaServerThrown {
-	Throwable t = null ;
-
-	InlineJavaServerThrown(Throwable _t){
-		t = _t ;
-	}
-
-	public Throwable GetThrowable(){
-		return t ;
-	}
-}
diff --git a/Java/JNI.pm b/Java/JNI.pm
index 4403187..121dba4 100644
--- a/Java/JNI.pm
+++ b/Java/JNI.pm
@@ -21,7 +21,7 @@ sub load_lib {
 	my $lib = (DynaLoader::dl_findfile($l))[0] ;	
 	
     if ((! $lib)||(! defined(DynaLoader::dl_load_file($lib, 0x01)))){
-		carp("Couldn't load $l.") ;
+		carp("Couldn't find or load $l.") ;
 	}
 }
 
diff --git a/Java/JVM.pm b/Java/JVM.pm
index 44ee883..5bfc461 100644
--- a/Java/JVM.pm
+++ b/Java/JVM.pm
@@ -8,7 +8,7 @@ $Inline::Java::JVM::VERSION = '0.31' ;
 use Carp ;
 use IPC::Open3 ;
 use IO::File ;
-use IO::Pipe ;
+use IO::Socket ;
 use POSIX qw(setsid) ;
 
 my %SIGS = () ;
@@ -41,7 +41,7 @@ sub new {
 		Inline::Java::debug(1, "JNI mode") ;
 
 		my $jni = new Inline::Java::JNI(
-			$ENV{CLASSPATH} || "",
+			$ENV{CLASSPATH} || '',
 			$o->get_java_config('EMBEDDED_JNI'),
 			Inline::Java::get_DEBUG(),
 		) ;
@@ -70,13 +70,12 @@ sub new {
 		}
 		$this->capture(1) ;
 
-		my $java = File::Spec->catfile($o->get_java_config('BIN'), 
+		my $java = File::Spec->catfile($o->get_java_config('J2SDK'), 'bin',
 			"java" . Inline::Java::portable("EXE_EXTENSION")) ;
 
-		my $shared_arg = ($this->{shared} ? "true" : "false") ;
-		my $cmd = "\"$java\" InlineJavaServer $debug $this->{port} $shared_arg" ;
+		my $shared = ($this->{shared} ? "true" : "false") ;
+		my $cmd = "\"$java\" InlineJavaServer $debug $this->{port} $shared" ;
 		Inline::Java::debug(1, $cmd) ;
-
 		if ($o->get_config('UNTAINT')){
 			($cmd) = $cmd =~ /(.*)/ ;
 		}
@@ -91,7 +90,7 @@ sub new {
 		$this->{socket}	= $this->setup_socket(
 			$this->{host}, 
 			$this->{port}, 
-			$o->get_java_config('STARTUP_DELAY'),
+			int($o->get_java_config('STARTUP_DELAY')),
 			0
 		) ;
 	}
@@ -323,10 +322,12 @@ sub process_command {
 	my $data = shift ;
 
 	my $resp = undef ;
+
 	# Patch by Simon Cozens for perl -wle 'use Our::Module; do_stuff()'
 	local $/ = "\n" ;
 	local $\ = "" ;
 	# End Patch
+
 	while (1){
 		Inline::Java::debug(3, "packet sent is $data") ;
 
diff --git a/Java/Makefile.PL b/Java/Makefile.PL
index 3162386..3e8ff86 100644
--- a/Java/Makefile.PL
+++ b/Java/Makefile.PL
@@ -5,6 +5,9 @@ use strict ;
 use File::Spec ;
 
 require "Portable.pm" ;
+# The file we just produced in the parent Makefile.PL
+require "DefaultJ2SDK.pl" ;
+
 
 # Some shortcuts while developing
 my $jdk_dir = undef ;
@@ -43,22 +46,17 @@ foreach my $f (@files){
 }
 
 
-print "\n" ;
 print
-	"Inline::Java can use a JNI extension that allows the Java Virtual Machine\n" .
+	"\nInline::Java can use a JNI extension that allows the Java Virtual Machine\n" .
 	"(JVM) to be dynamically linked with Perl instead of running as a separate\n" .
 	"process. The use of this extension is optional, and building it still\n" .
 	"allows Inline::Java to run the JVM in the default (separate process)\n" .
 	"fashion. Note: You need a C compiler to build the extension.\n\n" ;
 
-if (($build_jni || AskYN("Do you wish to build the JNI extension", 'n'))){
+if (($build_jni || AskYN("Do you wish to build the JNI extension?", 'y'))){
 	print "\nBuilding JNI extension.\n\n" ;
 
-	rename("JNI.xs_", "JNI.xs") ;
-
-	$jdk_dir = ($jdk_dir || AskSub("Enter the path to your Java 2 SDK installation",
-		sub {((($_[0]) && (-d $_[0])) ? 1 : (print("Directory '$_[0]' does not exist.\n") && 0))})) ;
-	print "\n" ;
+	$jdk_dir = Inline::Java::get_default_j2sdk() ;
 
 	my $type = FindDefaultVMType() ;
 
@@ -85,47 +83,37 @@ if (($build_jni || AskYN("Do you wish to build the JNI extension", 'n'))){
 		CleanSoDirs() ;
 
 		print "Building with:\n" ;
-		foreach my $f (@files){
-			print File::Spec->catfile($files->{$f}->{selected}, $f) . "\n" ;
-		}
-		print "\n" ;
+		map { print "  " . File::Spec->catfile($files->{$_}->{selected}, $_) . "\n" ;} @files ;
 
 		$done = 0 ;
 		if (! $done){
+			print
+				"\nNote: In order for Inline::Java to use the JNI extension, you will need to\n" . 			    
+				"use the JNI configuration option or set the PERL_INLINE_JAVA_JNI environment\n" .
+				"variable to a true value. You will also need to add the following directories\n" .
+				"to your " . Inline::Java::Portable::portable('SO_LIB_PATH_VAR') . " environment variable:\n" ;
+			map {print "  $_\n"; } keys %so_dirs ;
+			print "See README.JNI for more information.\n\n" ;
+
 			WriteMakefile(
 				NAME => 'Inline::Java::JNI',
 				VERSION_FROM => 'JNI.pm',
+				DIR => [],
 				INC => "-I" . $files->{'jni.h'}->{selected} . " -I" . $files->{'jni_md.h'}->{selected},
 				LIBS => ["-L" . $files->{$jvm_lib}->{selected} . " -ljvm"],
 				# CCFLAGS => '-D_REENTRANT',
 			) ;
-
-			print
-				"\nNote: In order for Inline::Java to use the JNI extension, you\n" .
-				"will need to use the JNI configuration option or set the\n" .
-				"PERL_INLINE_JAVA_JNI environment variable to a true value.\n" .
-				"You will also need to add the following directories to your\n" .
-				Inline::Java::Portable::portable('SO_LIB_PATH_VAR') . " environment variable:\n" ;
-
-			foreach my $d (keys %so_dirs){
-				print "  $d\n" ;
-			}
-
-			print 
-				"See README.JNI for more information.\n" ;
-
-			print "\n" ;
 		}
 	}
 }
 else{
 	print "\n" ;
-
-	rename("JNI.xs", "JNI.xs_") ;
-
 	WriteMakefile(
 		NAME => 'Inline::Java::JNI',
-		VERSION_FROM => 'JNI.pm') ;
+		VERSION_FROM => 'JNI.pm',
+		DIR => [],
+		XS => {},
+		C => []) ;
 }
 
 
@@ -139,6 +127,7 @@ sub search {
 	if ($File::Find::dir =~ /jre/){
 		if ($file =~ /\.$ext$/){
 			my $dir = File::Spec->canonpath($File::Find::dir) ;
+			print "---> $File::Find::dir\n" ;
 			$so_dirs{$dir} = 1 ;
 		}
 	}
@@ -211,16 +200,16 @@ sub Choose {
 
 	my $o = $files->{$f} ;
 	my $cnt = 0 ;
+	my $def = undef ;
 	foreach my $f (@{$o->{choices}}){
 		$cnt++ ;
-		my $hint = '' ;
 		if ($f =~ /$type/){
-			$hint = "[your system default]" ;
+			$def = $cnt ;
 		}
-		print "[$cnt] $f $hint\n" ;
+		print "$cnt- $f\n" ;
 	}
-	my $idx = AskSub("Please select from the above list which '$f' to use [1-$cnt]",
-		sub {(($_[0] >= 1)&&($_[0] <= $cnt))}) ;
+	my $idx = AskSub("Please select from the above list (using the corresponding number) which '$f' to use",
+		$def, sub {(($_[0] >= 1)&&($_[0] <= $cnt))}) ;
 
 	$o->{selected} = $o->{choices}->[int($idx) - 1] ;
 	print "\n" ;
@@ -230,8 +219,9 @@ sub Choose {
 # Gets string from stdin
 sub Ask {
 	my $ques = shift ;
+	my $def = shift ;
 
-	return AskSub($ques, undef) ;
+	return AskSub($ques, $def, undef) ;
 }
 
 
@@ -240,22 +230,19 @@ sub AskYN {
 	my $ques = shift ;
 	my $def = shift ;
 
-	$ques .= " [yn]?" ;
-
-	my $ans = AskSub($ques, sub {((! $_[0])||($_[0] =~ /^(y|n)$/i))}) ;
+	my $ans = AskSub($ques, $def, sub {((! $_[0])||($_[0] =~ /^(y|n)$/i))}) ;
 
-	return (($ans eq "y") ? 1 : 0) ;
+	return (($ans =~ /^y$/i) ? 1 : 0) ;
 }
 
 
 sub AskSub {
 	my $ques = shift ;
+	my $def = shift ;
 	my $sub = shift ;
 
-	my $str = $ques . ":" ;
-
 	while (1){
-		my $ans = prompt($str) ;
+		my $ans = prompt($ques, $def) ;
 		if (! $sub){
 			return $ans ;
 		}
diff --git a/Java/Object.pm b/Java/Object.pm
index 4b77ff5..80d01b0 100644
--- a/Java/Object.pm
+++ b/Java/Object.pm
@@ -548,12 +548,4 @@ sub DESTROY {
 
 
 
-
-package Inline::Java::Object ;
-
-
-1 ;
-
-
-__DATA__
-
+1 ;
\ No newline at end of file
diff --git a/Java/Portable.pm b/Java/Portable.pm
index 8403b7c..fb8a432 100644
--- a/Java/Portable.pm
+++ b/Java/Portable.pm
@@ -1,18 +1,20 @@
 package Inline::Java::Portable ;
 @Inline::Java::Portable::ISA = qw(Exporter) ;
 
- at EXPORT = qw(portable) ;
+ at EXPORT = qw(portable make_classpath get_jar) ;
 
 
 use strict ;
 
-$Inline::Java::Portable::VERSION = '0.31' ;
+$Inline::Java::Portable::VERSION = '0.40' ;
 
 
 use Exporter ;
 use Carp ;
 use Config ;
 use File::Find ;
+use File::Spec ;
+
 
 # Here is some code to figure out if we are running on command.com
 # shell under Windows.
@@ -38,27 +40,50 @@ sub debug {
 }
 
 
-# Here in Inline <= 0.43 there is a portability issue
-# with the mkpath function. It splits directly on '/'.
-# We assume this will be fixed in 0.44
-sub mkpath {
-	my $o = shift ;
-	my $path = shift ;
+# Cleans the CLASSPATH environment variable and adds
+# the paths specified.
+sub make_classpath {
+	my @paths = @_ ;
+
+	my @list = () ;
+	if (defined($ENV{CLASSPATH})){
+		push @list, $ENV{CLASSPATH} ;
+	}
+	push @list, @paths ;
+
+	my $sep = portable("ENV_VAR_PATH_SEP_CP") ;
+	my @cp = split(/$sep+/, join($sep, @list)) ;
+
+	# Clean up paths
+	foreach my $p (@cp){
+		$p =~ s/^\s+// ;
+		$p =~ s/\s+$// ;
+		$p = portable("SUB_FIX_CLASSPATH", $p) ;
+	}
+
+	# Remove duplicates, but preserve order
+	my @fcp = () ;
+	my %cp = map {$_ => 1} @cp ;
+	foreach my $p (@cp){
+		if (($p)&&($cp{$p})){
+			push @fcp, $p ;
+			delete $cp{$p} ;
+		}
+	}
+
+	my $cp = join($sep, @fcp) ;
+	Inline::Java::debug(1, "classpath: $cp") ;
 
-	return $o->Inline::mkpath($path) ;
-} ;
+	return (wantarray ? @fcp : $cp) ;
+}
 
 
-# Here in Inline <= 0.43 there is a portability issue
-# with the rmpath function. It splits directly on '/'.
-# We assume this will be fixed in 0.44
-sub rmpath {
-	my $o = shift ;
-	my $prefix = shift ;
-	my $path = shift ;
-	
-	return $o->Inline::rmpath($prefix, $path) ;
-} ;
+sub get_jar {
+	return File::Spec->catfile(
+		(File::Spec->splitpath($INC{"Inline/Java.pm"}))[0,1], 
+		'Java', 'jar', 'InlineJava.jar'
+	) ;
+}
 
 
 sub find_classes_in_dir {
@@ -68,9 +93,9 @@ sub find_classes_in_dir {
 	find(sub {
 		my $file = $_ ;
 		if ($file =~ /\.class$/){
-			push @ret, $file ;
+			push @ret, File::Spec->catfile($File::Find::dir, $file) ;
 		}
-	}, $dir) ;	
+	}, $dir) ;
 
 	return @ret ;
 }
@@ -177,8 +202,4 @@ sub portable {
 }
 
 
-1 ;
-
-
-
-
+1 ;
\ No newline at end of file
diff --git a/Java/Protocol.pm b/Java/Protocol.pm
index 546ff68..52e4646 100644
--- a/Java/Protocol.pm
+++ b/Java/Protocol.pm
@@ -3,7 +3,7 @@ package Inline::Java::Protocol ;
 
 use strict ;
 
-$Inline::Java::Protocol::VERSION = '0.31' ;
+$Inline::Java::Protocol::VERSION = '0.40' ;
 
 use Inline::Java::Object ;
 use Inline::Java::Array ;
@@ -370,7 +370,7 @@ sub DeserializeObject {
 
 			if ($thrown){
 				Inline::Java::debug(3, "throwing stub...") ;
-				my ($msg, $score) = $obj->__isa('InlineJavaPerlCaller$PerlException') ;
+				my ($msg, $score) = $obj->__isa('IJPerlException') ;
 				if ($msg){
 					die $obj ;
 				}
@@ -416,628 +416,39 @@ sub DESTROY {
 
 
 
-__DATA__
-
-
-/*
-	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 ;
-
-	InlineJavaProtocol(InlineJavaServer _ijs, String _cmd) {
-		ijs = _ijs ;
-		ijc = new InlineJavaClass(ijs, this) ;
-		ija = new InlineJavaArray(ijs, 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("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")){
-			ijs.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) ;
-
-			ijs.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 = 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 = 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 = 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[(ijs.reverse_members() ? (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 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 InlineJavaPerlCaller.InlineJavaException){
-					throw ((InlineJavaPerlCaller.InlineJavaException)t).GetException() ;
-				}
-				else{
-					SetResponse(new InlineJavaServerThrown(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()) ;
-
-			ijs.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 = m.invoke(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() ;
-				ijs.debug(1, "method " + name + " in class " + class_name + " threw exception " + type + ": " + msg) ;
-				if (t instanceof InlineJavaPerlCaller.InlineJavaException){
-					throw ((InlineJavaPerlCaller.InlineJavaException)t).GetException() ;
-				}
-				else{
-					SetResponse(new InlineJavaServerThrown(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) ;
-				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 {
-				f.set(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) ;
-			SetResponse(Array.get(o, idx)) ;
-		}
-		else{
-			ArrayList fl = ValidateMember(c, member, st) ;
-
-			Field f = (Field)fl.get(0) ;
-			String name = f.getName() ;
-			try {
-				Object ret = f.get(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 {
-			// This will allow usage of the default no-arg constructor
-			if (proto.length == 0){
-				ret = p.newInstance() ;
-			}
-			else{
-				Constructor con = (Constructor)p.getConstructor(proto) ;
-				ret = con.newInstance(args) ;
-			}
-		}
-		catch (NoSuchMethodException e){
-			throw new InlineJavaException("Constructor for class " + name + " with signature " + ijs.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 " + ijs.CreateSignature(proto) + ": " + e.getMessage()) ;
-		}
-		catch (IllegalArgumentException e){
-			throw new InlineJavaException("Arguments to constructor for class " + name + " with signature " + ijs.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 " + ijs.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 {
-		Member ma[] = (constructor ? (Member [])c.getConstructors() : (Member [])c.getMethods()) ;
-		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()) ;
-		}
-
-		ArrayList ml = new ArrayList(ma.length) ;
-		Class params[] = null ;
-		for (int i = 0 ; i < ma.length ; i++){
-			Member m = ma[i] ;
-
-			if (m.getName().equals(name)){
-				ijs.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 = ijs.CreateSignature(params, ",") ;
-				ijs.debug(3, sign + " = " + signature + "?") ;
-
-				if (signature.equals(sign)){
-					ijs.debug(3, "has matching signature " + sign) ;
-					ml.add(ml.size(), m) ;
-					break ;
-				}
-			}
-		}
-
-		// Now we got a list of matching methods. 
-		// 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 {
-		Field fa[] = c.getFields() ;
-		ArrayList ret = new ArrayList() ;
-
-		// Extract member type
-		String type = st.nextToken() ;
-
-		// Extract the argument
-		String arg = st.nextToken() ;
-
-		ArrayList fl = new ArrayList(fa.length) ;
-		Class param = null ;
-		for (int i = 0 ; i < fa.length ; i++){
-			Field f = fa[(ijs.reverse_members() ? (fa.length - 1 - i) : i)] ;
-
-			if (f.getName().equals(name)){
-				ijs.debug(3, "found a " + name + " member") ;
-
-				param = f.getType() ;
-				String t = param.getName() ;
-				if (type.equals(t)){
-					ijs.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) ;
-			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 InlineJavaServerThrown){ 
-				thrown = true ;
-				o = ((InlineJavaServerThrown)o).GetThrowable() ;
-			}			
-			int id = ijs.objid ;
-			ijs.PutObject(id, o) ;
-			return "object:" + (thrown ? "1" : "0") + ":" + String.valueOf(id) +
-				":" + o.getClass().getName() ;
-		}
-	}
-
-
-
-	public String decode(String s){
-		StringTokenizer st = new StringTokenizer(s, ".") ;
-		StringBuffer sb = new StringBuffer() ;
-		while (st.hasMoreTokens()){
-			String ss = st.nextToken() ; 
-			byte b[] = {(byte)Integer.parseInt(ss)} ;
-			sb.append(new String(b)) ;
-		}
-	
-		return sb.toString() ;
-	}
-
-
-	public String encode(String s){
-		byte b[] = s.getBytes() ;
-		StringBuffer sb = new StringBuffer() ;
-		for (int i = 0 ; i < b.length ; i++){
-			if (i > 0){
-				sb.append(".") ;
-			}
-			sb.append(String.valueOf(b[i])) ;
-		}
-
-		return sb.toString() ;
-	}
-}
-
+__END__
+
+
+RCS file: /cvsroot/inline-java/Inline-Java/Java/Protocol.pm,v
+retrieving revision 1.29
+diff -r1.29 Protocol.pm
+37a38,51
+> sub AddClassPath {
+>       my $this = shift ;
+>       my @paths = @_ ;
+>
+>       Inline::Java::debug(3, "adding to class path (" .
+>               join(", ", map {"'" . $_ . "'"} @paths) . ")") ;
+>
+>       my $data = "add_classpath " . join(" ", map {encode($_)} @paths) ;
+>
+>       return $this->Send($data, 1) ;
+> }
+>
+>
+>
+460a475,477
+>               else if (c.equals("add_classpath")){
+>                       AddClassPath(st) ;
+>               }
+553a571,580
+>       }
+>
+>
+>       void AddClassPath(StringTokenizer st) throws InlineJavaException {
+>               while (st.hasMoreTokens()){
+>                       String path = decode(st.nextToken()) ;
+>                       InlineJavaServer.instance.AddClassPath(path) ;
+>               }
+>
+>               SetResponse(null) ;
diff --git a/Java/sources/InlineJavaArray.java b/Java/sources/InlineJavaArray.java
new file mode 100644
index 0000000..c05c621
--- /dev/null
+++ b/Java/sources/InlineJavaArray.java
@@ -0,0 +1,98 @@
+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/InlineJavaCastException.java b/Java/sources/InlineJavaCastException.java
new file mode 100644
index 0000000..798fe21
--- /dev/null
+++ b/Java/sources/InlineJavaCastException.java
@@ -0,0 +1,5 @@
+class InlineJavaCastException extends InlineJavaException {
+	InlineJavaCastException(String m){
+		super(m) ;
+	}
+}
diff --git a/Java/sources/InlineJavaClass.java b/Java/sources/InlineJavaClass.java
new file mode 100644
index 0000000..861076f
--- /dev/null
+++ b/Java/sources/InlineJavaClass.java
@@ -0,0 +1,455 @@
+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) ;
+			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/InlineJavaException.java b/Java/sources/InlineJavaException.java
new file mode 100644
index 0000000..2143dac
--- /dev/null
+++ b/Java/sources/InlineJavaException.java
@@ -0,0 +1,5 @@
+class InlineJavaException extends Exception { 
+	InlineJavaException(String s) {
+		super(s) ;
+	}
+}
diff --git a/Java/sources/InlineJavaInvocationTargetException.java b/Java/sources/InlineJavaInvocationTargetException.java
new file mode 100644
index 0000000..d65b55d
--- /dev/null
+++ b/Java/sources/InlineJavaInvocationTargetException.java
@@ -0,0 +1,13 @@
+class InlineJavaInvocationTargetException extends InlineJavaException {
+	private Throwable t = null ;
+
+
+	InlineJavaInvocationTargetException(String m, Throwable _t){
+		super(m) ;
+		t = _t ;
+	}
+
+	Throwable GetThrowable(){
+		return t ;
+	}
+}
diff --git a/Java/sources/InlineJavaPerlCaller.java b/Java/sources/InlineJavaPerlCaller.java
new file mode 100644
index 0000000..04eaa38
--- /dev/null
+++ b/Java/sources/InlineJavaPerlCaller.java
@@ -0,0 +1,19 @@
+/*
+	Callback to Perl...
+
+	This class has user visibility so methods must be public.
+*/
+class InlineJavaPerlCaller {
+	public InlineJavaPerlCaller(){
+	}
+
+
+	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 {
+		return InlineJavaServer.instance.Callback(pkg, method, args, cast) ;
+	}
+}
diff --git a/Java/sources/InlineJavaPerlException.java b/Java/sources/InlineJavaPerlException.java
new file mode 100644
index 0000000..4f78755
--- /dev/null
+++ b/Java/sources/InlineJavaPerlException.java
@@ -0,0 +1,21 @@
+/*
+	This object can have user visibility and therefore
+	must have public methods.
+*/
+
+class InlineJavaPerlException extends Exception {
+	private Object obj = null ;
+
+
+	InlineJavaPerlException(Object o) {
+		obj = o ;
+	}
+
+	public Object GetObject(){
+		return obj ;
+	}
+
+	public String GetString(){
+		return (String)obj ;
+	}
+}
diff --git a/Java/Protocol.pm b/Java/sources/InlineJavaProtocol.java
similarity index 58%
copy from Java/Protocol.pm
copy to Java/sources/InlineJavaProtocol.java
index 546ff68..694ae83 100644
--- a/Java/Protocol.pm
+++ b/Java/sources/InlineJavaProtocol.java
@@ -1,422 +1,5 @@
-package Inline::Java::Protocol ;
-
-
-use strict ;
-
-$Inline::Java::Protocol::VERSION = '0.31' ;
-
-use Inline::Java::Object ;
-use Inline::Java::Array ;
-use Carp ;
-
-
-sub new {
-	my $class = shift ;
-	my $obj = shift ;
-	my $inline = shift ;
-
-	my $this = {} ;
-	$this->{obj_priv} = $obj || {} ;
-	$this->{module} = $inline->get_api('modfname') ;
-
-	bless($this, $class) ;
-	return $this ;
-}
-
-
-sub ServerType {
-	my $this = shift ;
-
-	Inline::Java::debug(3, "getting server type") ;
-
-	my $data = "server_type" ;
-
-	return $this->Send($data, 1) ;
-}
-
-
-sub Report {
-	my $this = shift ;
-	my $classes = shift ;
-
-	Inline::Java::debug(3, "reporting on $classes") ;
-
-	my $data = join(" ", 
-		"report", 
-		$this->ValidateArgs([$classes]),
-	) ;
-
-	return $this->Send($data, 1) ;
-}
-
-
-sub ISA {
-	my $this = shift ;
-	my $proto = shift ;
-
-	my $class = $this->{obj_priv}->{java_class} ;
-
-	Inline::Java::debug(3, "checking if $class is a $proto") ;
-
-	my $data = join(" ", 
-		"isa", 
-		Inline::Java::Class::ValidateClass($class),
-		Inline::Java::Class::ValidateClass($proto),
-	) ;
-
-	return $this->Send($data, 1) ;
-}
-
-
-sub ObjectCount {
-	my $this = shift ;
-
-	Inline::Java::debug(3, "getting object count") ;
-
-	my $data = join(" ", 
-		"obj_cnt", 
-	) ;
-
-	return $this->Send($data, 1) ;
-}
-
-
-# Called to create a Java object
-sub CreateJavaObject {
-	my $this = shift ;
-	my $class = shift ;
-	my $proto = shift ;
-	my $args = shift ;
-
-	Inline::Java::debug(3, "creating object new $class" . $this->CreateSignature($args)) ; 	
-
-	my $data = join(" ", 
-		"create_object", 
-		Inline::Java::Class::ValidateClass($class),
-		$this->CreateSignature($proto, ","),
-		$this->ValidateArgs($args),
-	) ;
-
-	return $this->Send($data, 1) ;
-}
-
-
-# Calls a Java method.
-sub CallJavaMethod {
-	my $this = shift ;
-	my $method = shift ;
-	my $proto = shift ;
-	my $args = shift ;
-
-	my $id = $this->{obj_priv}->{id} ;
-	my $class = $this->{obj_priv}->{java_class} ;
-	Inline::Java::debug(3, "calling object($id).$method" . $this->CreateSignature($args)) ;
-
-	my $data = join(" ", 
-		"call_method", 
-		$id,
-		Inline::Java::Class::ValidateClass($class),
-		$this->ValidateMethod($method),
-		$this->CreateSignature($proto, ","),
-		$this->ValidateArgs($args),
-	) ;
-
-	return $this->Send($data) ;
-}
-
-
-# Sets a member variable.
-sub SetJavaMember {
-	my $this = shift ;
-	my $member = shift ;
-	my $proto = shift ;
-	my $arg = shift ;
-
-	my $id = $this->{obj_priv}->{id} ;
-	my $class = $this->{obj_priv}->{java_class} ;
-	Inline::Java::debug(3, "setting object($id)->{$member} = " . ($arg->[0] || '')) ;
-	my $data = join(" ", 
-		"set_member", 
-		$id,
-		Inline::Java::Class::ValidateClass($class),
-		$this->ValidateMember($member),
-		Inline::Java::Class::ValidateClass($proto->[0]),
-		$this->ValidateArgs($arg),
-	) ;
-
-	return $this->Send($data) ;
-}
-
-
-# Gets a member variable.
-sub GetJavaMember {
-	my $this = shift ;
-	my $member = shift ;
-	my $proto = shift ;
-
-	my $id = $this->{obj_priv}->{id} ;
-	my $class = $this->{obj_priv}->{java_class} ;
-	Inline::Java::debug(3, "getting object($id)->{$member}") ;
-
-	my $data = join(" ", 
-		"get_member", 
-		$id,
-		Inline::Java::Class::ValidateClass($class),
-		$this->ValidateMember($member),
-		Inline::Java::Class::ValidateClass($proto->[0]),
-		"undef:",
-	) ;
-
-	return $this->Send($data) ;
-}
-
-
-# Deletes a Java object
-sub DeleteJavaObject {
-	my $this = shift ;
-	my $obj = shift ;
-
-	if (defined($this->{obj_priv}->{id})){
-		my $id = $this->{obj_priv}->{id} ;
-		my $class = $this->{obj_priv}->{java_class} ;
-
-		Inline::Java::debug(3, "deleting object $obj $id ($class)") ;
-
-		my $data = join(" ", 
-			"delete_object", 
-			$id,
-		) ;
-
-		$this->Send($data) ;
-	}
-}
-
-
-# This method makes sure that the method we are asking for
-# has the correct form for a Java method.
-sub ValidateMethod {
-	my $this = shift ;
-	my $method = shift ;
-
-	if ($method !~ /^(\w+)$/){
-		croak "Invalid Java method name $method" ;
-	}	
-
-	return $method ;
-}
-
-
-# This method makes sure that the member we are asking for
-# has the correct form for a Java member.
-sub ValidateMember {
-	my $this = shift ;
-	my $member = shift ;
-
-	if ($member !~ /^(\w+)$/){
-		croak "Invalid Java member name $member" ;
-	}	
-
-	return $member ;
-}
-
-
-# Validates the arguments to be used in a method call.
-sub ValidateArgs {
-	my $this = shift ;
-	my $args = shift ;
-	my $callback = shift ;
-
-	my @ret = () ;
-	foreach my $arg (@{$args}){
-		if (! defined($arg)){
-			push @ret, "undef:" ;
-		}
-		elsif (ref($arg)){
-			if ((! UNIVERSAL::isa($arg, "Inline::Java::Object"))&&(! UNIVERSAL::isa($arg, "Inline::Java::Array"))){
-				if (! $callback){
-					croak "A Java method or member can only have Java objects, Java arrays or scalars as arguments" ;
-				}
-				else{
-					croak "A Java callback function can only return Java objects, Java arrays or scalars" ;
-				}
-			}
-
-			my $obj = $arg ;
-			if (UNIVERSAL::isa($arg, "Inline::Java::Array")){
-				$obj = $arg->__get_object() ; 
-			}
-			my $class = $obj->__get_private()->{java_class} ;
-			my $id = $obj->__get_private()->{id} ;
-			push @ret, "object:$class:$id" ;
-		}
-		else{
-			push @ret, "scalar:" . encode($arg) ;
-		}
-	}
-
-	return @ret ;
-}
-
-
-sub CreateSignature {
-	my $this = shift ;
-	my $proto = shift ;
-	my $del = shift || ", " ;
-
-	my @p = map {$_ || ''} @{$proto} ;
-
-	return "(" . join($del, @p) . ")" ;
-}
-
-
-# This actually sends the request to the Java program. It also takes
-# care of registering the returned object (if any)
-sub Send {
-	my $this = shift ;
-	my $data = shift ;
-	my $const = shift ;
-
-	my $inline = Inline::Java::get_INLINE($this->{module}) ;
-	my $resp = Inline::Java::__get_JVM()->process_command($inline, $data) ;
-
-	if ($resp =~ /^error scalar:([\d.-]*)$/){
-		my $msg = decode($1) ;
-		Inline::Java::debug(3, "packet recv error: $msg") ;
-		croak $msg ;
-	}
-	elsif ($resp =~ s/^ok //){
-		return $this->DeserializeObject($const, $resp) ;
-	}
-
-	croak "Malformed response from server: $resp" ;
-}
-
-
-sub DeserializeObject {
-	my $this = shift ;
-	my $const = shift ;
-	my $resp = shift ;
-
-	if ($resp =~ /^scalar:([\d.-]*)$/){
-		return decode($1) ; 
-	}
-	elsif ($resp =~ /^undef:$/){
-		return undef ;
-	}
-	elsif ($resp =~ /^object:([01]):(\d+):(.*)$/){
-		# Create the Perl object wrapper and return it.
-		my $thrown = $1 ;
-		my $id = $2 ;
-		my $class = $3 ;
-
-		if ($thrown){
-			# If we receive a thrown object, we jump out of 'constructor
-			# mode' and process the returned object.
-			$const = 0 ;
-		}
-
-		if ($const){
-			$this->{obj_priv}->{java_class} = $class ;
-			$this->{obj_priv}->{id} = $id ;
-
-			return undef ;
-		}
-		else{
-			my $inline = Inline::Java::get_INLINE($this->{module}) ;
-			my $pkg = $inline->get_api('pkg') ;
-
-			my $obj = undef ;
-			my $elem_class = $class ;
-
-			Inline::Java::debug(3, "checking if stub is array...") ;
-			if (Inline::Java::Class::ClassIsArray($class)){
-				my @d = Inline::Java::Class::ValidateClassSplit($class) ;
-				$elem_class = $d[2] ;
-			}
-
-
-			my $perl_class = "Inline::Java::Object" ;
-			if ($elem_class){
-				# We have a real class or an array of real classes
-				$perl_class = Inline::Java::java2perl($pkg, $elem_class) ;
-				if (Inline::Java::Class::ClassIsReference($elem_class)){
-					if (! Inline::Java::known_to_perl($pkg, $elem_class)){
-						if (($thrown)||($inline->get_java_config('AUTOSTUDY'))){
-							$inline->_study([$elem_class]) ;
-						}
-						else{	
-							# Object is not known to Perl, it lives as a 
-							# Inline::Java::Object
-							$perl_class = "Inline::Java::Object" ;
-						}
-				 	}
-				}
-			}
-			else{
-				# We should only get here if an array of primitives types
-				# was returned, and there is nothing to do since
-				# the block below will handle it.
-			}
-
-			if (Inline::Java::Class::ClassIsArray($class)){
-				Inline::Java::debug(3, "creating array object...") ;
-				$obj = Inline::Java::Object->__new($class, $inline, $id) ;
-				$obj = new Inline::Java::Array($obj) ;
-				Inline::Java::debug(3, "array object created...") ;
-			}
-			else{
-				$obj = $perl_class->__new($class, $inline, $id) ;
-			}
-
-			if ($thrown){
-				Inline::Java::debug(3, "throwing stub...") ;
-				my ($msg, $score) = $obj->__isa('InlineJavaPerlCaller$PerlException') ;
-				if ($msg){
-					die $obj ;
-				}
-				else{
-					die $obj->GetObject() ;
-				}
-			}
-			else{
-				Inline::Java::debug(3, "returning stub...") ;
-				return $obj ;
-			}
-		}
-	}
-	else{
-		croak "Malformed response from server: $resp" ;
-	}
-}
-
-
-sub encode {
-	my $s = shift ;
-
-	return join(".", unpack("C*", $s)) ;
-}
-
-
-sub decode {
-	my $s = shift ;
-
-	return pack("C*", split(/\./, $s)) ;
-}
-
-
-sub DESTROY {
-	my $this = shift ;
-
-	Inline::Java::debug(4, "destroying Inline::Java::Protocol") ;
-}
-
-
-
-1 ;
-
-
-
-__DATA__
+import java.util.* ;
+import java.lang.reflect.* ;
 
 
 /*
@@ -430,12 +13,13 @@ class InlineJavaProtocol {
 	private String cmd ;
 	private String response ;
 
+
 	InlineJavaProtocol(InlineJavaServer _ijs, String _cmd) {
 		ijs = _ijs ;
 		ijc = new InlineJavaClass(ijs, this) ;
-		ija = new InlineJavaArray(ijs, ijc) ;
+		ija = new InlineJavaArray(ijc) ;
 
-		cmd = _cmd ;		
+		cmd = _cmd ;	
 	}
 
 
@@ -462,7 +46,7 @@ class InlineJavaProtocol {
 			Report(st) ;
 		}
 		else if (c.equals("isa")){
-			ISA(st) ;
+			IsA(st) ;
 		}
 		else if (c.equals("create_object")){
 			CreateJavaObject(st) ;
@@ -474,7 +58,7 @@ class InlineJavaProtocol {
 			ObjectCount(st) ;
 		}
 		else if (c.equals("die")){
-			ijs.debug(1, "received a request to die...") ;
+			InlineJavaUtils.debug(1, "received a request to die...") ;
 			System.exit(0) ;
 		}
 		else {
@@ -492,7 +76,7 @@ class InlineJavaProtocol {
 		StringTokenizer st2 = new StringTokenizer(st.nextToken(), ":") ;
 		st2.nextToken() ;
 
-		StringTokenizer st3 = new StringTokenizer(decode(st2.nextToken()), " ") ;
+		StringTokenizer st3 = new StringTokenizer(Decode(st2.nextToken()), " ") ;
 
 		ArrayList class_list = new ArrayList() ;
 		while (st3.hasMoreTokens()){
@@ -504,7 +88,7 @@ class InlineJavaProtocol {
 			String name = (String)class_list.get(i) ;
 			Class c = ijc.ValidateClass(name) ;
 
-			ijs.debug(3, "reporting for " + c) ;
+			InlineJavaUtils.debug(3, "reporting for " + c) ;
 													
 			pw.append("class " + c.getName() + "\n") ;
 			Constructor constructors[] = c.getConstructors() ;
@@ -516,14 +100,14 @@ class InlineJavaProtocol {
 				// If the class is public and has no constructors,
 				// we provide a default no-arg constructors.
 				if (c.getDeclaredConstructors().length == 0){
-					String noarg_sign = CreateSignature(new Class [] {}) ;
+					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 = CreateSignature(params) ;
+				String sign = InlineJavaUtils.CreateSignature(params) ;
 				Class decl = x.getDeclaringClass() ;
 				pw.append("constructor " + sign + "\n") ;
 			}
@@ -531,13 +115,13 @@ class InlineJavaProtocol {
 			for (int j = 0 ; j < methods.length ; j++){
 				Method x = methods[j] ;
 				String stat = (Modifier.isStatic(x.getModifiers()) ? " static " : " instance ") ;
-				String sign = CreateSignature(x.getParameterTypes()) ;
+				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[(ijs.reverse_members() ? (fields.length - 1 - j) : 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() ;
@@ -554,7 +138,7 @@ class InlineJavaProtocol {
 	}
 
 
-	void ISA(StringTokenizer st) throws InlineJavaException {
+	void IsA(StringTokenizer st) throws InlineJavaException {
 		String class_name = st.nextToken() ;
 		Class c = ijc.ValidateClass(class_name) ;
 
@@ -588,11 +172,12 @@ class InlineJavaProtocol {
 			}
 			catch (InlineJavaInvocationTargetException ite){
 				Throwable t = ite.GetThrowable() ;
-				if (t instanceof InlineJavaPerlCaller.InlineJavaException){
-					throw ((InlineJavaPerlCaller.InlineJavaException)t).GetException() ;
+				if (t instanceof InlineJavaException){
+					InlineJavaException ije = (InlineJavaException)t ;
+					throw ije ;
 				}
 				else{
-					SetResponse(new InlineJavaServerThrown(t)) ;
+					SetResponse(new InlineJavaThrown(t)) ;
 				}
 			}
 		}
@@ -612,7 +197,7 @@ class InlineJavaProtocol {
 
 			Class ec = ijc.ValidateClass(sb.toString()) ;
 
-			ijs.debug(4, "array elements: " + ec.getName()) ;
+			InlineJavaUtils.debug(4, "array elements: " + ec.getName()) ;
 			Object o = ija.CreateArray(ec, st) ;
 			SetResponse(o) ;
 		}
@@ -661,12 +246,13 @@ class InlineJavaProtocol {
 				Throwable t = e.getTargetException() ;
 				String type = t.getClass().getName() ;
 				String msg = t.getMessage() ;
-				ijs.debug(1, "method " + name + " in class " + class_name + " threw exception " + type + ": " + msg) ;
-				if (t instanceof InlineJavaPerlCaller.InlineJavaException){
-					throw ((InlineJavaPerlCaller.InlineJavaException)t).GetException() ;
+				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 InlineJavaServerThrown(t)) ;
+					SetResponse(new InlineJavaThrown(t)) ;
 				}
 			}
 		}
@@ -801,23 +387,23 @@ class InlineJavaProtocol {
 			}
 		}
 		catch (NoSuchMethodException e){
-			throw new InlineJavaException("Constructor for class " + name + " with signature " + ijs.CreateSignature(proto) + " not found: " + e.getMessage()) ;
+			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 " + ijs.CreateSignature(proto) + ": " + e.getMessage()) ;
+			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 " + ijs.CreateSignature(proto) + " are incompatible: " + e.getMessage()) ;
+			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 " + ijs.CreateSignature(proto) + " threw exception " + type + ": " + msg,
+				"Constructor for class " + name + " with signature " + InlineJavaUtils.CreateSignature(proto) + " threw exception " + type + ": " + msg,
 				t) ;
 		}
 
@@ -847,7 +433,7 @@ class InlineJavaProtocol {
 			Member m = ma[i] ;
 
 			if (m.getName().equals(name)){
-				ijs.debug(3, "found a " + name + (constructor ? " constructor" : " method")) ;
+				InlineJavaUtils.debug(3, "found a " + name + (constructor ? " constructor" : " method")) ;
 
 				if (constructor){
 					params = ((Constructor)m).getParameterTypes() ;
@@ -857,11 +443,11 @@ class InlineJavaProtocol {
 				}
 
 				// Now we check if the signatures match
-				String sign = ijs.CreateSignature(params, ",") ;
-				ijs.debug(3, sign + " = " + signature + "?") ;
+				String sign = InlineJavaUtils.CreateSignature(params, ",") ;
+				InlineJavaUtils.debug(3, sign + " = " + signature + "?") ;
 
 				if (signature.equals(sign)){
-					ijs.debug(3, "has matching signature " + sign) ;
+					InlineJavaUtils.debug(3, "has matching signature " + sign) ;
 					ml.add(ml.size(), m) ;
 					break ;
 				}
@@ -929,15 +515,15 @@ class InlineJavaProtocol {
 		ArrayList fl = new ArrayList(fa.length) ;
 		Class param = null ;
 		for (int i = 0 ; i < fa.length ; i++){
-			Field f = fa[(ijs.reverse_members() ? (fa.length - 1 - i) : i)] ;
+			Field f = fa[(InlineJavaUtils.ReverseMembers() ? (fa.length - 1 - i) : i)] ;
 
 			if (f.getName().equals(name)){
-				ijs.debug(3, "found a " + name + " member") ;
+				InlineJavaUtils.debug(3, "found a " + name + " member") ;
 
 				param = f.getType() ;
 				String t = param.getName() ;
 				if (type.equals(t)){
-					ijs.debug(3, "has matching type " + t) ;
+					InlineJavaUtils.debug(3, "has matching type " + t) ;
 					fl.add(fl.size(), f) ;
 				}
 			}
@@ -991,30 +577,28 @@ class InlineJavaProtocol {
 			return "undef:" ;
 		}
 		else if ((ijc.ClassIsNumeric(o.getClass()))||(ijc.ClassIsChar(o.getClass()))||(ijc.ClassIsString(o.getClass()))){
-			return "scalar:" + encode(o.toString()) ;
+			return "scalar:" + Encode(o.toString()) ;
 		}
 		else if (ijc.ClassIsBool(o.getClass())){
 			String b = o.toString() ;
-			return "scalar:" + encode((b.equals("true") ? "1" : "0")) ;
+			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 InlineJavaServerThrown){ 
+			if (o instanceof InlineJavaThrown){ 
 				thrown = true ;
-				o = ((InlineJavaServerThrown)o).GetThrowable() ;
+				o = ((InlineJavaThrown)o).GetThrowable() ;
 			}			
-			int id = ijs.objid ;
-			ijs.PutObject(id, o) ;
+			int id = ijs.PutObject(o) ;
 			return "object:" + (thrown ? "1" : "0") + ":" + String.valueOf(id) +
 				":" + o.getClass().getName() ;
 		}
 	}
 
 
-
-	public String decode(String s){
+	String Decode(String s){
 		StringTokenizer st = new StringTokenizer(s, ".") ;
 		StringBuffer sb = new StringBuffer() ;
 		while (st.hasMoreTokens()){
@@ -1027,7 +611,7 @@ class InlineJavaProtocol {
 	}
 
 
-	public String encode(String s){
+	String Encode(String s){
 		byte b[] = s.getBytes() ;
 		StringBuffer sb = new StringBuffer() ;
 		for (int i = 0 ; i < b.length ; i++){
@@ -1039,5 +623,9 @@ class InlineJavaProtocol {
 
 		return sb.toString() ;
 	}
-}
 
+
+	String GetResponse(){
+		return response ;
+	}
+}
diff --git a/Java/sources/InlineJavaServer.java b/Java/sources/InlineJavaServer.java
new file mode 100644
index 0000000..da1b0ff
--- /dev/null
+++ b/Java/sources/InlineJavaServer.java
@@ -0,0 +1,288 @@
+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 {
+	static InlineJavaServer instance = null ;
+	private int port = 0 ;
+	private boolean shared_jvm = false ;
+
+
+	private InlineJavaUserClassLoader ijucl = null ;
+	private HashMap thread_objects = new HashMap() ;
+	private int objid = 1 ;
+
+
+	// This constructor is used in JNI mode
+	public InlineJavaServer(int d){
+		init(d) ;
+
+		thread_objects.put(Thread.currentThread().getName(), new HashMap()) ;
+	}
+
+
+	// This constructor is used in server mode
+	public InlineJavaServer(String[] argv){
+		init(new Integer(argv[1]).intValue()) ;
+
+		port = Integer.parseInt(argv[2]) ;
+		shared_jvm = new Boolean(argv[3]).booleanValue() ;
+
+		ServerSocket ss = null ;
+		try {
+			ss = new ServerSocket(port) ;	
+		}
+		catch (IOException e){
+			System.err.println("Can't open server socket on port " + String.valueOf(port) +
+				": " + e.getMessage()) ;
+			System.err.flush() ;
+			System.exit(1) ;
+		}
+
+		while (true){
+			try {
+				InlineJavaServerThread ijt = new InlineJavaServerThread(this, ss.accept()) ;
+				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 ;
+		InlineJavaUtils.debug = debug ;
+
+		ijucl = new InlineJavaUserClassLoader() ;
+	}
+
+	
+	String GetType(){
+		return (shared_jvm ? "shared" : "private") ;
+	}
+
+
+	/*
+		Since this function is also called from the JNI XS extension,
+		it's best if it doesn't throw any exceptions.
+		It is public only for testing purposes.
+	*/
+	String ProcessCommand(String cmd) {
+		return ProcessCommand(cmd, true) ;
+	}
+
+
+	private 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 ;
+	}
+
+	
+	Object GetObject(int id) throws InlineJavaException {
+		Object o = null ;
+		String name = Thread.currentThread().getName() ;
+		HashMap h = (HashMap)thread_objects.get(name) ;
+
+		if (h == null){
+			throw new InlineJavaException("Can't find thread " + name + "!") ;
+		}
+		else{
+			o = h.get(new Integer(id)) ;
+			if (o == null){
+				throw new InlineJavaException("Can't find object " + id + " for thread " + name) ;
+			}
+		}
+
+		return o ;
+	}
+
+
+	synchronized int PutObject(Object o) throws InlineJavaException {
+		String name = Thread.currentThread().getName() ;
+		HashMap h = (HashMap)thread_objects.get(name) ;
+
+		int id = objid ;
+		if (h == null){
+			throw new InlineJavaException("Can't find thread " + name + "!") ;
+		}
+		else{
+			h.put(new Integer(objid), o) ;
+			objid++ ;
+		}
+
+		return id ;
+	}
+
+
+	Object DeleteObject(int id) throws InlineJavaException {
+		Object o = null ;
+		String name = Thread.currentThread().getName() ;
+		HashMap h = (HashMap)thread_objects.get(name) ;
+
+		if (h == null){
+			throw new InlineJavaException("Can't find thread " + name + "!") ;
+		}
+		else{
+			o = h.remove(new Integer(id)) ;
+			if (o == null){
+				throw new InlineJavaException("Can't find object " + id + " for thread " + name) ;
+			}
+		}
+
+		return o ;
+	}
+
+
+	int ObjectCount() throws InlineJavaException {
+		int i = -1 ;
+		String name = Thread.currentThread().getName() ;
+		HashMap h = (HashMap)thread_objects.get(name) ;
+
+		if (h == null){
+			throw new InlineJavaException("Can't find thread " + name + "!") ;
+		}
+		else{
+			i = h.values().size() ;
+		}
+
+		return i ;
+	}
+
+
+	Object Callback(String pkg, String method, Object args[], String cast) throws InlineJavaException, InlineJavaPerlException {
+		Object ret = null ;
+
+		try {
+			InlineJavaProtocol ijp = new InlineJavaProtocol(this, null) ;
+			InlineJavaClass ijc = new InlineJavaClass(this, ijp) ;
+			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])) ;
+				}
+			}
+			String cmd = cmdb.toString() ;
+			InlineJavaUtils.debug(2, "callback command: " + cmd) ;
+
+			Thread t = Thread.currentThread() ;
+			String resp = null ;
+			while (true) {			
+				InlineJavaUtils.debug(3, "packet sent (callback) is " + cmd) ;
+				if (t instanceof InlineJavaServerThread){
+					// Client-server mode
+					InlineJavaServerThread ijt = (InlineJavaServerThread)t ;
+					ijt.bw.write(cmd + "\n") ;
+					ijt.bw.flush() ;
+
+					resp = ijt.br.readLine() ;
+				}
+				else{
+					// JNI mode
+					resp = 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() ;
+					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 = ProcessCommand(resp, false) ;
+
+					continue ;
+				}
+			}
+		}
+		catch (IOException e){
+			throw new InlineJavaException("IO error: " + e.getMessage()) ;
+		}
+
+		return ret ;
+	}
+
+
+	native private String jni_callback(String cmd) ;
+
+
+	void AddThread(String name){
+		thread_objects.put(name, new HashMap()) ;
+	}
+
+
+	void RemoveThread(String name){
+		thread_objects.remove(name) ;
+	}
+	
+
+	/*
+		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/InlineJavaServerThread.java b/Java/sources/InlineJavaServerThread.java
new file mode 100644
index 0000000..9a524eb
--- /dev/null
+++ b/Java/sources/InlineJavaServerThread.java
@@ -0,0 +1,48 @@
+import java.io.* ;
+import java.net.* ;
+import java.util.* ;
+
+
+class InlineJavaServerThread extends Thread {
+	InlineJavaServer ijs ;
+	Socket client ;
+	BufferedReader br ;
+	BufferedWriter bw ;
+
+	InlineJavaServerThread(InlineJavaServer _ijs, Socket _client) throws IOException {
+		super() ;
+		client = _client ;
+		ijs = _ijs ;
+
+		br = new BufferedReader(
+			new InputStreamReader(client.getInputStream())) ;
+		bw = new BufferedWriter(
+			new OutputStreamWriter(client.getOutputStream())) ;
+	}
+
+
+	public void run(){
+		try {
+			ijs.AddThread(getName()) ;
+
+			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(getName()) ;
+		}
+	}
+}
diff --git a/Java/sources/InlineJavaTest.java b/Java/sources/InlineJavaTest.java
new file mode 100644
index 0000000..16f27ae
--- /dev/null
+++ b/Java/sources/InlineJavaTest.java
@@ -0,0 +1,8 @@
+class InlineJavaTest {
+	public static void main(String[] args){
+		InlineJavaServer ijs = InlineJavaServer.jni_main(5) ;
+		String resp = ijs.ProcessCommand("server_type") ;
+
+		System.out.println(resp) ;
+	}
+}
diff --git a/Java/sources/InlineJavaThrown.java b/Java/sources/InlineJavaThrown.java
new file mode 100644
index 0000000..92f88bd
--- /dev/null
+++ b/Java/sources/InlineJavaThrown.java
@@ -0,0 +1,11 @@
+class InlineJavaThrown {
+	Throwable t = null ;
+
+	InlineJavaThrown(Throwable _t){
+		t = _t ;
+	}
+
+	Throwable GetThrowable(){
+		return t ;
+	}
+}
diff --git a/Java/sources/InlineJavaUserClassLoader.java b/Java/sources/InlineJavaUserClassLoader.java
new file mode 100644
index 0000000..b8e4f88
--- /dev/null
+++ b/Java/sources/InlineJavaUserClassLoader.java
@@ -0,0 +1,20 @@
+import java.net.* ;
+import java.util.* ;
+
+
+public class InlineJavaUserClassLoader extends URLClassLoader {
+    private HashMap urls = new HashMap() ;
+
+
+    public InlineJavaUserClassLoader(){
+        super(new URL [] {}) ;
+    }
+
+
+    public void AddPath(URL u){
+        if (urls.get(u) == null){
+            urls.put(u, "1") ;
+            addURL(u) ;
+        }
+    }
+}
diff --git a/Java/sources/InlineJavaUtils.java b/Java/sources/InlineJavaUtils.java
new file mode 100644
index 0000000..7d2173a
--- /dev/null
+++ b/Java/sources/InlineJavaUtils.java
@@ -0,0 +1,47 @@
+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 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 df3ff11..0e9445a 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -6,7 +6,6 @@ TODO
 Makefile.PL
 Java.pm
 Java.pod
-Java/Init.pm
 Java/Object.pm
 Java/Protocol.pm
 Java/Class.pm
diff --git a/Makefile.PL b/Makefile.PL
index 3d80d06..637291f 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -1,26 +1,137 @@
 use ExtUtils::MakeMaker ;
+# $Verbose = 2 ;
 
 use strict ;
 use File::Spec ;
+use Config ;
 
 require "Java/Portable.pm" ;
 
-# Replace everything just like out-of-the-box...
-my $xs = File::Spec->catfile("Java", "JNI.xs") ;
-rename($xs . "_", "$xs") ;
-
 print "\nWelcome to the Inline::Java installation procedure.\n\n" ;
 
+# Grab the J2SDK argument
+my @new_args = () ;
+my $jdk_dir = '' ;
+foreach my $arg (@ARGV){
+	if ($arg =~ /^J2SDK=(.+)$/){
+		$jdk_dir = $1 ;
+	}
+	else {
+		push @new_args, $_ ;
+	}
+}
+ at ARGV = @new_args ;
+
+if (! $jdk_dir){
+	print <<NO_J2SDK;
+A Java 2 SDK is required to install and use Inline::Java. Please 
+specify your Java 2 SDK installation directory using the J2SDK 
+option to Makefile.PL as such:
+
+    perl Makefile.PL J2SDK=/path/to/your/j2sdk/installation
+NO_J2SDK
+	exit(1) ;
+}
+elsif (! -d $jdk_dir){
+	print <<BAD_J2SDK;
+Java 2 SDK installation directory '$jdk_dir' does not exist.
+BAD_J2SDK
+	exit(1) ;
+}
+my $perl_jdk_dir = $jdk_dir ;
+$perl_jdk_dir =~ s/'/\'/g ;
+
+# Check directory
+my $ext = Inline::Java::Portable::portable('EXE_EXTENSION') ;
+foreach my $f ('javac', 'jar', 'java'){
+	if (! -x File::Spec->catfile($jdk_dir, 'bin', $f . $ext)){
+		my $bf = File::Spec->catfile('bin', $f . $ext) ;
+		print "Can't locate file '$bf' anywhere under '$jdk_dir'\n" ;
+	}
+}
+
+
+# Now we have the J2SDK directory and it exists. 
+# We will create the DefaultJ2SDK.pl file that
+# will contain that value for future use.
+my $def_jdk = File::Spec->catfile('Java', 'DefaultJ2SDK.pl') ;
+open(J2SDK, ">$def_jdk") or
+	die("Can't open '$def_jdk' for writing: $!") ;
+print J2SDK <<J2SDK_PL;
+# This file is created by the Makefile.PL for Inline::Java
+# You can modify it if you which
+use strict ;
+
+# The default J2SDK to use for Inline::Java. You can change
+# it if this value becomes invalid.
+sub Inline::Java::get_default_j2sdk {
+	return '$perl_jdk_dir' ;
+}
+
+1 ;
+J2SDK_PL
+close(J2SDK) ;
+
+my $ij_site_lib = File::Spec->catdir($Config{installsitelib}, 'Inline', 'Java') ;
+print <<SAVE_J2SDK;
+Default J2SDK for Inline:Java will be '$jdk_dir'.
+See module documentation for information on how to use a different J2SDK
+or change this default value.
+
+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 $src = File::Spec->catfile($src_dir, '*.java') ;
+my $obj_dir = File::Spec->catdir('Java', 'classes') ;
+my $arch_dir = File::Spec->catdir('Java', 'jar') ;
+my $arch = File::Spec->catfile($arch_dir, 'InlineJava.jar') ;
+
+sub MY::postamble {
+	<<MAKE;
+pure_all :: java
+
+java ::
+	\@\$(MKPATH) $obj_dir
+	\@\$(MKPATH) $arch_dir
+	"$javac" -d $obj_dir $src
+	"$jar" cf $arch -C $obj_dir .
+MAKE
+}
+
+
+# Skip the tests for the Java directory
+sub MY::test {
+  my $this = shift ;
+
+  my $hold = delete $this->{DIR} ;
+  my $ret = $this->MM::test(@_) ;
+  $this->{DIR} = $hold if defined($hold) ;
+  return $ret ;
+}
+
+
+# Write the Makefile
 WriteMakefile(
 	NAME => 'Inline::Java',
 	VERSION_FROM => 'Java.pm',
+	DIR => ['Java'],
 	PREREQ_PM => {
 		Inline	=> 0.44
 	},
-	clean => {FILES => '_Inline_test/'},
+	PM => {
+		'Java.pm' => File::Spec->catfile('$(INST_LIBDIR)', 'Java.pm'),
+		'Java.pod'=> File::Spec->catfile('$(INST_LIBDIR)', 'Java.pod'),
+		$arch => File::Spec->catfile('$(INST_LIBDIR)', $arch),
+	},
+	clean => {FILES => "$def_jdk _Inline_test $obj_dir $arch_dir"},
 ) ;
 
 
+# Clean up the Makefile for Win95/98/Me
 if (Inline::Java::Portable::portable('COMMAND_COM')){
 	print "\nFixing Makefile for Win95/98/Me...\n" ;
 	open(MAKEFILE, "<Makefile") or die "Can't open Makefile for reading" ;
diff --git a/TODO b/TODO
index 0c8dd4b..0922b1c 100644
--- a/TODO
+++ b/TODO
@@ -1,4 +1,8 @@
 CODE:
+- Implement AddClassPath
+- Change BIN to J2SDK
+- Fix makfile.PL to build at install time, create jar and config file
+- Fix environment variables
 
 TEST:
 - Alpha
diff --git a/t/01_init.t b/t/01_init.t
index 4cdc2ae..6c0a978 100644
--- a/t/01_init.t
+++ b/t/01_init.t
@@ -13,11 +13,13 @@ use Inline (
 	Java => 'DATA'
 ) ;
 
-
+my $mod = (Inline::Java::get_INLINE_modules())[0] ;
+my $ij = Inline::Java::get_INLINE($mod) ;
+my $jdk = $ij->get_java_config("J2SDK") ;
 my $ver = types1->version() ;
 print STDERR "\nInline version is $Inline::VERSION\n" ;
 print STDERR "Inline::Java version is $Inline::Java::VERSION\n" ;
-print STDERR "J2SDK version is $ver\n" ;
+print STDERR "J2SDK version is $ver, from $jdk\n" ;
 
 if ($ENV{PERL_INLINE_JAVA_EMBEDDED_JNI}){
 	print STDERR "Using JNI extension (embedded).\n" ;
diff --git a/t/no_const.class b/t/no_const.class
index 98ea5ef..79d98bc 100644
Binary files a/t/no_const.class and b/t/no_const.class differ
diff --git a/t/types.class b/t/types.class
index 918c408..fc9e393 100644
Binary files a/t/types.class and b/t/types.class differ

-- 
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