Perlは言語学者が作っただけあって、おおむねそのまま読んで自然言語のように意味が伝わるような識別子が選ばれている。他の言語だと外部ライブラリの読みこみに import foo.foo.foo.foo; とか require hoge/hoge とか割り当てられているけど、Perlの場合は use Hoge; となる。
昨日、Perl から Java を使うという、その名も Java というCPANモジュールを発見、試してみた。このモジュールを使う時、use Java; となるので、PerlからJava使ってやるんだいっーという感じがしてほほえましい。
これの動作の理論は、付属してくる JavaServerというJava仮想マシンを先に立ち上げておいて、それに対してソケットを張る(デフォルトはポート2000番)というもので、Inline::Java とは違う。
CPANでinstall Javaって入力する不思議さを味わうのもよいなあ。ぉぃぉぃPerlモジュールいれるんじゃないのかよ、みたいな。
http://search.cpan.org/~metzzo/Java/Java.pm
ちなみに環境はWindowsXP、ActivePerl5.8.7で試しました。Javaは
> java -version
java version "1.4.2_08"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_08-b03)
Java HotSpot(TM) Client VM (build 1.4.2_08-b03, mixed mode)
以下のような簡単なものを D:Java-4.7Dog.java として保存。
public class Dog {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public String toString() {
return "Bow! (" + this.name + ")";
}
}
そしてコマンドラインから D:Java-4.7>javac Dog.java
Dog.classができたことを確認し、Dog.class を使ってみる Perlスクリプトを以下みたいな感じで作成し、D:Java-4.7Dog.pl とかで保存。
#!/usr/bin/perl
use strict;
use Java;
my $dog = Java->new->create_object('Dog');
$dog->setName('Pochi');
print $dog->getName->get_value();
そして例の仮想マシンを起動する。
D:Java-4.7>java -cp JavaServer.jar;D:Java-4.7 com.zzo.javaserver.JavaServer
待機しはじめるはず。このDosプロンプトがコンソールになる(エラーのスタックレースとかが並ぶ)ので、別なプロンプト立ち上げて、D:Java-4.7>perl Dog.pl
PochiがワンとなけばOK。
ちょっと補足すると、なぜ print $dog->getName(); でreturnの値を参照できないかというと、Javaの型をPerlにコンバートするために、値はオブジェクトを通してやり取りされるから。(booleanとかcharとかあるもんね)->get_value() がtoStringという感じです。
このモジュール、PerlからJavaを使ってSwingでGUI部品を組み立てていくサンプルが多くて、その場合は
use Java; # したあと、
my $java = new Java(); # Javaオブジェクトを作って、
my $string = $java->create_object("java.lang.String", "HogeHoge"); # とか
my $frame = $java->create_object("java.awt.Frame", "Frame's Title"); # していくみたい
もうちょっと発展させてみたいけど、JavaでGUIはやったことないので、以下のようなクラスを作って、PerlからJavaxのmailを通してメールを送ってみることにした。
D:Java-4.7SendmailTest.java
import java.util.Properties;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.AddressException;
public class SendmailTest {
private String smtp;
private String to;
private String subject;
private String body;
public SendmailTest(String smtp) {
this.smtp = smtp;
}
public boolean send() {
Properties properties = new Properties();
properties.setProperty("mail.smtp.host", this.smtp);
Session session = Session.getDefaultInstance(properties);
MimeMessage mail = new MimeMessage(session);
try {
mail.setRecipients(MimeMessage.RecipientType.TO, this.to);
mail.setSubject(this.subject);
mail.setText(this.body);
mail.saveChanges();
Transport.send(mail);
return true;
} catch(MessagingException e) {
e.printStackTrace();
return false;
}
}
}
Java詳しくないんでいいかげんだけどいいのだ。これはいくつか別クラスを使うので、コンパイルは以下みたいな感じに。mail.jarとactivation.jarが必要です。
D:Java-4.7>javac -classpath C:j2sdk1.4.2_08libmail.jar;C:j2sdk1.4.2_08libactivation.jar SendmailTest.java
Perlコードはこんな感じ。set_field() や get_field() を使ってみました。
D:Java-4.7SendmailTest.pl
#!/usr/bin/perl
use Java;
$mail = Java->new->create_object('SendmailTest', 'ここにはSMTPサーバー名を入れてね');
$mail->set_field( to => 'java_test@example.net'); # もちろん変えてねー
$mail->set_field( subject => 'from Perl');
$mail->set_field( body => 'Hello!' );
if ($mail->send()->get_value() eq 'true') { # booleanのget_valueは true か false になる
printf "Success. (to = %s)
",
$mail->getfield('to')->getvalue();
} else {
print "Error!
";
}
JavaServerも再起動が必要です。Ctrl+Cで終了して、以下みたいに使うクラスを指定して再実行
D:Java-4.7>java -cp C:j2sdk1.4.2_08libmail.jar;C:j2sdk1.4.2_08libactivation.jar;JavaServer.jar;D:Java-4.7 com.zzo.javaserver.JavaServer
そいで
D:Java-4.7>perl SendmailTest.pl
Success. (to = java_test@example.net)
とかなればOK。
ほかにもいろいろメソッドが用意されているみたいだから、テストに使うと便利? いやかえって不便だし信頼できないよ、とか、これってAcmeなんじゃないか?とか思いながらも、おもしろかったし use Java; っていう思い切ったネーミングが気に入ってしまいました。
ちなみに今回は関係ないけど、ActivePerlのインストール先を c:usr にすると Windows でも #!/usr/bin/perl になるのでCGIとかそのままでいけるので楽なのでおすすめ