During the last few days, i've been doing some heavy programming incorporating execution of Java code inside our Content Management System. Except the possiblity to run Perl and JavaScript in the webpages the system creates, the marketing people also wanted native Java support. At first, this sounded like an "almost" impossible task (since i had 3.5 working days to fix it). But nothing is impossible =)
Inline::Java fixes the problem to run java inside perl, but once you want java code to call perl subrutines (or methods) things get harder. So i realised it was time to dig into JNI (Java Native Interface) and mix that with perl API calls. Inline::Java is really really nice, but didn't really do what i wanted so i ended up using Jvm.pm which is just an interface to JNI Invokation Interface. We wanted to wrap our perl classes inside Java and that was the problem. This is basiclly what i ended up with:
----------------------------------------
# Wrapper Java class
public class FooWrapper {
int _SVaddr = 0;
static { System.loadLibrary("FooWrapper") }
public FooWrapper(int ptr) {
_SVaddr = ptr;
}
public native void printID();
}
# Some JNI code, compiles to libFooWrapper.so needed for System.loadLibrary
SV *get_sv_reflect(JNIEnv *env, jobject obj) {
SV *reflect_sv;
jclass class_ref;
jfieldID addr_field_ref;
jint addr;
class_ref = (*env)->GetObjectClass(env, obj);
if(!class_ref) return NULL;
addr_field_ref = (*env)->GetFieldID(env, class_ref, "_SVaddr", "I");
if(!addr_field_ref) return NULL;
addr = (*env)->GetIntField(env, obj, addr_field_ref);
if(!addr) return NULL;
reflect_sv = (SV *) addr;
return reflect_sv;
}
JNIEXPORT void JNICALL Java_FooWrapper_printID(JNIEnv *env, jobject obj) {
dSP;
SV *ref;
ref = get_sv_reflect(env, obj);
if(ref) {
ENTER; SAVETMPS; PUSHMARK(SP);
XPUSHs(ref);
PUTBACK;
call_pv("Foo::printID", G_VOID);
FREETMPS;
LEAVE;
}
}
# Our java code
public class Party {
public Party {
}
public void run(FooWrapper foo) {
foo.printID();
}
}
# Some perl code
package Foo;
sub new {
my $class = shift;
my $id = shift;
return bless { id => $id }, $class;
}
sub printID {
my $self = shift;
print "ID is: $self->{id}\n"
}
package main;
use Inline ( C => "int get_sv_addr (SV *var) { return (int) var; }" );
use Jvm;
my $party = new Jvm("Party", "()V");
my $foo = new Foo(10);
my $foow = new Jvm("FooWrapper", "(I)V", get_sv_addr($foo));
$party->run("(LFooWrapper;)V", $foow);
----------------------------------------
The real code i wrote throws Java Exceptions if the perl subrutine/method dies =)
Magic =)
/claes