package Inline::Java::Callback ; use strict ; use Carp ; $Inline::Java::Callback::VERSION = '0.52' ; $Inline::Java::Callback::OBJECT_HOOK = undef ; my %OBJECTS = () ; my $next_id = 1 ; sub InterceptCallback { my $inline = shift ; my $resp = shift ; # With JNI we need to store the object somewhere since we # can't drag it along all the way through Java land... if (! defined($inline)){ $inline = $Inline::Java::JNI::INLINE_HOOK ; } if ($resp =~ s/^callback ([^ ]+) (\@?[\w:]+) ([^ ]+)//){ my $via = $1 ; my $function = $2 ; my $cast_return = $3 ; my @args = split(' ', $resp) ; # "Relative" namespace... if ($via =~ /^::/){ $via = $inline->get_api('pkg') . $via ; } if ($function =~ /^::/){ $function = $inline->get_api('pkg') . $function ; } return Inline::Java::Callback::ProcessCallback($inline, $via, $function, $cast_return, @args) ; } croak "Malformed callback request from server: $resp" ; } sub ProcessCallback { my $inline = shift ; my $via = shift ; my $function = shift ; my $cast_return = shift ; my @sargs = @_ ; my $list_ctx = 0 ; if ($function =~ s/^\@//){ $list_ctx = 1 ; } my $pc = new Inline::Java::Protocol(undef, $inline) ; my $thrown = 'false' ; my $ret = undef ; my @ret = () ; eval { my @args = map { my $a = $pc->DeserializeObject(0, $_) ; $a ; } @sargs ; no strict 'refs' ; if ($via =~ /^(\d+)$/){ # Call via object my $id = $1 ; Inline::Java::debug(2, "processing callback $id" . "->" . "$function(" . join(", ", @args) . ")") ; my $obj = Inline::Java::Callback::GetObject($id) ; if ($list_ctx){ @ret = $obj->$function(@args) ; } else{ $ret = $obj->$function(@args) ; } } elsif ($via ne 'null'){ # Call via package Inline::Java::debug(2, "processing callback $via" . "->" . "$function(" . join(", ", @args) . ")") ; if ($list_ctx){ @ret = $via->$function(@args) ; } else{ $ret = $via->$function(@args) ; } } else { # Straight call Inline::Java::debug(2, "processing callback $function(" . join(", ", @args) . ")") ; if ($function !~ /::/){ $function = 'main' . '::' . $function ; } if ($list_ctx){ @ret = $function->(@args) ; } else{ $ret = $function->(@args) ; } } if ($list_ctx){ $ret = \@ret ; } } ; if ($@){ $ret = $@ ; $thrown = 'true' ; if ((ref($ret))&&(! UNIVERSAL::isa($ret, "Inline::Java::Object"))){ croak "Can't propagate non-Inline::Java reference exception ($ret) to Java" ; } } ($ret) = Inline::Java::Class::CastArgument($ret, $cast_return, $inline) ; # Here we must keep a reference to $ret or else it gets deleted # before the id is returned to Java... my $ref = $ret ; ($ret) = $pc->ValidateArgs([$ret], 1) ; return ("callback $thrown $ret", $ref) ; } sub GetObject { my $id = shift ; my $obj = $OBJECTS{$id} ; if (! defined($obj)){ croak("Can't find object $id") ; } return $obj ; } sub PutObject { my $obj = shift ; my $id = $next_id ; $next_id++ ; $OBJECTS{$id} = $obj ; return $id ; } sub DeleteObject { my $id = shift ; my $quiet = shift || 0 ; my $obj = delete $OBJECTS{$id} ; if ((! $quiet)&&(! defined($obj))){ croak("Can't find object $id") ; } } sub ObjectCount { return scalar(keys %OBJECTS) ; } sub __GetObjects { return \%OBJECTS ; } ########## Utility methods used by Java to access Perl objects ################# sub java_eval { my $code = shift ; Inline::Java::debug(3, "evaling Perl code: $code") ; my $ret = eval $code ; if ($@){ die($@) ; } return $ret ; } sub java_require { my $module = shift ; my $is_file = shift ; if (! defined($is_file)){ if (-e $module){ $module = "\"$module\"" ; } } if ($is_file){ $module = "\"$module\"" ; } Inline::Java::debug(3, "requiring Perl module/file: $module") ; return java_eval("require $module ;") ; } sub java_finalize { my $id = shift ; my $gc = shift ; Inline::Java::Callback::DeleteObject($id, $gc) ; } 1 ;