Welcome to the Frightening World of Java/Perl interoperability!

There are two parts to this:
1. The 'Backend' - which is contained in 'Java.jar'.  The backend must be
running for the 'Frontend' (part #2) to work.  Run 'install_java_server.pl'
to get this part going.  The 'main' Java class is called 'JavaServer' so
you end up running the thing as 'java -classpath <classpath> JavaServer'
JavaServer listens on a port for incoming connexions from Frontends - you
can alter the default port of 2000 by specifying it on the command line link:
java -classpath <classpath> JavaServer 8000
Will start the server listening on port 8000.  You would then need to tell
the Java Perl module to connect to port 8000 instead of the default like:
my $java = new Java(port => 8000);
More on this below.
2. The 'Frontend' - which is the Perl module 'Java.pm' which you install
as any other Perl module.

First be sure to run 'install_java_server.pl' to get your JavaServer environment
set up and happy.
Make sure 'JavaServer' is up and running before you try to run any tests!

Basically you just need to add 'Java.jar' to your classpath on the 'java'
command line (which unfortunately forces you to also add in classes.zip
manually).  Run the 'install_java_server.pl' and it will create a shell
or batch file for you (most likely) - or at least tell you what you need to
to.

Here is the actual perldoc on Java.pm so I don't have to re-type it!

NAME
   Java - Perl extension for accessing a JVM remotely or locally

SYNOPSIS
     use Java;
     $java = new Java;
     $frame = $java->create_object("java.awt.Frame","Frame's Title");
     $frame->setSize(400,400);
     $frame->show();
     $java->do_event($frame,"addWindowListener",\&event_handler);

     $array = $java->create_array("java.lang.String",5);
     // Set array element 3 to "Java is lame"
     $array->set_field(3,"Java is lame");
     $element = $array->get_field(3)->get_value();

     $button = $java->create_object("java.awt.Button","Push Me");
     // Listen for 'Action' events from $button object
     $java->do_event($button,"addActionListener",\&event_handler);

     // Loop & wait mode
     while(1)
     {
          my $continue = $java->go;
          last if (!defined $continue);
     }

     // Got an event!
     sub event_handler
     {
           my($object_that_caused_event,$event_object) = @_;
           if ($object_that_caused_event->same($button))
           {
                   // From $button!
                   print "You pushed my button!!\n";
           }
     }

DESCRIPTION
   This module allows you to talk to a JVM on a local or remote machine.
   You can create objects, call functions, access fields, deal with arrays,
   get events & all the nonsense you can do in Java - from Perl!

 Starting a JVM server

   First you must run 'JavaServer' on the machine to which you will make
   connections. Simply to a 'java JavaServer' to start the server. By
   default it will start listening on port 2000. Make sure the
   'JavaServer.jar' is in your classpath - also make sure the Swing stuff
   (JFC if you prefer) is in your classpath as well if you want to use
   Swing stuff (note this does not apply to JVM 1.2+).

 Creating the root Java object

   You connect to a remote (or local) JVM when you create a new Java
   instance. The new call accepts a hash with the following keys:

           host => hostname of remote machine to connect to
                           default is 'localhost'
           port => port the JVM is listening on (JavaServer)
                           default is 2000
           event_port => port that the remote JVM will send events to
                           default is 2001

   For example:

           $java = new Java(host => "java.zzo.com", event_port => 4032);
           $java2 = new Java(port => 8032);

   You can have any number of java 'environments' in a Perl program.

   Also if you 'use strict' you must do a 'no struct 'subs'' 'cuz all Java
   method calls are AUTOLOAD'ed - sorry.

 Creating java primitives

   The Java.pm module will treat all integers encountered in parameter
   lists as integer and strings as java Strings. All other primitive types
   must be suffixed with an identifier so Java.pm knows what primitive Java
   type to convert it to - for instance boolean types are tagged like:
   "true:b" or "false:b"

   Here's a complete list of supported Java primitives:

           Perl String Value  -> (converted to) -> Java Primitive
           -----------------                       --------------
           "2344"                                  int
           "23:short"                              short
           "23:byte"                               byte
           "a:char"                                char
           "23445:long"                            long
           "3.42:float"                            float
           "3.14159:double"                        double
           "true:b" or "false:b"                   boolean
           "Anything else"                         String

 Creating java objects

   Once you've connected to a JVM via the 'new Java' call you can start
   creating Java objects. This is accomplished via the 'create_object'
   function. The first argument must be the 'fully-qualified'/'full path'
   of the Java object you want to create - like 'java.lang.String' or
   'java.awt.Frame'. The remaining arguments are passed to that object's
   constructor.

   For example:

           my $frame = $java->create_object("java.awt.Frame","Frame Title");
           my $dialog = $java->create_object("java.awt.Dialog",$frame,
                           "Dialog Title","true:b");

   Note the use of "true:b" in the constructor to tell Java.pm that that
   value should be a 'true' Java boolean value.

   In these cases a 'java.awt.Frame' takes a String as the lone parameter,
   whereas a 'java.awt.Dialog' takes a Frame, a String, and a boolean value
   in its constructor.

 Calling java methods

   You can make both static and instantiated method calls on java objects.
   The parameter lists work exactly like constructor parameter lists - if
   you want to pass a java primitive anything other than integers or
   Strings need to be tagged accordingly. All function calls that return
   something return a java object - so even if the java function returns an
   'int' it is returned to perl as a 'java.lang.Integer'. To get the value
   of that Integer you must use the 'get_value' function. The syntax is
   exactly what you'd expect (I hope!).

   For example:

           $frame->setSize(200,500);
           $frame->show();  (or $frame->show)

   Note functions that don't take any parameters don't need the
   parentheses!

   To call static functions the syntax is slightly different.

   For example:

   To call the static method 'forName' in the object 'java.lang.Class' it
   looks like this:

           my $class = $java->java_lang_Class("forName","Test");

   Note you use the '$java' object returned from the call to 'new Java' to
   access static methods - the static object must be fully-qualified
   separated by '_'s instead of '.'s. And finally the first parameter is
   the name of the static function followed by any parameters to it.

 Getting and Setting java object fields

   You can get and set individual fields in java objects (static or
   instantiated) using the 'get_field' and 'set_field' methods. All
   'get_field' calls return java objects just like calling java functions.
   You must use the 'get_value' function to 'unwrap' primitive types to
   their actual values.

   For example:

   Get a static field

           my $win_act = $java->get_field("java.awt.event.WindowEvent",
                                                   "WINDOW_ACTIVATED");

   Note the first parameter must be the fully qualified java object name
   and the second parameter is the static field.

   Get an instantiated field

           my $obj = $java->create_object("java.my.Object");
           my $field = $obj->get_field("my_field");

   Similarly to set a field another parameter is added to the 'set_field'
   call with the object that the specified field is to be set to:

   Set a static field

           $java->set_field("java.static.Object","field_name",$obj);

   Set an instantiated field

           $obj->set_field("integer_field_name",400);

 Comparing Java objects

   You can see if two references to java objects actually point to the same
   object by using the 'same' function like:

           if ($object1->same($object2))
           {
                   # They're the same!
           }
           else
           {
                   # Nope, not the same
           }

   You'll see why this is useful in the next section 'Events'.

 Events

   Events are passed from the remote JVM to Perl5 via a separate event
   port. To enable events on an object use the 'do_event' function. Your
   callback function will receive the object that caused the event as its
   first parameter and the event object itself as the second parameter.
   Here's where ya wanna use the 'same' function to see what object caused
   this event if you set up multiple objects to call the same event
   function.

   For example:

           my $frame = $java->create_object("java.awt.Frame","Title");
           $java->do_event($frame,"addWindowListener",\&event_handler);
           my $button = $java->create_object("java.awt.Button","Push Me");
           $java->do_event($button,"addActionListener",\&event_handler);

   To stop listening for events do:

           $java->do_event($frame,"removeWindowListener");

   Where: - $frame is the object for which you'd like to receive events -
   "addWindowListener" specifies the types of events you want to listen for
   - \&event_handler is your event callback routing that will handle these
   events

   You will keep receiving events you registered for until you make a
   "remove" call or your Java object goes away (out of scope, you destroy
   it, whatever).

   Note the second parameter MUST be of the form:

           "<add | remove><Event Type>Listener"

   Default <Event Types> are:

           Component
           Container
           Focus
           Key
           Mouse
           MouseMotion
           Window
           Action
           Item
           Adjustment
           Text

   Swing <Event Types> are:

           Ancestor
           Caret
           CellEditor
           Change
           Hyperlink
           InternalFrame
           ListData
           ListSelection
           MenuDragMouse
           MenuKey
           Menu
           PopupMenu
           TreeExpansion
           TreeSelection
           TreeWillExpand

   And within most of these <Event Types> there are a number of specific
   events. Check out the Java event docs if you don't know what I'm talking
   about...

   Here's what an event handler looks like:

           sub event_handler
           {
                   my($object,$event) = @_;
                   if ($object->same($frame))
                   {
                           # Event caused by our frame object!

                           # This will get this event's ID value
                           my $event_id = $event->getID->get_value;

                           # Get value for a WINDOW_CLOSING event
                           my $closing_id = $java->get_field("java.awt.event.WindowEvent","WINDOW_CLOSING")->get_value;

                           if ($event_id == $closing_id)
                           {
                                   # Close our frame @ user request
                                   $object->dispose;
                           }
                   }
                   if ($object->same($button))
                   {
                           print "You Pushed My Button!\n";
                   }
           }

   Note return values from event handlers are ignored by Java.pm BUT are
   returned from the Event Loop as you'll see in a bit.

   Note also how I had to call 'get_value' to get the actualy integer
   values of the 'getID' function return value and the field value of
   WINDOW_CLOSING.

 Event Loops

   Once you've set up your event handlers you must start the event loop to
   begin getting events - there are two ways to do this.

           1. Have Java.pm handle the event loop
           2. Roll your own.

   Java.pm's event loop will block until an events happens - typically this
   is what you want but sometimes you might want more control, so I've
   decided to be nice this _one_ time & let you roll your own too.

   Here's how Java.pm's event loop works for ya:

           #
           # Set up a bunch of events...
           #

           while(1)
           {
                   my $cont = $java->go;
                   last if (!defined $cont);
           }

   Note this works similarly to Tk's event loop. Your program will now just
   sit & respond to events via your event handlers. Also note that
   Java.pm's event loop only handles ONE event & then returns - the return
   value is whatever your event handler returned OR undef if there was an
   error (like you lost yer connexion to the JVM).

   Here's how you can create yer own Event Loop:

   You ask Java.pm for a FileHandle that represents the incoming event
   stream. You can then select on this FileHandle or do whatever else you
   want - remember this is a READ ONLY FileHandle so writing to it ain't
   going to do anything. Once you get a 'line' from this FileHandle you can
   (and probably should) call 'decipher_event' & the event will be
   dispatched to your event handler appropriately - the return value being
   the return value of your event handler. This can look something like
   this:

           ## Roll my own event loop

           # Get event FileHandle
           my $event_file_handle = $java->get_event_FH;

           # Set up my select loop
           my $READBITS = 0;
           vec($READBITS,$event_file_handle->fileno,1) = 1;

           # Suck in lines forever & dispatch events
           while(1)
           {
                   my $nf = select(my $rb = $READBITS,undef,undef,undef);
                   if ($nf)
                   {
                           my $event_line = <$event_file_handle>;
                           $java->decipher_event($event_line);
                   }
           }

   Note this example is EXACTLY what Java.pm's 'go' function does - if you
   roll yer own Event Loop you prolly want to do something more interesting
   than this!

   The upshot is you'll probably just want to use the 'go' function but if
   you've got some other FileHandles going on & you don't want to block on
   just this one you can (and should) use the 'roll your own' method.

 Getting values

   To 'unwrap' java primitives (including Strings) you need to call the
   'get_value' function. This will stringify any object given to it -
   typcially this is only useful for 'unwrapping' java primitives and
   Strings.

   For example:

           my $string1 = $java->create_object("java.lang.String","Mark");
           my $string2 = $java->create_object("java.lang.String","Jim");

           if ($string1 eq $string2)
           {
                   # WRONG!!!
                   # $string1 & $string2 are objects!
           }

           if ($string1->get_value eq $string2->get_value)
           {
                   # RIGHT!!!
                   # now you're comparing actual strings...
           }

 Arrays

   Arrays are created with the 'create_array' function call. It needs a
   fully-qualified java object and a dimension.

   For example:

           # This will create a String array with 5 elements
           my $array = $java->create_array("java.lang.String",5);

   Array elements are get and set using the 'get_field' and 'set_field'
   function calls.

   For example:

           # Set element #3 to 'Mark Rox'
           $array->set_field(3,"Mark Rox");

           # Get element #4
           my $element_4 = $array->get_field(4);

           # Don't forget to get the actual string value you gotta call
           #       'get_value'!
           my $string_value = $element_4->get_value;

   To get the length of an array use the get_length function.

   For example:

           my $length = $array->get_length;

   Note this will return an actual integer! You do not need to call
   'get_value' on 'get_length's return value!

 EXPORT

   None by default.

AUTHOR
   Mark Ethan Trostler, [email protected]

SEE ALSO
   perl(1). http://www.javasoft.com/. Any sorta Java documentation you can
   get yer hands on!


JavaServer Tested On Matrix:

       JVM     1.1.8           1.2
Platorm
-------
NetBSD          Yep             <Not available>
Solaris         <Not tested>    Yep
Windows '98     Yep             Yep
Linux           Yep             <Not tested>

In theory - according to 'Write Once Run Anywhere' that is! - JavaServer should run no problem under any 1.1+ JVM.  It doesn't really do anything too fancy.
The 'SwingEventListener' does need Swing to be loaded (or accessible) to the
JVM to use Swing events & of course Swing classes.
You can run JavaServer just fine if Swing isn't available - it'll automatically
detect that Swing isn't available and use 'EventListener' rather than
'SwingEventListener'.  That gets ya all the plain old AWT events.
'SwingEventListener' subclasses 'EventListener' & just adds all them bizzare
Swing events.

A great place to look is the 'test.pl' script...