Attempting to inline Java into Perl via the Inline::Java module
This is my first attempt to inline Java code in Perl. We cannot use the standard SFTP command on our system. This is out of my power. We have a jarfile called SFTP.jar which can be used. The previous person before me was able to get Inline::Perl to work, but his implementation was sloppy, and I'd like to clean it up.
I am working on a Windows system on the H:\svn
directory. I have my module under the H:\svn\FMS3
directory, and I have a jarfile called SFTP.jar
under the H:\svn\FMS3\Sftp.pm
directory. There is a file called Sftp.pm
located under the H:\svn\FMS3
directory, and defines a module called FMS3::Sftp
. (I'm keeping all of our custom modules under the FMS3
parent module).
I have inlined code in FMS3::Sftp
, and it looks like it compiles. However, when I attempt to execute, it claims Can't exec JVM: open3: Can't call method "close" on an undefined value at C:/Perl/lib/IPC/Open3.pm line 370
.
Exactly what am I doing wrong?
The FMS3::Sftp
module:
#! /usr/bin/env perl
# Sftp.pm
########################################################################
########################################################################
# PACKAGE FMS3::Sftp
#
package FMS3::Sftp;
#
########################################################################
########################################################################
# PERL PRAGMAS
#
use strict;
use warnings;
use vars qw($PERL_CLASSPATH);
#
########################################################################
########################################################################
# CONSTANTS
#
use constant {
FTP_SERVER => "10.85.10.190",
FTP_USER => "fisaftp",
FTP_PASSWORD => "Fisa123456",
};
#
########################################################################
########################################################################
# INITIALIZE
#
# Set a PERL_CLASSPATH that will include all directories in the
# @INC array. Somewhere in this array will be located our JAR file
# that we need to include, and of course, this classpath.
#
# This will be appended to the standard $CLASSPATH environment variable.
#
BEGIN {
use Config;
my $cpsep;
if ($Config{osname} =~ /^mswin32/i) {
$cpsep = ";";
} else {
$cpsep = ":";
}
$PERL_CLASSPATH = join("/FMS3/Sftp/SFTP.jar$cpsep", @INC);
$PERL_CLASSPATH = "$PERL_CLASSPATH/FMS3/Sftp/SFTP.jar";
}
#
########################################################################
########################################################################
#
# PERL INLINE JAVA CODE:
#
use Inline (
Java => 'DATA',
J2SDK => $ENV{JAVA_HOME},
CLASSPATH => $PERL_CLASSPATH,
STUDY => ["SFTP", "close", "list", "get", "put", "remove"],
DEBUG => 4,
);
#
########################################################################
########################################################################
# CONSTRUCTORS
#
sub new {
my $class = shift;
my $server = shift;
my $user = shift;
my $password = shift;
if (not $server) { $server = FTP_SERVER; }
if (not $user) { $user = FTP_USER; }
if (not $password) { $password = FTP_PASSWORD; }
my $self = {};
bless($self, $class);
eval {$self->{CONNECTION} = new SFTP($server, $user, $password);};
if ($@) {
$self->{ERROR} = $@;
return;
}
return $self;
}
#
########################################################################
########################################################################
# DESTRUCTOR (Automatic close on losing $self)
#
sub DESTROY {
my $self = shift;
$self->{CONNECTION}->close();
return 1;
}
#
########################################################################
########################################################################
# List
#
sub List {
my $self = shift;
my $location = shift;
my @list;
eval {@list = $self->{CONNECTION}->list($location);};
if ($@) {
$self->{ERROR} = $@;
return;
}
return @list;
}
#
########################################################################
########################################################################
# Get
#
sub Get {
my $self = shift;
my $file = shift;
my $location = shift;
eval {$self->{CONNECTION}->get($file, $location);};
if ($@) {
$self->{ERROR} = $@;
return;
}
return 1;
}
#
########################################################################
########################################################################
# Put
#
sub Put {
my $self = shift;
my $file = shift;
my $location = shift;
my $mode = shift;
eval {$self->{CONNECTION}->put($file, $location, $mode);};
if ($@) {
$self->{ERROR} = $@;
return;
}
return 1;
}
#
########################################################################
########################################################################
# Remove
#
sub Remove {
my $self = shift;
my $file = shift;
eval {$self->{CONNECTION}->remove($file);};
if ($@) {
$self->{ERROR} = $@;
return;
}
return 1;
}
#
########################################################################
########################################################################
# Error
#
sub Error {
my $self = shift;
return $self->{ERROR};
}
#
########################################################################
1;
__DATA__
__Java__
import com.trilead.ssh2.*;
import java.io.IOException;
import java.util.*;
public class SFTP {
ConnectionInfo ci;
SCPClient sftp=null;
SFTPv3Client sftpv3=null;
Connection conn=null;
public SFTP(String host, String username, String password) {
boolean b=false;
conn= new Connection(host);
try {
ci=conn.connect();
b=conn.authenticateWithPassword(username,password);
if (!b) {
System.out.println("Invalid login.");
System.exit(0);
}
sftp = new SCPClient( conn );
sftpv3 = new SFTPv3Client (conn);
} catch (IOException e) {
System.out.println("Unable to connect"+": "+e.getMessage());
}
}
public void close()
{
conn.close();
}
public String[] list (String loc)
{
Vector v=null;
SFTPv3DirectoryEntry x=null;
try
{
v = sftpv3.ls(loc);
} catch (IOException e) {
System.out.println("Pickup location does not exist, please check!");
String[] value = new String[1];
return value;
}
String[] s=new String[v.size()];
for (int i=0; i<v.size(); i++) {
x = (SFTPv3DirectoryEntry)v.elementAt(i);
s[i]=x.filename;
}
return s;
}
public void get (String file, String loc)
{
try{
sftp.get(file,loc);
} catch (IOException e) {
System.out.println("Unable to download, please check location or file permissions");
}
}
public void put (String file, String loc, String mode)
{
try{
sftp.put(file,loc,mode);
} catch (IOException e) {
System.out.println("Unable to put"+": "+e.getMessage());
}
}
public void remove (String file)
{
try{
sftpv3.rm(file);
} catch (IOException e) {
System.out.println("Unable to remove"+": "+e.getMessage());
}
}
}
I have a test program called test.pl which looks like this:
use FMS3::Sftp;
my $ftp = FMS3::Sftp->new();
print $ftp->List(".");
All I am trying to do is connect to our server and do a list of the directory. However, I am getting classpath errors when attempting to run test.pl
[perl][1] validate done.
[perl][1] Starting build.
[perl][4] portable: ENV_VAR_PATH_SEP_CP for MSWin32 is ';'
[perl][4] portable: SUB_FIX_JAVA_PATH => H:\svn for MSWin32 is default 'H:\svn'
[perl][4] portable: SUB_FIX_JAVA_PATH => D:\PROGRA~1\IBM\SQLLIB~1\java\db2java.zip for MSWin32 is default 'D:\PROGRA~1\IBM\SQLLIB~1\java\db2java.zip'
[perl][4] portable: SUB_FIX_JAVA_PATH => D:\PROGRA~1\IBM\SQLLIB~1\java\db2jcc.jar for MSWin32 is default 'D:\PROGRA~1\IBM\SQLLIB~1\java\db2jcc.jar'
[perl][4] portable: SUB_FIX_JAVA_PATH => D:\PROGRA~1\IBM\SQLLIB~1\java\sqlj.zip for MSWin32 is default 'D:\PROGRA~1\IBM\SQLLIB~1\java\sqlj.zip'
[perl][4] portable: SUB_FIX_JAVA_PATH => D:\PROGRA~1\IBM\SQLLIB~1\java\db2jcc_license_cu.jar for MSWin32 is default 'D:\PROGRA~1\IBM\SQLLIB~1\java\db2jcc_license_cu.jar'
[perl][4] portable: SUB_FIX_JAVA_PATH => D:\PROGRA~1\IBM\SQLLIB~1\bin for MSWin32 is default 'D:\PROGRA~1\IBM\SQLLIB~1\bin'
[perl][4] portable: SUB_FIX_JAVA_PATH => D:\PROGRA~1\IBM\SQLLIB~1\java\common.jar for MSWin32 is default 'D:\PROGRA~1\IBM\SQLLIB~1\java\common.jar'
[perl][4] portable: SUB_FIX_JAVA_PATH => D:\Program Files\Rational\ClearQuest\cqjni.jar for MSWin32 is default 'D:\Program Files\Rational\ClearQuest\cqjni.jar'
[perl][4] portable: SUB_FIX_JAVA_PATH => C:\Perl\site\lib\Inline\Java\InlineJavaServer.jar for MSWin32 is default 'C:\Perl\site\lib\Inline\Java\InlineJavaServer.jar'
[perl][2] classpath candidate 'C:/Perl/site/lib/FMS3/Sftp/SFTP.jar' scraped
[perl][2] classpath candidate 'C:/Perl/lib/FMS3/Sftp/SFTP.jar' scraped
[perl][4] portable: SUB_FIX_JAVA_PATH => H:\svn\FMS3\Sftp\SFTP.jar for MSWin32 is default 'H:\svn\FMS3\Sftp\SFTP.jar'
[perl][2] classpath: H:\svn;D:\PROGRA~1\IBM\SQLLIB~1\java\db2java.zip;D:\PROGRA~1\IBM\SQLLIB~1\java\db2jcc.jar;D:\PROGRA~1\IBM\SQLLIB~1\java\sqlj.zip;D:\PROGRA~1\IBM\SQLLIB~1\java\db2jcc_license_cu.jar;D:\PROGRA~1\IBM\SQLLIB~1\bin;D:\PROGRA~1\IBM\SQLLIB~1\java\common.jar;D:\Program Files\Rational\ClearQuest\cqjni.jar;C:\Perl\site\lib\Inline\Java\InlineJavaServer.jar;H:\svn\FMS3\Sftp\SFTP.jar
[perl][4] portable: J2SDK_BIN for MSWin32 is 'bin'
[perl][4] portable: EXE_EXTENSION for MSWin32 is '.exe'
[perl][4] portable: IO_REDIR for MSWin32 is '2>&1'
[perl][4] portable: SUB_FIX_JAVA_PATH => H:\svn\_Inline\lib\auto\FMS3\Sftp_7ae5 for MSWin32 is default 'H:\svn\_Inline\lib\auto\FMS3\Sftp_7ae5'
[perl][4] portable: SUB_FIX_CMD_QUOTES => "C:\Program Files\Java\jdk1.6.0_17\bin\javac.exe" -deprecation -d "H:\svn\_Inline\lib\auto\FMS3\Sftp_7ae5" SFTP.java > cmd.out 2>&1 for MSWin32 is default '"C:\Program Files\Java\jdk1.6.0_17\bin\javac.exe" -deprecation -d "H:\svn\_Inline\lib\auto\FMS3\Sftp_7ae5" SFTP.java > cmd.out 2>&1'
[perl][2] "C:\Program Files\Java\jdk1.6.0_17\bin\javac.exe" -deprecation -d "H:\svn\_Inline\lib\auto\FMS3\Sftp_7ae5" SFTP.java > cmd.out 2>&1
[perl][4] portable: COMMAND_COM for MSWin32 is '0'
[perl][2] classpath: .;D:\PROGRA~1\IBM\SQLLIB~1\java\db2java.zip;D:\PROGRA~1\IBM\SQLLIB~1\java\db2jcc.jar;D:\PROGRA~1\IBM\SQLLIB~1\java\sqlj.zip;D:\PROGRA~1\IBM\SQLLIB~1\java\db2jcc_license_cu.jar;D:\PROGRA~1\IBM\SQLLIB~1\bin;D:\PROGRA~1\IBM\SQLLIB~1\java\common.jar;D:\Program Files\Rational\ClearQuest\cqjni.jar
[perl][1] build done.
[perl][1] Starting load.
[perl][4] portable: ENV_VAR_PATH_SEP_CP for MSWin32 is ';'
[perl][4] portable: SUB_FIX_JAVA_PATH => H:\svn for MSWin32 is default 'H:\svn'
[perl][4] portable: SUB_FIX_JAVA_PATH => D:\PROGRA~1\IBM\SQLLIB~1\java\db2java.zip for MSWin32 is default 'D:\PROGRA~1\IBM\SQLLIB~1\java\db2java.zip'
[perl][4] portable: SUB_FIX_JAVA_PATH => D:\PROGRA~1\IBM\SQLLIB~1\java\db2jcc.jar for MSWin32 is default 'D:\PROGRA~1\IBM\SQLLIB~1\java\db2jcc.jar'
[perl][4] portable: SUB_FIX_JAVA_PATH => D:\PROGRA~1\IBM\SQLLIB~1\java\sqlj.zip for MSWin32 is default 'D:\PROGRA~1\IBM\SQLLIB~1\java\sqlj.zip'
[perl][4] portable: SUB_FIX_JAVA_PATH => D:\PROGRA~1\IBM\SQLLIB~1\java\db2jcc_license_cu.jar for MSWin32 is default 'D:\PROGRA~1\IBM\SQLLIB~1\java\db2jcc_license_cu.jar'
[perl][4] portable: SUB_FIX_JAVA_PATH => D:\PROGRA~1\IBM\SQLLIB~1\bin for MSWin32 is default 'D:\PROGRA~1\IBM\SQLLIB~1\bin'
[perl][4] portable: SUB_FIX_JAVA_PATH => D:\PROGRA~1\IBM\SQLLIB~1\java\common.jar for MSWin32 is default 'D:\PROGRA~1\IBM\SQLLIB~1\java\common.jar'
[perl][4] portable: SUB_FIX_JAVA_PATH => D:\Program Files\Rational\ClearQuest\cqjni.jar for MSWin32 is default 'D:\Program Files\Rational\ClearQuest\cqjni.jar'
[perl][4] portable: SUB_FIX_JAVA_PATH => C:\Perl\site\lib\Inline\Java\InlineJavaServer.jar for MSWin32 is default 'C:\Perl\site\lib\Inline\Java\InlineJavaServer.jar'
[perl][2] classpath: H:\svn;D:\PROGRA~1\IBM\SQLLIB~1\java\db2java.zip;D:\PROGRA~1\IBM\SQLLIB~1\java\db2jcc.jar;D:\PROGRA~1\IBM\SQLLIB~1\java\sqlj.zip;D:\PROGRA~1\IBM\SQLLIB~1\java\db2jcc_license_cu.jar;D:\PROGRA~1\IBM\SQLLIB~1\bin;D:\PROGRA~1\IBM\SQLLIB~1\java\common.jar;D:\Program Files\Rational\ClearQuest\cqjni.jar;C:\Perl\site\lib\Inline\Java\InlineJavaServer.jar
[perl][1] starting JVM...
[perl][1] client/server mode
[perl][4] portable: GOT_NEXT_FREE_PORT for MSWin32 is '0'
[perl][4] portable: J2SDK_BIN for MSWin32 is 'bin'
[perl][4] portable: EXE_EXTENSION for MSWin32 is '.exe'
[perl][4] portable: SUB_FIX_CMD_QUOTES => "C:\Program Files\Java\jdk1.6.0_17\bin\java.exe" org.perl.inline.java.InlineJavaServer 4 localhost 7890 false false false for MSWin32 is default '"C:\Program Files\Java\jdk1.6.0_17\bin\java.exe" org.perl.inline.java.In开发者_开发问答lineJavaServer 4 localhost 7890 false false false'
[perl][2] "C:\Program Files\Java\jdk1.6.0_17\bin\java.exe" org.perl.inline.java.InlineJavaServer 4 localhost 7890 false false false
[perl][4] portable: DEV_NULL for MSWin32 is 'nul'
[perl][1] JVM owner exiting...
Can't exec JVM: open3: Can't call method "close" on an undefined value at C:/Perl/lib/IPC/Open3.pm line 370.
at C:/Perl/site/lib/Inline/Java.pm line 484
INIT failed--call queue aborted.
[perl][1] killed by natural death.
[perl][1] exiting with 22
Okay. I figured it out. I had several things wrong:
- Under Study, I had both the Methods and Class, but I only should have the Class.
Wrong
use Inline (
Java => 'DATA',
J2SDK => $ENV{JAVA_HOME},
CLASSPATH => $PERL_CLASSPATH,
STUDY => ["SFTP", "close", "list", "get", "put", "remove"],
# DEBUG => 4,
);
Right
use Inline (
Java => 'DATA',
J2SDK => $ENV{JAVA_HOME},
CLASSPATH => $PERL_CLASSPATH,
STUDY => ["SFTP"],
# DEBUG => 4,
);
- When I declare the SFTP object as
new
, I have to give it the full Perl namespace:
Wrong
eval {$self->{CONNECTION} = new SFTP($server, $user, $password);};
Right
eval {$self->{CONNECTION} = new FMS3::Sftp::SFTP($server, $user, $password);};
You spend several hours on something like this, give up, and then suddenly the light in the ol' dusty attic comes on. I'm a fairly smart guy. Stick a screwdriver in a live socket, and after the third or fourth time, I go "Hey, maybe that's not a good idea".
Try Net::SFTP::Foreign, if you use it with plink (the command line ssh client from the PuTTY package) you would not need any other module to get it working.
精彩评论