Попытка встроить Java в Perl через модуль Inline::Java

Это моя первая попытка встроить Java-код в Perl. Мы не можем использовать стандартную команду SFTP в нашей системе. Это вне моей власти. У нас есть jar-файл с именем SFTP.jar, который можно использовать. Предыдущий человек до меня смог заставить Inline::Perl работать, но его реализация была небрежной, и я хотел бы ее почистить.

Я работаю над системой Windows в каталоге H:\svn. У меня есть модуль в каталоге H:\svn\FMS3, и у меня есть файл jar с именем SFTP.jar в каталоге H:\svn\FMS3\Sftp.pm. Существует файл с именем Sftp.pm, расположенный в каталоге H:\svn\FMS3 и определяющий модуль с именем FMS3::Sftp. (Я храню все наши пользовательские модули в родительском модуле FMS3).

У меня есть встроенный код в FMS3::Sftp, и похоже, что он компилируется. Однако, когда я пытаюсь выполнить, он требует Can't exec JVM: open3: Can't call method "close" on an undefined value at C:/Perl/lib/IPC/Open3.pm line 370.

Что именно я делаю неправильно?

Модуль FMS3::Sftp:

#! /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());
        }
    }
}

У меня есть тестовая программа под названием test.pl, которая выглядит так:

use FMS3::Sftp;
my $ftp = FMS3::Sftp->new();
print $ftp->List(".");

Все, что я пытаюсь сделать, это подключиться к нашему серверу и составить список каталогов. Однако я получаю ошибки пути к классам при попытке запустить 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.InlineJavaServer 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

person David W.    schedule 16.11.2010    source источник
comment
Inline::Perl предназначен для встраивания другого интерпретатора Perl (скажем, для другой версии Perl) в сценарий Perl. Это Inline::Java вопрос.   -  person mob    schedule 16.11.2010
comment
Пробовали ли вы использовать Net::SFTP или один из других SFTP-клиентов Perl на CPAN? Это должно обойти ваше требование не использовать системный sftp без необходимости интеграции нескольких языков.   -  person Eric Strom    schedule 16.11.2010
comment
Я пытался использовать Net::SFTP, но требуется слишком много модулей, которых у нас нет, а установка модулей в нашу систему — большая проблема. Тем не менее, я решил свой вопрос.   -  person David W.    schedule 17.11.2010


Ответы (2)


Хорошо. Я понял. У меня было несколько ошибок:

  • В процессе изучения у меня были и Методы, и Класс, но должен был быть только Класс.

Неправильно

use Inline (
    Java => 'DATA',
    J2SDK => $ENV{JAVA_HOME},
    CLASSPATH => $PERL_CLASSPATH,
    STUDY => ["SFTP", "close", "list", "get", "put", "remove"],
#    DEBUG => 4,
);

Верно

use Inline (
    Java => 'DATA',
    J2SDK => $ENV{JAVA_HOME},
    CLASSPATH => $PERL_CLASSPATH,
    STUDY => ["SFTP"],
#    DEBUG => 4,
);
  • Когда я объявляю объект SFTP как new, я должен предоставить ему полное пространство имен Perl:

Неправильно

eval {$self->{CONNECTION} = new SFTP($server, $user, $password);};

Верно

eval {$self->{CONNECTION} = new FMS3::Sftp::SFTP($server, $user, $password);};

Потратишь на что-то подобное несколько часов, сдашься, и вдруг на старом пыльном чердаке загорается свет. Я довольно умный парень. Втыкаешь отвертку в розетку под напряжением, и после третьего или четвертого раза я говорю: «Эй, может быть, это не очень хорошая идея».

person David W.    schedule 16.11.2010
comment
Придирка: косвенный синтаксис, как правило, устарел. Предпочтительный синтаксис: FMS3::Sftp::SFTP->new(). - person Axeman; 17.11.2010

Попробуйте Net::SFTP::Foreign, если вы используете его с plink (клиент ssh командной строки из пакета PuTTY), вам не понадобится никакой другой модуль, чтобы заставить его работать.

person salva    schedule 18.11.2010
comment
Мы делаем это в системах Unix и Windows, так что это не сработает для нас. - person David W.; 18.11.2010
comment
Net::SFTP::Foreign работает как в Unix, так и в Windows, используя клиенты plink или openssh, или даже модуль Net::SSH2. - person salva; 26.11.2010