Some reader favorites:
EJB fundamentals and session beans
Create a scrollable virtual desktop in Swing
JW Blogs: The cult of Spring
Obviously when you're up and coming, you gun for those already on top. Nonetheless, JW blogger Josh Fruhlinger is charmed
by Web4J creator John O'Hanley's recent comments about the Spring framework, which he notes "has met with a disturbing lack of criticism ..."
| Agile Development: Five Steps to Continuous Integration |
| SOA redefined: Simple. Open. Affordable. |
| The Four Requirements of Next Generation Web Performance Management |
Problem: You need to access a Perl program from your Java program—maybe a custom screen scraper written with LWP (Library for WWW access in Perl), maybe Bugzilla, or maybe one of countless possibilities. You don't want to rewrite the Perl code and would rather just call it somehow.
Solution: You can unite your families with XML-RPC (remote procedure call). Though SOAP is a mature technology often used to solve complex transactional problems, sometimes your problem is simple, and a light API like XML-RPC can allow you to quickly and easily connect formerly independent programs that were separated by language, platform, and location.
This technique is easy to implement and can save a ton of work in either rewriting the Perl routines or explaining to stakeholders why you can't add their functionality to the enterprise system until next quarter. So if you want to learn a get-it-done-now way to hook up Perl and Java, read on.
To make sense of the wrapper structure I describe in this article, we start with the Perl module and routines we want to call, wrap a facade around them, then connect the XML-RPC server to the facade. Next, we call the routine through the Java XML-RPC implementation.
We want to wire up to a Perl module that already exists. Here's the simplest example I can think of; it is named simply PreExistingMod.pm:
package PreExistingMod;
# import all the preexisting Perl Modules you would wish to call here
##### a routine with no arguments and a single String output #####
sub say_hello {
return 'Hello from the PreExistingMod' ;
}
##### a Perl routine with an array of arguments #####
##### and a hash for output #####
sub echo_args {
my ($PassData) = @_;
return { Status => 'Test',
EchoData => ${$PassData}{SessionID},
FromIP => ${$PassData}{ClientIP} };
};
###############################################
1; # Perl Modules require this
PreExistingMod has two routines say_hello and echo_args. Their output is self-explanatory.
When you are integrating two systems, you'll find it's better to gather calls into a façade. The simpler the subsystem's view,
the better; plus this structure also features security benefits. Though this intermediate module isn't necessary and you can
call straight through, placing a façade between the XML-RPC server and PreExistingMod requires little effort and offers great advantages. This structure allows us to protect routines in modules too sensitive
to be available over the wire, check authorization if we wish, and add routines from other modules later.
Here's our PerlSystemFacade.pm module:
package PerlSystemFacade;
# import all the pre-existing/legacy Perl Modules you would wish to call here
###############################################
##### Simple methods to test the plumbing #####
###############################################
sub say_hello_psf {
my $retVal;
# just return a string
$retVal = ' hello from PerlSystemFacade.say_hello_psf';
return $retVal;
}
sub echo_args_psf {
my ($Refer, $PassData) = @_;
#create some output with the input
return {Status => 'Test', EchoData => ${$PassData}{SessionID}, FromIP => ${$PassData}{ClientIP}};
};
################################################
# Facade Methods that use the existing system to produce their result #
################################################
sub say_hello {
my $retVal;
# delegate to the legacy method
use PreExistingMod;
$retVal = PreExistingMod::say_hello();
return $retVal;
}
sub echo_args {
my ($Refer, $PassData) = @_;
my $retVal;
# delegate to the legacy method
use PreExistingMod;
$retVal = PreExistingMod::echo_args( ($PassData) );
return $retVal;
}
1; # Perl Modules require this
The routines say_hello_psf and echo_args_psf allow you to test server connectivity. The routines say_hello and echo_args delegate to PreExistingMod.
Notice that PreExistingMod::echo_args takes ($Passdata) = @_;, whereas the first time the façade assigns @_ in PerlSystemFacade::echo_args, it assigns it to ($Refer, Passdata). The Perl XML-RPC library requires this hack to pad the input's first array element. We just throw $Refer away and don't use it thereafter.
The Perl XML-RPC server is quite simple. We need to install XMLRPC::Lite on our Web server and load the server.pl file:
use XMLRPC::Transport::HTTP;
my $facadeserver = XMLRPC::Transport::HTTP::CGI
-> dispatch_to('PerlSystemFacade')
-> handle;
In simple terms, the XMLRPC library takes the posted input, parses it, stores the routine name being called, creates an argument array structure in Perl
form, calls PerlSystemFacade::some_routine_name, and passes it the array, which becomes @_. It then packages the routine's output and puts it in the response.
Now you have all the server pieces in place. In terms of message flow, client XML-RPC calls now call your module methods along this sequence:
XML-RPC server sequence. Click on thumbnail to view full-sized image.
For this article's implementation, you need Apache XML-RPC. IBM donated this library, which was previously called Helma XML-RPC. It's only one jar file, so the configuration just requires you putting it on your classpath.
The client class that uses XML-RPC to call the server is straightforward:
package perlClientExample;
import org.apache.xmlrpc.XmlRpcClientLite;
import java.util.*;
public class XmlRpcClientExample {
public XmlRpcClientExample() { }
private static final String SERVER_URL = "http://192.168.1.101:8080/server.pl";
public String say_hello() {
String retVal = "NaN";
try {
XmlRpcClientLite xmlrpc = new XmlRpcClientLite(SERVER_URL);
String methodName = "PerlSystemFacade.say_hello";
Vector params = new Vector(0);
retVal = (String) xmlrpc.execute( methodName, params );
}
catch (Exception e) {
e.printStackTrace();
}
return retVal;
}
public Object echo_args() {
Object retVal = new Vector();
try {
XmlRpcClientLite xmlrpc = new XmlRpcClientLite(SERVER_URL);
String methodName = "PerlSystemFacade.echo_args";
Vector params = new Vector(2);
Hashtable hashArg = new Hashtable();
hashArg.put("SessionID", "TestSessionIDValue");
hashArg.put("ClientIP", "10.1.1.22");
params.add( hashArg );
retVal = xmlrpc.execute( methodName, params );
}
catch (Exception e) {
e.printStackTrace();
}
return retVal;
}
public static void main(String[] args) {
XmlRpcClientExample x = new XmlRpcClientExample();
System.out.println ("Output from say_hello() : " + x.say_hello().toString() );
System.out.println ("Output from echo_args() : " + x.echo_args().toString() );
}
}
If you compile and run XmlRpcClientExample, it will return:
Output from say_hello() : Hello from thePreExistingMod
Output from echo_args() : {Status=Test, EchoData=TestSessionIDValue, FromIP=10.1.1.22}
If you are somewhat familiar with Perl, you know that you package an array for the routine arguments. Similarly, you do the
same here. Look carefully at Vector params and PreExistingMod::say_hello, and you will see the correspondence. Basically, our client's params maps to the Perl routine's @_ array, while the client's hashArg Hashtable maps to $PassData. Remember that $Refer argument is just a hack to pad the first element of @_. The real payload, as far as Perl goes, is in the second $Passdata arg.
When handling the response, you need specific knowledge of the structure being returned. The return values are arrays, hashtables,
and strings, which seem to be all the Perl XMLRPC::Lite will return at present. There are no nicely typed object attributes to walk through. If you need those attributes, move to
SOAP. If an element of the returned array is expected to be another primitive type, like int or double, cast it to be sure
from the string.
Apache's XML-RPC implementation does not require WSDL (Web Services Description Language), so it's easier to configure than SOAP or Sun's JAX-RPC (Java API for XML-Remote Procedure Call). The flip side is the absence of a method for clients to use to discover the correct signatures for calling your server's exposed methods. Regardless, we aren't looking to provide a universally available service here. For a project where we just want to wrap Perl routines and call them from Java, it remains a nice fit.
die(...) statements to handle exceptions under the assumption that the script runs from the command line. The Perl XML-RPC server
does not handle the fault correctly and just closes the socket. Luckily, the Apache XML-RPC client detects that the socket
closed unexpectedly and throws an exception you can catch: org.apache.xmlrpc.XmlRpcException: Server returned an invalid fault response.We started off with the problem of how to wire our Java application to call Perl functions. To prepare the Perl routines for calling, we added a façade, and then connected the façade to a Perl implementation of XML-RPC. We then called the routines from our Java application using a Java implementation of XML-RPC. The end result is access to those Perl routines.
This article focused on how XML-RPC can solve the problem of how to integrate two programs separated by language. XML-RPC also addresses the problem of physical separation. I've found it to be a handy and reliable tool. Its benefit is tactical, more than strategic, and thus is realized quickly. I hope it also helps you.
| Subject | Replies |
Last post
|
|
By Anonymous |
2 |
05/16/08 06:28 AM
by Anonymous |
|
By JavaWorld |
0 |
02/28/08 12:43 AM
by Anonymous |
|
By Matty |
1 |
05/24/07 12:54 PM
by Anonymous |
Free Download - 5 Minute Product Review. When slow equals Off: Manage the complexity of Web applications - Symphoniq
![]()
Free Download - 5 Minute Product Review. Realize the benefits of real user monitoring in less than an hour. - Symphoniq