| 1 | =head1 NAME
|
|---|
| 2 |
|
|---|
| 3 | Tutorial - Perl and Java
|
|---|
| 4 |
|
|---|
| 5 | =head1 SYNOPSIS
|
|---|
| 6 |
|
|---|
| 7 | Java and Perl have different strengths and complement each other well.
|
|---|
| 8 |
|
|---|
| 9 | You can connect them at runtime with tools such as JPL, PJC, or
|
|---|
| 10 | ActiveX. In theory, you can convert Perl to Java bytecode, and
|
|---|
| 11 | vice-versa.
|
|---|
| 12 |
|
|---|
| 13 | =head2 Note:
|
|---|
| 14 |
|
|---|
| 15 | Not actually a conversion.
|
|---|
| 16 |
|
|---|
| 17 | At this stage, we are generating Java opcodes by walking Perl's syntax
|
|---|
| 18 | tree. This is very different from converting Perl to Java. It's a lot
|
|---|
| 19 | easier!
|
|---|
| 20 |
|
|---|
| 21 | =head1 1.1 Perl and Java, Compared
|
|---|
| 22 |
|
|---|
| 23 | Perl offers rich text processing features, high-level network APIs,
|
|---|
| 24 | excellent database integration, and a centralized repository of
|
|---|
| 25 | reusable code:
|
|---|
| 26 |
|
|---|
| 27 | =over 4
|
|---|
| 28 |
|
|---|
| 29 | =item *
|
|---|
| 30 |
|
|---|
| 31 | Regular expression engine is a powerful sub language that can perform
|
|---|
| 32 | complex text manipulations and extract data.
|
|---|
| 33 |
|
|---|
| 34 | =item *
|
|---|
| 35 |
|
|---|
| 36 | Packages such as libwww-perl (LWP) and libnet are powerful, high-level
|
|---|
| 37 | interfaces to network functionality.
|
|---|
| 38 |
|
|---|
| 39 | =item *
|
|---|
| 40 |
|
|---|
| 41 | The Perl DBI is an interface to SQL data sources.
|
|---|
| 42 |
|
|---|
| 43 | =item *
|
|---|
| 44 |
|
|---|
| 45 | CPAN provides a centralized, organized archive of reusable code.
|
|---|
| 46 |
|
|---|
| 47 | =back
|
|---|
| 48 |
|
|---|
| 49 | Java has a powerful graphical API, has numerous embedded
|
|---|
| 50 | implementations, excellent database integration, but no single
|
|---|
| 51 | recognized repository of reusable code.
|
|---|
| 52 |
|
|---|
| 53 | =over 4
|
|---|
| 54 |
|
|---|
| 55 | =item *
|
|---|
| 56 |
|
|---|
| 57 | The Swing (JFC) toolkit is a powerful toolkit for developing user
|
|---|
| 58 | interfaces. Java also boasts 2D and 3D graphics APIs.
|
|---|
| 59 |
|
|---|
| 60 | =item *
|
|---|
| 61 |
|
|---|
| 62 | Java comes in embedded flavors, such as:
|
|---|
| 63 |
|
|---|
| 64 | =over 4
|
|---|
| 65 |
|
|---|
| 66 | =item *
|
|---|
| 67 |
|
|---|
| 68 | Kaffe C<http://www.transvirtual.com/> - embedded implementations for
|
|---|
| 69 | different platforms
|
|---|
| 70 |
|
|---|
| 71 | =item *
|
|---|
| 72 |
|
|---|
| 73 | Waba C<http://www.wabasoft.com/> - a subset of Java for Windows CE and
|
|---|
| 74 | PalmOS
|
|---|
| 75 |
|
|---|
| 76 | =item *
|
|---|
| 77 |
|
|---|
| 78 | It's embedded into web browsers (Netscape and MS Internet Explorer)
|
|---|
| 79 |
|
|---|
| 80 | =item *
|
|---|
| 81 |
|
|---|
| 82 | and more...
|
|---|
| 83 |
|
|---|
| 84 | =back
|
|---|
| 85 |
|
|---|
| 86 | =item *
|
|---|
| 87 |
|
|---|
| 88 | Java's JDBC is similar to Perl's DBI
|
|---|
| 89 |
|
|---|
| 90 | =item *
|
|---|
| 91 |
|
|---|
| 92 | Java has many different repositories of code. Efforts such as the
|
|---|
| 93 | Giant Java Tree C<http://www.gjt.org/> attempt to create a unified
|
|---|
| 94 | repository.
|
|---|
| 95 |
|
|---|
| 96 | =back
|
|---|
| 97 |
|
|---|
| 98 | =head1 1.2 Opportunities to Combine Java and Perl
|
|---|
| 99 |
|
|---|
| 100 | You have a Java program with a lot of data that needs to be parsed,
|
|---|
| 101 | filed, briefed, debriefed, and numbered.
|
|---|
| 102 |
|
|---|
| 103 | You want to build your GUI in Java, but let Perl do the heavy lifting.
|
|---|
| 104 |
|
|---|
| 105 | You've adopted the "Java is a systems language, Perl is a scripting
|
|---|
| 106 | language" paradigm, and it works for you.
|
|---|
| 107 |
|
|---|
| 108 | You're not sure which regex implementation to use:
|
|---|
| 109 |
|
|---|
| 110 | C<org.teeth.green.loony.raving.monster.regex.*;>
|
|---|
| 111 |
|
|---|
| 112 | C<com.zeppelin.regex.*;>
|
|---|
| 113 |
|
|---|
| 114 | You want the I<B<best of both worlds>>.
|
|---|
| 115 |
|
|---|
| 116 | =head1 1.3 Important Differences between Java and Perl
|
|---|
| 117 |
|
|---|
| 118 | =over 4
|
|---|
| 119 |
|
|---|
| 120 | =item *
|
|---|
| 121 |
|
|---|
| 122 | C<perl> compiles and executes programs each time you run them (unless you
|
|---|
| 123 | use the Perl compiler).
|
|---|
| 124 |
|
|---|
| 125 | =item *
|
|---|
| 126 |
|
|---|
| 127 | C<javac> compiles programs in advance, C<java> runs them in the Java
|
|---|
| 128 | interpreter.
|
|---|
| 129 |
|
|---|
| 130 | =item *
|
|---|
| 131 |
|
|---|
| 132 | The Java interpreter supports method overloading (methods can have the
|
|---|
| 133 | same name, but are differentiated on the basis of their argument
|
|---|
| 134 | types). Overloaded methods generally perform the same function, but
|
|---|
| 135 | methods with a shorter argument list often use defaults:
|
|---|
| 136 |
|
|---|
| 137 | =back
|
|---|
| 138 |
|
|---|
| 139 | // Draw a circle in the center of the screen
|
|---|
| 140 | int drawCircle(int radius);
|
|---|
| 141 |
|
|---|
| 142 | // Draw a circle at specified coordinates
|
|---|
| 143 | int drawCircle(int radius, int h, int k);
|
|---|
| 144 |
|
|---|
| 145 | =over 4
|
|---|
| 146 |
|
|---|
| 147 | =item *
|
|---|
| 148 |
|
|---|
| 149 | The Perl interpreter doesn't support method overloading. In JPL, when
|
|---|
| 150 | we call Java from Perl, we need to use some tricks to specify the Java
|
|---|
| 151 | method we want to invoke. We'll learn about this when we see JPL's
|
|---|
| 152 | C<getmeth> function.
|
|---|
| 153 |
|
|---|
| 154 | =back
|
|---|
| 155 |
|
|---|
| 156 | =head2 Note:
|
|---|
| 157 |
|
|---|
| 158 | At the time this presentation was prepared, JPL did not work with Perl
|
|---|
| 159 | for Win32. However, JPL is in the core Perl distribution, and there
|
|---|
| 160 | are plans to make it work with Perl for Win32.
|
|---|
| 161 |
|
|---|
| 162 | With that in mind, I'm presenting the JPL material first, because it
|
|---|
| 163 | is of interest to both Win32 and Unix Perl people. The Win32-specific
|
|---|
| 164 | stuff (alternatives to JPL) will come last. I won't be offended if the
|
|---|
| 165 | Unix people leave when I move to this section of the tutorial, since
|
|---|
| 166 | there is no Unix material in that section. I'm perfectly happy to take
|
|---|
| 167 | questions between JPL and ActiveX sections.
|
|---|
| 168 |
|
|---|
| 169 | A subset of JPL now works on Win32. You can embed Java in Perl, but
|
|---|
| 170 | you cannot embed Perl in Java (yet).
|
|---|
| 171 |
|
|---|
| 172 | =head1 2.1 JPL Overview
|
|---|
| 173 |
|
|---|
| 174 | Let's look at an overview of JPL.
|
|---|
| 175 |
|
|---|
| 176 | =head2 2.1.1 Calling Perl from Java
|
|---|
| 177 |
|
|---|
| 178 | Well-supported by JPL, but it is a complicated process:
|
|---|
| 179 |
|
|---|
| 180 | =over 4
|
|---|
| 181 |
|
|---|
| 182 | =item *
|
|---|
| 183 |
|
|---|
| 184 | The JPL preprocessor parses the I<.jpl> file and generates C code
|
|---|
| 185 | wrappers for Perl methods. It also generates Java and Perl source
|
|---|
| 186 | files.
|
|---|
| 187 |
|
|---|
| 188 | =item *
|
|---|
| 189 |
|
|---|
| 190 | The C compiler compiles the wrapper and links it to the
|
|---|
| 191 | I<libPerlInterpreter.so> shared library, producing a shared library for
|
|---|
| 192 | the wrapper.
|
|---|
| 193 |
|
|---|
| 194 | =item *
|
|---|
| 195 |
|
|---|
| 196 | The Java compiler compiles the Java source file, which uses native
|
|---|
| 197 | methods to load the wrapper.
|
|---|
| 198 |
|
|---|
| 199 | =item *
|
|---|
| 200 |
|
|---|
| 201 | The wrapper connects the Java code to the Perl code in the Perl source
|
|---|
| 202 | file.
|
|---|
| 203 |
|
|---|
| 204 | =back
|
|---|
| 205 |
|
|---|
| 206 | Fortunately, a generic F<Makefile.PL> simplifies the process. This is a
|
|---|
| 207 | Perl script that generates a I<Makefile> for you.
|
|---|
| 208 |
|
|---|
| 209 | =head2 2.1.2 Calling Java from Perl
|
|---|
| 210 |
|
|---|
| 211 | This works best when Perl is embedded within a Java program.
|
|---|
| 212 |
|
|---|
| 213 | The JNI Perl module creates and loads a JVM. There is no precompiler,
|
|---|
| 214 | nothing extra -- it's just a Perl module and extension.
|
|---|
| 215 |
|
|---|
| 216 | B<A Problem, Though>. In theory, you can call Java from standalone
|
|---|
| 217 | Perl programs, but this doesn't work because some implementations
|
|---|
| 218 | of Java use a user-level threads package (green threads) that
|
|---|
| 219 | override some functions in the C library. Perl is comfortable
|
|---|
| 220 | using these functions, but Java is not happy using the standard C
|
|---|
| 221 | library functions.
|
|---|
| 222 |
|
|---|
| 223 | So, with green threads, you can't reliably embed Java in a standalone
|
|---|
| 224 | Perl program.
|
|---|
| 225 |
|
|---|
| 226 | Many Java implementations now use native threads. JPL has been tested
|
|---|
| 227 | on Solaris with JDK 1.1.x and native threads, but not on Linux.
|
|---|
| 228 |
|
|---|
| 229 | =head2 Note:
|
|---|
| 230 |
|
|---|
| 231 | Oddly enough, this is the only way it works on Win32.
|
|---|
| 232 |
|
|---|
| 233 | On Unix, I've still had trouble, even with native threads. I might
|
|---|
| 234 | need to recompile perl with -DREENTRANT, but I'm not sure.
|
|---|
| 235 |
|
|---|
| 236 |
|
|---|
| 237 | =head1 2.2 Working with JPL
|
|---|
| 238 |
|
|---|
| 239 | How to set up a JPL application, compile, and install it.
|
|---|
| 240 |
|
|---|
| 241 | =head2 2.2.1 Setting up a Project
|
|---|
| 242 |
|
|---|
| 243 | =over 4
|
|---|
| 244 |
|
|---|
| 245 | =item 1
|
|---|
| 246 |
|
|---|
| 247 | The I<install-jpl> script creates the I<setvars> script. Source the
|
|---|
| 248 | output of I<setvars> into your shell when you want to develop or run
|
|---|
| 249 | JPL applications.
|
|---|
| 250 |
|
|---|
| 251 | =item 2
|
|---|
| 252 |
|
|---|
| 253 | Create a directory with the name of your project, such as
|
|---|
| 254 | I<Frotz>. (if you want to use the generic F<Makefile.PL>, you need a
|
|---|
| 255 | separate directory for each JPL class you create).
|
|---|
| 256 |
|
|---|
| 257 | =item 3
|
|---|
| 258 |
|
|---|
| 259 | Copy the generic F<Makefile.PL> into the project directory. The
|
|---|
| 260 | I<jpl/Sample> directory in the Perl distribution includes the generic
|
|---|
| 261 | F<Makefile.PL>.
|
|---|
| 262 |
|
|---|
| 263 | =item 4
|
|---|
| 264 |
|
|---|
| 265 | Write a I<.jpl> program with the same name as the project (such as
|
|---|
| 266 | F<Frotz.jpl>)
|
|---|
| 267 |
|
|---|
| 268 | =back
|
|---|
| 269 |
|
|---|
| 270 | =head2 2.2.2 Compiling and Installing a Project
|
|---|
| 271 |
|
|---|
| 272 | Type C<make> to compile the application, and C<make install> to
|
|---|
| 273 | install it. This installs the application in the I<jpl> directory you
|
|---|
| 274 | created when you installed JPL.
|
|---|
| 275 |
|
|---|
| 276 | B<Beware>. The default I<jpl> directory is the same as the
|
|---|
| 277 | directory you install it I<from>. If you go with the default and
|
|---|
| 278 | delete your Perl source, you'll delete your JPL installation!
|
|---|
| 279 |
|
|---|
| 280 | Type C<java Frotz> (or the name you chose in step 2 of section 2.2.1)
|
|---|
| 281 | to run it
|
|---|
| 282 |
|
|---|
| 283 | =head2 2.2.3 What's in the jpl Directory?
|
|---|
| 284 |
|
|---|
| 285 | =over 4
|
|---|
| 286 |
|
|---|
| 287 | =item *
|
|---|
| 288 |
|
|---|
| 289 | B<libPerlInterpreter.so>: a shared library that loads the Perl
|
|---|
| 290 | interpreter.
|
|---|
| 291 |
|
|---|
| 292 | =item *
|
|---|
| 293 |
|
|---|
| 294 | Compiled F<.class> files for JPL applications you have written.
|
|---|
| 295 |
|
|---|
| 296 | =item *
|
|---|
| 297 |
|
|---|
| 298 | Native code shared library wrappers for JPL applications you have
|
|---|
| 299 | written.
|
|---|
| 300 |
|
|---|
| 301 | =item *
|
|---|
| 302 |
|
|---|
| 303 | Perl scripts that contain the Perl code to load at runtime.
|
|---|
| 304 |
|
|---|
| 305 | =back
|
|---|
| 306 |
|
|---|
| 307 | Beware. If you issue the C<make> command and then run the examples
|
|---|
| 308 | in your development directory, you might be in for a surprise! If
|
|---|
| 309 | the JPL directories come first in your CLASSPATH and
|
|---|
| 310 | LD_LIBRARY_PATH, you'll keep running the installed, older version,
|
|---|
| 311 | rather than the one you are developing
|
|---|
| 312 |
|
|---|
| 313 | =head2 Note:
|
|---|
| 314 |
|
|---|
| 315 | "Source" means to load it into your current shell, with something
|
|---|
| 316 | like:
|
|---|
| 317 |
|
|---|
| 318 | C<eval-backtick-setvars-backtick>
|
|---|
| 319 |
|
|---|
| 320 | as opposed to just executing it, because then only the subshell gets
|
|---|
| 321 | the environment vars.
|
|---|
| 322 |
|
|---|
| 323 | =head1 2.3 Calling Perl from Java
|
|---|
| 324 |
|
|---|
| 325 | Now, we'll look at how you can invoke Perl from Java.
|
|---|
| 326 |
|
|---|
| 327 | =head2 2.3.1 Perl Methods
|
|---|
| 328 |
|
|---|
| 329 | You can put Perl methods in your F<.jpl> file. Perl methods are
|
|---|
| 330 | declared C<perl> and use double curly braces to make life easier on
|
|---|
| 331 | the JPL preprocessor:
|
|---|
| 332 |
|
|---|
| 333 | perl int perlMultiply(int a, int b) {{
|
|---|
| 334 | my $result = $a * $b;
|
|---|
| 335 | return $result;
|
|---|
| 336 | }}
|
|---|
| 337 |
|
|---|
| 338 | In your Java code, you can invoke Perl methods like a Java method. The
|
|---|
| 339 | native code wrappers take care of running the Perl code:
|
|---|
| 340 |
|
|---|
| 341 | public void invokePerlFunction() {
|
|---|
| 342 | int x = 3;
|
|---|
| 343 | int y = 6;
|
|---|
| 344 | int retval = perlMultiply(x, y);
|
|---|
| 345 | System.out.println(x + " * " + y + " = " + retval);
|
|---|
| 346 | }
|
|---|
| 347 |
|
|---|
| 348 | class MethodDemo
|
|---|
| 349 |
|
|---|
| 350 | class MethodDemo {
|
|---|
| 351 | // A Perl method to multiply two numbers and
|
|---|
| 352 | // return the result.
|
|---|
| 353 | //
|
|---|
| 354 | perl int perlMultiply(int a, int b) {{
|
|---|
| 355 | my $result = $a * $b;
|
|---|
| 356 | return $result;
|
|---|
| 357 | }}
|
|---|
| 358 |
|
|---|
| 359 | // A Java method to call the Perl function.
|
|---|
| 360 | //
|
|---|
| 361 | public void invokePerlFunction() {
|
|---|
| 362 | int x = 3;
|
|---|
| 363 | int y = 6;
|
|---|
| 364 | int retval = perlMultiply(x, y);
|
|---|
| 365 | System.out.println(x +" * "+ y +" = "+ retval);
|
|---|
| 366 | }
|
|---|
| 367 |
|
|---|
| 368 | public static void main(String[] args) {
|
|---|
| 369 | MethodDemo demo = new MethodDemo();
|
|---|
| 370 | demo.invokePerlFunction();
|
|---|
| 371 | }
|
|---|
| 372 | }
|
|---|
| 373 |
|
|---|
| 374 | =head2 Where did $self go?
|
|---|
| 375 |
|
|---|
| 376 | Don't worry, C<$self> is still there. JPL takes care of fetching it, as
|
|---|
| 377 | well as all the other arguments:
|
|---|
| 378 |
|
|---|
| 379 | perl int perlMultiply(int a, int b) {{
|
|---|
| 380 | my $result = $a * $b;
|
|---|
| 381 | return $result;
|
|---|
| 382 | }}
|
|---|
| 383 |
|
|---|
| 384 | perl void calculateProduct() {{
|
|---|
| 385 | my $x = 3;
|
|---|
| 386 | my $y = 6;
|
|---|
| 387 | my $retval = $self->perlMultiply($x, $y);
|
|---|
| 388 | print "$x * $y = $retval\n";
|
|---|
| 389 | }}
|
|---|
| 390 |
|
|---|
| 391 | B<Note>. JPL takes care of putting all the arguments, including
|
|---|
| 392 | C<$self>, into variables. If you see a variable in the function
|
|---|
| 393 | header, you will get a variable of the same name without having to
|
|---|
| 394 | use C<shift> or C<@_>, guaranteed.
|
|---|
| 395 |
|
|---|
| 396 |
|
|---|
| 397 |
|
|---|
| 398 | NOTE: I've added a line that prints the output of "ref dollar sign self"
|
|---|
| 399 | You'll see this when I run the demo.
|
|---|
| 400 |
|
|---|
| 401 | class SelfDemo {
|
|---|
| 402 |
|
|---|
| 403 | // A Perl method to multiply two values.
|
|---|
| 404 | //
|
|---|
| 405 | perl int perlMultiply(int a, int b) {{
|
|---|
| 406 | my $result = $a * $b;
|
|---|
| 407 | return $result;
|
|---|
| 408 | }}
|
|---|
| 409 |
|
|---|
| 410 | // A Perl method to invoke another Perl method.
|
|---|
| 411 | //
|
|---|
| 412 | perl void calculateProduct() {{
|
|---|
| 413 | my $x = 3;
|
|---|
| 414 | my $y = 6;
|
|---|
| 415 | # Ahhh. There's our old friend, $self!
|
|---|
| 416 | #
|
|---|
| 417 | my $retval = $self->perlMultiply($x, $y);
|
|---|
| 418 | # Display the results.
|
|---|
| 419 | #
|
|---|
| 420 | print "$x * $y = $retval\n";
|
|---|
| 421 | }}
|
|---|
| 422 |
|
|---|
| 423 | public static void main(String[] args) {
|
|---|
| 424 | SelfDemo demo = new SelfDemo();
|
|---|
| 425 | demo.calculateProduct();
|
|---|
| 426 | }
|
|---|
| 427 | }
|
|---|
| 428 |
|
|---|
| 429 | =head2 Passing Arrays
|
|---|
| 430 |
|
|---|
| 431 | If you pass an array from Java into a Perl method, it arrives in the
|
|---|
| 432 | form of a scalar reference.
|
|---|
| 433 |
|
|---|
| 434 | Use the GetIntArrayElements() JNI function to convert that scalar into
|
|---|
| 435 | an array of integers.
|
|---|
| 436 |
|
|---|
| 437 | perl void min_max( int[] data ) {{
|
|---|
| 438 |
|
|---|
| 439 | # Get the array elements
|
|---|
| 440 | #
|
|---|
| 441 | my @new_array = GetIntArrayElements( $data );
|
|---|
| 442 |
|
|---|
| 443 | # Sort the array numerically
|
|---|
| 444 | #
|
|---|
| 445 | my @sorted = sort {$a <=> $b} @new_array;
|
|---|
| 446 |
|
|---|
| 447 | print "Min: $sorted[0], ",
|
|---|
| 448 | "Max: $sorted[$#sorted]\n";
|
|---|
| 449 | }}
|
|---|
| 450 |
|
|---|
| 451 | void minMaxDemo() {
|
|---|
| 452 | int[] data = {101, 99, 42, 666, 23};
|
|---|
| 453 | min_max( data );
|
|---|
| 454 | }
|
|---|
| 455 |
|
|---|
| 456 | Some JNI Array Functions
|
|---|
| 457 |
|
|---|
| 458 | =over 4
|
|---|
| 459 |
|
|---|
| 460 | =item GetBooleanArrayElements( scalar)
|
|---|
| 461 |
|
|---|
| 462 | Converts scalar to an array of booleans.
|
|---|
| 463 |
|
|---|
| 464 | =item GetByteArrayElements( scalar )
|
|---|
| 465 |
|
|---|
| 466 | Converts scalar to an array of bytes.
|
|---|
| 467 |
|
|---|
| 468 | =item GetCharArrayElements( scalar )
|
|---|
| 469 |
|
|---|
| 470 | Converts scalar to an array of characters.
|
|---|
| 471 |
|
|---|
| 472 | =item GetShortArrayElements( scalar )
|
|---|
| 473 |
|
|---|
| 474 | Converts scalar to an array of short integers.
|
|---|
| 475 |
|
|---|
| 476 | =item GetIntArrayElements( scalar )
|
|---|
| 477 |
|
|---|
| 478 | Converts scalar to an array of integers.
|
|---|
| 479 |
|
|---|
| 480 | =item GetLongArrayElements( scalar )
|
|---|
| 481 |
|
|---|
| 482 | Converts scalar to an array of long integers.
|
|---|
| 483 |
|
|---|
| 484 | =item GetFloatArrayElements( scalar )
|
|---|
| 485 |
|
|---|
| 486 | Converts scalar to an array of floating point numbers.
|
|---|
| 487 |
|
|---|
| 488 | =item GetDoubleArrayElements( scalar )
|
|---|
| 489 |
|
|---|
| 490 | Converts scalar to an array of double precision numbers.
|
|---|
| 491 |
|
|---|
| 492 | =item GetArrayLength( scalar )
|
|---|
| 493 |
|
|---|
| 494 | Returns the length of the array.
|
|---|
| 495 |
|
|---|
| 496 | =back
|
|---|
| 497 |
|
|---|
| 498 | PerlTakesArray.jpl
|
|---|
| 499 | // Show how to pass an array from Java to Perl.
|
|---|
| 500 | //
|
|---|
| 501 |
|
|---|
| 502 | public class PerlTakesArray {
|
|---|
| 503 |
|
|---|
| 504 | perl void min_max( int[] data ) {{
|
|---|
| 505 | # Get the array elements
|
|---|
| 506 | #
|
|---|
| 507 | my @new_array = GetIntArrayElements( $data );
|
|---|
| 508 |
|
|---|
| 509 | # Sort the array numerically
|
|---|
| 510 | #
|
|---|
| 511 | my @sorted = sort {$a <=> $b} @new_array;
|
|---|
| 512 | print "Min: $sorted[0], ",
|
|---|
| 513 | "Max: $sorted[$#sorted]\n";
|
|---|
| 514 | }}
|
|---|
| 515 |
|
|---|
| 516 | void minMaxDemo() {
|
|---|
| 517 | // Create an array and ask Perl to tell us
|
|---|
| 518 | // the min and max values.
|
|---|
| 519 | int[] data = {101, 99, 42, 666, 23};
|
|---|
| 520 | min_max( data );
|
|---|
| 521 | }
|
|---|
| 522 |
|
|---|
| 523 | public static void main(String[] argv) {
|
|---|
| 524 | PerlTakesArray demo = new PerlTakesArray();
|
|---|
| 525 | demo.minMaxDemo();
|
|---|
| 526 | }
|
|---|
| 527 |
|
|---|
| 528 | }
|
|---|
| 529 |
|
|---|
| 530 | =head2 2.3.4 Passing Arrays of Objects
|
|---|
| 531 |
|
|---|
| 532 | Working with arrays of objects is a little more complicated, because you
|
|---|
| 533 | need to work with them one at a time.
|
|---|
| 534 |
|
|---|
| 535 | Fetch one element at a time with GetObjectArrayElement(), which returns
|
|---|
| 536 | an object of type java.lang.Object (the most generic type).
|
|---|
| 537 |
|
|---|
| 538 | Explicitly cast the Object to its real type with bless().
|
|---|
| 539 |
|
|---|
| 540 | perl void sortArray( String[] names ) {{
|
|---|
| 541 | my @new_array;
|
|---|
| 542 | for (my $i = 0; $i < GetArrayLength($names); $i++) {
|
|---|
| 543 | my $string = GetObjectArrayElement($names, $i);
|
|---|
| 544 | bless $string, "java::lang::String";
|
|---|
| 545 | push @new_array, $string;
|
|---|
| 546 | }
|
|---|
| 547 | print join(', ', sort @new_array), "\n";
|
|---|
| 548 | }}
|
|---|
| 549 |
|
|---|
| 550 | void arrayDemo() {
|
|---|
| 551 | String[] names = {"Omega", "Gamma", "Beta", "Alpha"};
|
|---|
| 552 | sortArray( names );
|
|---|
| 553 | }
|
|---|
| 554 |
|
|---|
| 555 | Note. String is not a primitive type: it is a class (java.lang.String).
|
|---|
| 556 | So, you need to use this technique for Strings as well. You can't use
|
|---|
| 557 | the technique in 2.3.3.
|
|---|
| 558 |
|
|---|
| 559 | PerlTakesObjectArray.jpl
|
|---|
| 560 |
|
|---|
| 561 | public class PerlTakesObjectArray {
|
|---|
| 562 |
|
|---|
| 563 | // Perl method to sort an array of strings.
|
|---|
| 564 | //
|
|---|
| 565 | perl void sortArray( String[] names ) {{
|
|---|
| 566 | my @new_array; # an array to copy names[] to
|
|---|
| 567 |
|
|---|
| 568 | # Fetch each element from the array.
|
|---|
| 569 | for (my $i = 0; $i < GetArrayLength($names); $i++) {
|
|---|
| 570 |
|
|---|
| 571 | # Get the object (it's not a String yet!) at
|
|---|
| 572 | # the current index ($i).
|
|---|
| 573 | my $string = GetObjectArrayElement($names, $i);
|
|---|
| 574 |
|
|---|
| 575 | # Cast (bless) it into a String.
|
|---|
| 576 | bless $string, "java::lang::String";
|
|---|
| 577 |
|
|---|
| 578 | # Add it to the array.
|
|---|
| 579 | push @new_array, $string;
|
|---|
| 580 | }
|
|---|
| 581 |
|
|---|
| 582 | # Print the sorted, comma-delimited array.
|
|---|
| 583 | print join(', ', sort @new_array), "\n";
|
|---|
| 584 |
|
|---|
| 585 | }}
|
|---|
| 586 |
|
|---|
| 587 | // Create a String array and ask Perl to sort it for us.
|
|---|
| 588 | //
|
|---|
| 589 |
|
|---|
| 590 | void arrayDemo() {
|
|---|
| 591 | String[] names = {"Omega", "Gamma", "Beta", "Alpha"};
|
|---|
| 592 | sortArray( names );
|
|---|
| 593 | }
|
|---|
| 594 |
|
|---|
| 595 | public static void main(String[] argv) {
|
|---|
| 596 | PerlTakesObjectArray demo = new PerlTakesObjectArray();
|
|---|
| 597 | demo.arrayDemo();
|
|---|
| 598 | }
|
|---|
| 599 | }
|
|---|
| 600 |
|
|---|
| 601 | =head2 2.3.5 Returning Arrays from Perl to Java
|
|---|
| 602 |
|
|---|
| 603 | To write a Perl method that returns an array, declare its return value
|
|---|
| 604 | as an array type. Make sure you return a reference to the array, not a
|
|---|
| 605 | list:
|
|---|
| 606 |
|
|---|
| 607 | perl int[] getTime() {{
|
|---|
| 608 | my ($sec, $min, $hour, @unused) = localtime(time);
|
|---|
| 609 | # Return an array with seconds, minutes, hours
|
|---|
| 610 | my @time_array = ($sec, $min, $hour);
|
|---|
| 611 | return \@time_array;
|
|---|
| 612 | }}
|
|---|
| 613 |
|
|---|
| 614 | void testArray() {
|
|---|
| 615 | int time[] = getTime();
|
|---|
| 616 | System.out.println(time[2] + ":" + time[1]);
|
|---|
| 617 | }
|
|---|
| 618 |
|
|---|
| 619 | PerlGivesArray.jpl
|
|---|
| 620 |
|
|---|
| 621 | // Simple JPL demo to show how to send an array to Java
|
|---|
| 622 | // from Perl
|
|---|
| 623 |
|
|---|
| 624 | class PerlGivesArray {
|
|---|
| 625 | // Call the Perl method to get an array and print
|
|---|
| 626 | // the hour and minute elements.
|
|---|
| 627 |
|
|---|
| 628 | void testArray() {
|
|---|
| 629 | int time[] = getTime();
|
|---|
| 630 | System.out.println(time[2] + ":" + time[1]);
|
|---|
| 631 | }
|
|---|
| 632 |
|
|---|
| 633 | // Perl method that returns an array reference.
|
|---|
| 634 | //
|
|---|
| 635 | perl int[] getTime() {{
|
|---|
| 636 | # Get the first three arguments from localtime,
|
|---|
| 637 | # discard the rest.
|
|---|
| 638 | my ($sec, $min, $hour, @unused) = localtime(time);
|
|---|
| 639 |
|
|---|
| 640 | # Return an array with seconds, minutes, hours
|
|---|
| 641 | my @time_array = ($sec, $min, $hour);
|
|---|
| 642 | return \@time_array;
|
|---|
| 643 | }}
|
|---|
| 644 |
|
|---|
| 645 | public static void main(String[] argv) {
|
|---|
| 646 | PerlGivesArray demo = new PerlGivesArray();
|
|---|
| 647 | demo.testArray();
|
|---|
| 648 | }
|
|---|
| 649 | }
|
|---|
| 650 |
|
|---|
| 651 | =head2 2.3.6 Arrays from Strings
|
|---|
| 652 |
|
|---|
| 653 | JPL will slice Perl strings up into Java arrays for you. If you declare
|
|---|
| 654 | a Perl method as an array type and return a string (instead of an array
|
|---|
| 655 | reference), JPL splits up the elements into an array.
|
|---|
| 656 |
|
|---|
| 657 | Consider this example, where a GIF stored in a string gets turned into
|
|---|
| 658 | an array of bytes so Java can make an Image out of it:
|
|---|
| 659 |
|
|---|
| 660 | void generateImage() {
|
|---|
| 661 | Toolkit kit = Toolkit.getDefaultToolkit();
|
|---|
| 662 | byte[] image_data = mkImage();
|
|---|
| 663 | img = kit.createImage( image_data );
|
|---|
| 664 | }
|
|---|
| 665 |
|
|---|
| 666 | perl byte[] mkImage() {{
|
|---|
| 667 | use GD;
|
|---|
| 668 | my $im = new GD::Image( $self->width, $self->height);
|
|---|
| 669 | my $white = $im->colorAllocate(255, 255, 255);
|
|---|
| 670 | my $blue = $im->colorAllocate(0, 0, 255);
|
|---|
| 671 | $im->fill($white, 0, 0);
|
|---|
| 672 | $im->string(gdLargeFont, 10, 10, "Hello, World", $blue);
|
|---|
| 673 | return $im->gif;
|
|---|
| 674 | }}
|
|---|
| 675 |
|
|---|
| 676 | GifDemo.jpl
|
|---|
| 677 |
|
|---|
| 678 | import java.awt.*;
|
|---|
| 679 | import java.awt.event.*;
|
|---|
| 680 | import java.awt.image.*;
|
|---|
| 681 |
|
|---|
| 682 | /*
|
|---|
| 683 | * A JPL program that demonstrates passing byte arrays
|
|---|
| 684 | * between Java and Perl
|
|---|
| 685 | *
|
|---|
| 686 | */
|
|---|
| 687 |
|
|---|
| 688 | class GIFDemo extends Canvas {
|
|---|
| 689 | Image img;
|
|---|
| 690 | int width = 200;
|
|---|
| 691 | int height = 30;
|
|---|
| 692 |
|
|---|
| 693 | // Constructor for this class.
|
|---|
| 694 | public GIFDemo() {
|
|---|
| 695 | this.setSize(width, height);
|
|---|
| 696 | }
|
|---|
| 697 |
|
|---|
| 698 | // Java method to create an image.
|
|---|
| 699 | //
|
|---|
| 700 | void generateImage() {
|
|---|
| 701 | Toolkit kit = Toolkit.getDefaultToolkit();
|
|---|
| 702 |
|
|---|
| 703 | // Invoke the mkImage() Perl method to generate an
|
|---|
| 704 | // image.
|
|---|
| 705 |
|
|---|
| 706 | byte[] image_data = mkImage();
|
|---|
| 707 |
|
|---|
| 708 | // Create the image with the byte array we got
|
|---|
| 709 | // from the Perl method.
|
|---|
| 710 |
|
|---|
| 711 | img = kit.createImage( image_data );
|
|---|
| 712 | }
|
|---|
| 713 |
|
|---|
| 714 | // A Perl method to generate an image.
|
|---|
| 715 |
|
|---|
| 716 | perl byte[] mkImage() {{
|
|---|
| 717 |
|
|---|
| 718 | # Use the GD image manipulation extension.
|
|---|
| 719 |
|
|---|
| 720 | use GD;
|
|---|
| 721 |
|
|---|
| 722 | # Create a new image with the height and width specified
|
|---|
| 723 | # in the enclosing Java class.
|
|---|
| 724 |
|
|---|
| 725 | my $im = new GD::Image( $self->width, $self->height);
|
|---|
| 726 |
|
|---|
| 727 | # Allocate two colors.
|
|---|
| 728 |
|
|---|
| 729 | my $white = $im->colorAllocate(255, 255, 255);
|
|---|
| 730 | my $blue = $im->colorAllocate(0, 0, 255);
|
|---|
| 731 |
|
|---|
| 732 | # Fill the image with white and draw a greeting.
|
|---|
| 733 |
|
|---|
| 734 | $im->fill($white, 0, 0);
|
|---|
| 735 | $im->string(gdLargeFont, 10, 10,
|
|---|
| 736 | "Hello, World", $blue);
|
|---|
| 737 | return $im->gif;
|
|---|
| 738 | }}
|
|---|
| 739 |
|
|---|
| 740 | // Java uses this to repaint the image when necessary.
|
|---|
| 741 |
|
|---|
| 742 | public void paint(Graphics g) {
|
|---|
| 743 | g.drawImage(img, 0, 0, this);
|
|---|
| 744 | }
|
|---|
| 745 |
|
|---|
| 746 | // The entry point.
|
|---|
| 747 |
|
|---|
| 748 | public static void main(String[] argv) {
|
|---|
| 749 |
|
|---|
| 750 | // Set up a frame and create an image.
|
|---|
| 751 |
|
|---|
| 752 | Frame f = new Frame("GD Example");
|
|---|
| 753 | f.setLayout(new BorderLayout());
|
|---|
| 754 |
|
|---|
| 755 | GIFDemo demo = new GIFDemo();
|
|---|
| 756 | demo.generateImage();
|
|---|
| 757 |
|
|---|
| 758 | f.add("Center", demo);
|
|---|
| 759 | f.addWindowListener( new Handler() );
|
|---|
| 760 |
|
|---|
| 761 | f.pack();
|
|---|
| 762 | f.show();
|
|---|
| 763 |
|
|---|
| 764 | }
|
|---|
| 765 | }
|
|---|
| 766 |
|
|---|
| 767 | // A handler to process a request to close a window.
|
|---|
| 768 |
|
|---|
| 769 | class Handler extends WindowAdapter {
|
|---|
| 770 | public void windowClosing(WindowEvent e) {
|
|---|
| 771 | System.exit(0);
|
|---|
| 772 | }
|
|---|
| 773 | }
|
|---|
| 774 |
|
|---|
| 775 | =head2 2.3.7 Summary: Calling Perl from Java
|
|---|
| 776 |
|
|---|
| 777 | =over 4
|
|---|
| 778 |
|
|---|
| 779 | =item 1
|
|---|
| 780 |
|
|---|
| 781 | Put your embedded Perl code in methods that are declared C<perl>.
|
|---|
| 782 |
|
|---|
| 783 | =item 2
|
|---|
| 784 |
|
|---|
| 785 | Use double, rather than single, curly braces ({{ and }}).
|
|---|
| 786 |
|
|---|
| 787 | =item 3
|
|---|
| 788 |
|
|---|
| 789 | Invoke the Perl methods from Java just like any other Java method.
|
|---|
| 790 |
|
|---|
| 791 | =item 4
|
|---|
| 792 |
|
|---|
| 793 | No need to pull arguments off of C<@_> with C<shift>: JPL takes care of
|
|---|
| 794 | this for you. This includes C<$self>.
|
|---|
| 795 |
|
|---|
| 796 | =item 5
|
|---|
| 797 |
|
|---|
| 798 | If you pass a Java array into a Perl method, it comes in as a scalar
|
|---|
| 799 | reference.
|
|---|
| 800 |
|
|---|
| 801 | =item 6
|
|---|
| 802 |
|
|---|
| 803 | Convert references to arrays of primitives with C<Get*ArrayElements>
|
|---|
| 804 |
|
|---|
| 805 | =item 7
|
|---|
| 806 |
|
|---|
| 807 | Use C<GetObjectArrayElement> to get elements from arrays of strings and
|
|---|
| 808 | other objects.
|
|---|
| 809 |
|
|---|
| 810 | =item 8
|
|---|
| 811 |
|
|---|
| 812 | To return an array from a C<perl> method, declare the method as returning
|
|---|
| 813 | an array type, and either:
|
|---|
| 814 |
|
|---|
| 815 | =item 9
|
|---|
| 816 |
|
|---|
| 817 | Return an array reference.
|
|---|
| 818 |
|
|---|
| 819 | =item 10
|
|---|
| 820 |
|
|---|
| 821 | Return a string: JPL slices it up for you.
|
|---|
| 822 |
|
|---|
| 823 | =back
|
|---|
| 824 |
|
|---|
| 825 | =head1 2.4 Calling Java from Perl
|
|---|
| 826 |
|
|---|
| 827 | Next, let's look at how to invoke Java from Perl.
|
|---|
| 828 |
|
|---|
| 829 | =head2 2.4.1 Java in Perl in Java
|
|---|
| 830 |
|
|---|
| 831 | Remember the issues from 2.1.2 - this is unstable unless you are calling Java from Perl methods that are themselves embedded in a Java program.
|
|---|
| 832 |
|
|---|
| 833 | =head2 2.4.2 Java in Perl: Simple Constructors
|
|---|
| 834 |
|
|---|
| 835 | Use JPL::Class to load the class:
|
|---|
| 836 |
|
|---|
| 837 | C<use JPL::Class "java::awt::Frame";>
|
|---|
| 838 |
|
|---|
| 839 | Invoke the constructor to create an instance of the class:
|
|---|
| 840 |
|
|---|
| 841 | C<my $f = java::awt::Frame->new;>
|
|---|
| 842 |
|
|---|
| 843 | You've got a reference to a Java object in $f, a Perl scalar. I think
|
|---|
| 844 | this is cool.
|
|---|
| 845 |
|
|---|
| 846 | =head2 2.4.3 Constructors that Take Parameters
|
|---|
| 847 |
|
|---|
| 848 | If the constructor has parameters, look up the method signature with
|
|---|
| 849 | C<getmeth>:
|
|---|
| 850 |
|
|---|
| 851 | my $new = getmeth("new", ['java.lang.String'], []);
|
|---|
| 852 |
|
|---|
| 853 | The first argument to C<getmeth> is the name of the method. The second
|
|---|
| 854 | argument is a reference to an array that contains a list of the argument
|
|---|
| 855 | types. The final argument to C<getmeth> is a reference to an array
|
|---|
| 856 | containing a single element with the return type. Constructors always
|
|---|
| 857 | have a null (void) return type, even though they return an instance of
|
|---|
| 858 | an object.
|
|---|
| 859 |
|
|---|
| 860 | Invoke the method through the variable you created:
|
|---|
| 861 |
|
|---|
| 862 | my $f = java::awt::Frame->$new( "Frame Demo" );
|
|---|
| 863 |
|
|---|
| 864 | Because Java supports method overloading, the only way Java can
|
|---|
| 865 | distinguish between different methods that have the same name is through
|
|---|
| 866 | the method signature. The C<getmeth> function simply returns a mangled,
|
|---|
| 867 | Perl-friendly version of the signature. JPL's AutoLoader takes care of
|
|---|
| 868 | finding the right class.
|
|---|
| 869 |
|
|---|
| 870 | For example, the method signature for $new is C<(Ljava/lang/String;)V>.
|
|---|
| 871 | In Perl, this is translated to C<new__Ljava_lang_String_2__V>. Sure, it
|
|---|
| 872 | means something to Java, but thanks to C<getmeth> and JPL's AutoLoader,
|
|---|
| 873 | we don't have to worry about it!
|
|---|
| 874 |
|
|---|
| 875 | =head2 2.4.4 More on getmeth
|
|---|
| 876 |
|
|---|
| 877 | The C<getmeth> function is not just for constructors. You'll use it to look
|
|---|
| 878 | up method signatures for any method that takes arguments.
|
|---|
| 879 |
|
|---|
| 880 | To use C<getmeth>, just supply the Java names of the types and objects in
|
|---|
| 881 | the argument or return value list. Here are a few examples:
|
|---|
| 882 |
|
|---|
| 883 | =over 4
|
|---|
| 884 |
|
|---|
| 885 | =item *
|
|---|
| 886 |
|
|---|
| 887 | Two int arguments, void return type:
|
|---|
| 888 |
|
|---|
| 889 | $setSize = getmeth("setSize", ['int', 'int'], []);
|
|---|
| 890 |
|
|---|
| 891 | =item *
|
|---|
| 892 |
|
|---|
| 893 | One argument (java.awt.Component), with a return type of the same:
|
|---|
| 894 |
|
|---|
| 895 | $add = getmeth("add", ['java.awt.Component'],
|
|---|
| 896 |
|
|---|
| 897 | ['java.awt.Component']);
|
|---|
| 898 |
|
|---|
| 899 | =item *
|
|---|
| 900 |
|
|---|
| 901 | Two arguments, a String object and a boolean value, and a void return
|
|---|
| 902 | type:
|
|---|
| 903 |
|
|---|
| 904 | $new = getmeth("new",
|
|---|
| 905 |
|
|---|
| 906 | ['java.lang.String', 'boolean'], []);
|
|---|
| 907 |
|
|---|
| 908 | =item *
|
|---|
| 909 |
|
|---|
| 910 | A String argument with a java.lang.Class return type:
|
|---|
| 911 |
|
|---|
| 912 | $forName = getmeth("forName",
|
|---|
| 913 |
|
|---|
| 914 | ['java.lang.String'],
|
|---|
| 915 |
|
|---|
| 916 | ['java.lang.Class']);
|
|---|
| 917 |
|
|---|
| 918 | =item *
|
|---|
| 919 |
|
|---|
| 920 | No arguments, but a boolean return value:
|
|---|
| 921 |
|
|---|
| 922 | $next = getmeth("next", [], ['boolean']);
|
|---|
|
|---|