Executing Perl script from jEE Spring project
Lately I had to execute a Perl script from java project and I want to share my experience with you. It might be useful in your future projects as it was for me in this particular work. I based my job on usage of WWW::Mechanize library for automating interaction with websites. There were some issues to run Perl from java project, but I managed to deal with them in my own way. And that way of mine I want to share with today in this small article.
Problems:
Where to put your perl script file in javaEE Spring project.
Define absolute path to your script.
Define correct bash command.
Turn on the logs to log the messages at the debug level.
Define a process.
How to use Runtime to execute your script.
How to log message from output and error stream of the process.
First of all you have to decide where to store your perl script files. I chose the location where I keep my resources (src/main/resources). This location is added to classpath by default. The output files will be in target/classes folder.
Here is entry from eclipse project .classpath file:
<classpathentry excluding="**" including="**/*.java" kind="src" output="target/classes" path="src/main/resources"/>
I used ResourceLoader method from org.springframework.core.io library to get resource from a specified classpath:
Resource resource = resourceLoader.getResource("classpath:/perl/myScript.pl");
If I have the resource I can specify an absolute path to it:
String absolutePath = resource.getFile().getAbsolutePath();
At this moment absolute path looks something like this: ../target/classes/perl/myScript.pl
Next step is to define bash command which is used to run the script. In terminal to execute we have to type: perl myScript.pl parameter1 parameter2 …
We have to define this command as a string:
String bashCommand = "perl " + absolutePath + " " + parameter;
If perl is not defined in your system classpath you have to define absolute path for it f.e.:
/usr/bin/perl
So the command string can look like this:
String bashCommand = "/usr/bin/perl " + absolutePath + " " + parameter;
At this moment we have ready-to-use command as a string, so we can trigger a script using Runtime.exec().
But wait! What if the script is not working correctly or even it does not work at all? What if we run the script and nothing happens?
To obtain the information about what the script is doing, we can define a process:
Process process = Runtime.getRuntime().exec(bashCommand);
“ Runtime.exec method create a native process and return an instance of a subclass of Process that can be used to control the process and obtain information about it. The class Process provides methods for performing input from the process, performing output to the process, waiting for the process to complete, checking the exit status of the process, and destroying (killing) the process.” [1]
At this moment we can get information about the process:
Input stream of the subprocess obtains data from the standard output stream of the process
process.getInputStream()
Error stream of the subprocess obtains data from the error output stream of the process
process.getErrorStream()
To log the messages we have to define logger:
Logger LOG = LoggerFactory.getLogger(MyService.class); LOG.debug(IOUtils.toString(process.getInputStream())); LOG.debug(IOUtils.toString(process.getErrorStream()));
In order to log messages at the debug level we have to turn it on in the configuration file.I have my configuration in log4j.xml:
<logger name="your.package.name"> <level value="DEBUG" /> <appender-ref ref="debug" /> </logger>
To trigger the script I used a controller method. To run it I have to put the url address in my web browser: http://myhost/runPerlScript/parameter
//Controller @RequestMapping(value = "/runPerlScript/{parameter}") public void runPerlScript(@PathVariable String parameter) { myService.runPerlScript(parameter); }
And that’s all folks! Now when you trigger your service method, your program will run and you will see the output messages.
When your script is not working for some reason, you can easily find a solution by going through all the errors that will be listed.
Java source code:
//Service import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.stereotype.Service; @Service public class MyService { private Logger LOG = LoggerFactory.getLogger(MyService.class); @Autowired private ResourceLoader resourceLoader; public void runPerlScript(String parameter) { try { Resource resource = resourceLoader.getResource("classpath:/perl/myScript.pl"); String absolutePath = resource.getFile().getAbsolutePath(); String bashCommand = "perl " + absolutePath + " " + parameter; Process process = Runtime.getRuntime().exec(bashCommand); process.waitFor();
LOG.debug(IOUtils.toString(process.getInputStream())); LOG.debug(IOUtils.toString(process.getErrorStream()));
} catch (Exception e) {
// TODO Auto-generated catch block e.printStackTrace(); } } } //Controller @RequestMapping(value = "/runPerlScript/{parameter}") public void runPerlScript(@PathVariable String parameter) {
myService.runPerlScript(parameter); }
References and notes: [1] JavaDoc
by L.Wartalski
edited P.Chaberski















