Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

JVM Languages

Jperl: Accessing Perl from Java


Feb99: Jperl: Accessing Perl from Java

The author is a software design engineer working for the ASIC group of Texas Instruments, India. He can be contacted at [email protected].


Jperl provides an interface to Perl from Java. The Jperl interface was written in C++ using Perl APIs and integrated into Java using the Java Native Interface (JNI). The APIs in Jperl also make accessing Perl from C++ simple, with a single overloaded function that masks argument ordering, stack manipulation, and data structure conversion. The package -- freely available (courtesy of Texas Instruments) at http://www.angelfire.com/ in/sbm, from Comprehensive Perl Archives Network (CPAN) at http://www.perl.com/ CPAN-local/authors/id/S/SB/SBALA/, and from DDJ (see "Resource Center," page 5) -- includes source code, examples, documentation, and precompiled libraries for Solaris. To compile your own libraries, you need to install JDK 1.1.4, g++ 2.7.x, Perl 5.002 (or higher).

More specifically, the modules include:

  • jperl.c, which contains the implementation for the Perl access in C++.
  • jperl.h, which contains the function prototypes.
  • jp.c and jp.h, which provide the JNI.
  • jp.java, which defines the package for Perl access.

Accessing Perl from Java

Before accessing Perl, you must make sure the path to libperl.so is added to LD_LIBRARY_PATH and jp.class to the CLASSPATH. jp.class defines six public methods for calling Perl subroutines, two for turning debug on/off in the native code, and a constructor (see Table 1).

The constructor jp() takes the path to the Perl file as a string argument and initializes the interpreter. Ideally, the Perl file should include all the subroutines that will be called from Java. Only one instance of the Perl interpreter can be alive at a time; trying to initialize more than one instance throws a RuntimeException.

Additional Perl modules (other than those required by the Perl file supplied to the jp() constructor) can be included at run time using IPLLoadLibrary(). This method takes as an argument the path of the Perl package and adds it to the interpreter within the existing namespace.

The DebugOn() and DebugOff() methods turn the debug flag on and off in the native code. When the debug flag is on, arguments are passed to Perl subroutines, values are returned, and status messages are displayed on stdout. Make sure you unbuffer the output in Perl so that messages from Perl and debug messages from the native code appear in order. In Perl, you can do this with select((select(STDOUT),$| = 1)[0]);.

Perl subroutines or package methods can be called using one of Java's PLCall methods. There are three methods, one for each type of data being returned from Perl. Package methods can be called by specifying package_name::method_name. All PLCall methods take an Object array as an argument and make this data available as arguments to the Perl subroutine through the "@_" array in Perl.

PLCallScalar() calls a Perl subroutine and returns a scalar value. PLCallArray() calls the subroutine and returns a Perl list as a String[]. PLCallHash(), calls the specified subroutine and returns a Perl Hash array (or a list with even numbers of elements) as Hashtable in Java. If an odd number of elements are returned from Perl, a RuntimeException is thrown.

Perl scalars can be converted to Integer, Double, or String, although all values returned from Perl are stored as String. Hash arrays from Perl are converted to Java Hashtables. Both key and value are stored as String, which can contain an empty string if nothing is returned from Perl. In case of error in conversion from Perl data structure to Java, the string will contain "(null)" as its value. All strings are guaranteed to be defined.

As previously mentioned, PLCall methods take an Object array as arguments to be passed to Perl. Application can directly pass Integer, Double, or String arrays as valid arguments. If the application must pass a Vector or a Hashtable, an Object array has to be explicitly created and the Hashtable or Vector made elements of the Object array; see Listings One and Two. One of the most powerful features of Jperl is its ability to evaluate Perl expressions on the fly. The IPLEval method enables this functionality. It takes a Perl expression as an argument, evaluates it, and returns a String array of results; for example, String[] EvRet = perl.IPLEval("$a = 'This is a test';$b = reverse($a);' + "return ($a,$b);");.

Listings Three and Four give the complete picture. In Listing Three, the test.pl program contains two subroutines -- MyPerlFunc and TestFuncHash. The first prints the arguments passed and returns them. The second creates a Hash array and returns it. In Listing Four, example.java uses jp.class to access the subroutines in test.pl. Almost all of these methods throw RuntimeException and IllegalArgumentException. The try-catch block is used to catch these exceptions and display error messages. Hashtable.toString() displays a string representation of the hashtable.

Accessing Perl from C++

Table 2 lists Jperl's function calls. The PLInit() function initializes the Perl interpreter. It takes the path to the Perl file as an argument. This Perl file would normally include all the subroutines that you intend to call. PLLoadModule() lets you add additional Perl modules at run time. This function takes the full path of the modulename as an argument and loads it into the interpreter. After you have finished using the Perl subroutines, call PLClose() to release the resources held by the interpreter.

Perl subroutines can be called using the overloaded PLCall function. The first parameter is the variable in which to return the data, the second parameter is the subroutine name to be called, and the third parameter defines the format of the arguments to be passed to Perl. All PLCall() functions take a variable number of arguments and pass them as arguments to the Perl subroutine in @_. The functions return the number of elements returned by the Perl subroutine or -1 on error.

The return values from the Perl subroutine can be int, double, String (char *), and arrays of int, double, or String. You should call the appropriate PLCall() based on the expected return type from Perl subroutines. If you are not sure of the return types, use PLCall(), which takes the String array as the return parameter. Hasharray from Perl should be received as an array of String, with alternate elements being key and values.

Each of the variable numbers of arguments is converted to an appropriate Perl data structure based on the type specified in format. Valid formats are %d for int, %f for double, %s for char *, %D for an array of int, %F for an array of double, %S for an array of char *. When passing arrays, the first argument should be the length of the array followed by the actual array; see Listing Five.

Perl expressions can be evaluated with the PLEval() function, which takes a Perl expression as input, evaluates it, and returns the results as an array of String.

PLGeneric() is similar to PLCall(), except that it concatenates all the return values from Perl separated by the passed delimiter and returns a single string. For example, sub foo { return ("Hai",1); }, when called with PLGeneric() with delimiter "**", returns a single string "Hai**1" in retval.

The PLCall() functions, as well as PLEval() and PLGeneric(), allocate the necessary memory for returning the values from Perl. It is up to the application using these functions to free them.

Accessing Perl from Applets

Since you cannot add native code to applets, one workaround is to create a plug-in that exports the necessary functionality. These methods can then be accessed from other applets on the same document. You need to download Netscape's Plug-in SDK (http://home.netscape .com/comprod/development_partners/ plugin_api/ index.html), write your own plug-in on top of jperl.c, and export the needed functionality.

Conclusion

The Jperl package provides programmers with the functionality of CPAN modules without having to rewrite them in Java. You can refer to the perlembed, perlguts, and perlcall documentation at http://www.perl.com/CPAN-local/doc/manual/ html/pod/perl.html if you want to extend the C++ interface of Jperl. Refer to JNI documentation at http://java.sun.com/ docs/books/tutorial/native1.1/index.html if you want to extend the Java interface.

DDJ

Listing One

// Passing String array as argument to Perl. // Intger and Double arrays can be passed similarly.
String[]  INP = new String[2];


</p>
// ... fill in INP


</p>
perl.PLCallScalar("MyFunc",INP); // Ditto for PLCallArray & PLCallHash

Back to Article

Listing Two

// Passing a Hashtable and Vector as arguments to Perl Object[] ARGS = new Object[2];
Vector    V;
Hashtable H;


</p>
// ... fill in H & V


</p>
ARGS[0] = H;
ARGS[1] = V;
perl.PLCallScalar("MyFunc",ARGS); // Ditto for PLCallArray & PLCallHash

Back to Article

Listing Three

test.pl sub MyPerlFunc
{
 my($a,$b) = @_;
 print $a,":",$b,"\n";
 return 0;
}
sub TestFuncHash
{
 my($a,$b) = @_;
 my(%ret)  = ("A"=>$a,"B"=>$b);
 return ret;
}

Back to Article

Listing Four

example.javaimport java.util.Hashtable;
import java.util.Stack;
import jp; // The Jperl interface
class main
{
 public static void main(String[] args)
  {
   String[] INP = new String[2];
   INP[0] = "Data1";
   INP[1] = "Data2";
   try {
        // The perl file that contains the subroutines
        jp perl = new jp("test.pl"); 


</p>
        //Turn on Debug if necessary
        //perl.DebugOn;
        
        // Make a call and ignore the returned value!
        String t = perl.PLCallScalar("MyPerlFunc",INP);


</p>
        String[] EvRet = perl.IPLEval("$a = 'This is a test'; 
                                      $b = reverse($a); return ($a,$b);");
       // Display result of evaluation
       for(int i=0;i<EvRet.length;i++)
          {
           System.out.println(EvRet[i]);
          } 
       // Call Hash
       Hashtable H = perl.PLCallHash("TestFuncHash",INP);


</p>
       // Output content of Hash
       System.out.println(H.toString());
       }
   catch(IllegalArgumentException e)
     {
      System.out.println("Error caught "+e.getMessage());
     }
   catch(RuntimeException e)
     {
      System.out.println("Error caught "+e.getMessage());
     }
  }
}

Back to Article

Listing Five

// IntializePLInit("/user/java/dev/test/mytest.pl");


</p>
// Passing a double array to Perl and recieving an int
int I;                            // Return value
double DA[] = { 0.10, 0.20 } ;    // Arguments to the Perl sub
PLCall(I,"TestFuncAI","%F",2,DA); // Length is passed before the array


</p>
// Passing an int, float and string to Perl and recieving a Hash array
char **S;
int ct = PLCall(S,"TestFunc","%d%f%s",33,(double)100,"Hello World");
for(int i=0;i<ct;i++)
   {
    printf("%s\n",S[i]);
   }
// Evaluate a Perl expression
ct = PLEval(EvalRet,"$a = 'This is a Test'; @b = split(/\\s+/,$a); 
            return @b;");
// print results here ....
// Free resources
PLCose();

Back to Article


Copyright © 1999, Dr. Dobb's Journal

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.