2012年7月8日日曜日

Eclipse の機能を使ったプログラムを java コマンドで実行する

Eclipse のプラグインを開発する場合、多かれ少なかれ他のプラグイン(Eclipse 自体がプラグインで出来ています)のクラス群を利用することになります。また、 Eclipse のプラグインではない普通のプログラムを作る場合にもそれらクラス群を利用可能です。実際に Eclipseプラグインの開発サイクル短縮化計画 では、Eclipseプラグインを通常のJavaアプリに変えて実行しています。


Eclipse をインストールしたディレクトリの plugins ディレクトリを開いてみれば、膨大な数の jar ファイルに驚くと思います。これらの jar ファイルに含まれるクラス群を自由に使っていいと思うと非常にワクワクしますね!

今回はコマンドラインから java コマンドを用いて、 Eclipse のクラス群を利用した通常のアプリを起動させる方法を模索しました。なぜかって?アプリのテストを自動化するためです。java コマンドで起動させられれば、 Eclipse の上で実行せずとも、シェルスクリプトなどを用いてアプリを起動でき、 Eclipse と疎結合なテストが書けるのです。

さて、ここで問題になるのは、 Eclipse のクラス群を CLASSPATH に設定しなくちゃいけないということです。例えば CLASSPATH を設定せずに僕が作っているアプリを起動させると

Exception in thread "main" java.lang.NoClassDefFoundError: org/eclipse/core/runtime/IPath
 at com.github.uchan_nos.c_helper.Launcher.main(Launcher.java:112)
Caused by: java.lang.ClassNotFoundException: org.eclipse.core.runtime.IPath
 at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
 ... 1 more
という出力が出てきます。
ここで「ふむふむ、 org.eclipse.core.runtime.IPath が見つからないのか。では org.eclipse.core.runtime_3.8.0.v20120521-2346.jar を CLASSPATH に追加しよう。」と考えても、実は IPath クラスはそのjarファイルに含まれておらず、先ほどの例外は解決しないのです。
どうも、Eclipseのプラグイン(プラグイン=jarファイルと考えていいだろう)の名前と、それに含まれるクラスのパッケージ名が一致しないらしいのです。うーん、こまった。


ということで、 Eclipse の plugins ディレクトリにあるすべてのjarファイル名を列挙して、それをコロン:区切りで結合した文字列を出力するだけのスクリプトを書いてみました。
import os
import sys
import re

if __name__ == '__main__':
 plugindir = '/Applications/eclipse-juno/plugins'
 if len(sys.argv) == 2:
  plugindir = sys.argv[1]
 elif len(sys.argv) != 1:
  print('Usage: python searchplugins.py [plugin-directory]')
 
 classpath = '.'
 jarpat = re.compile(r'.*\.jar')
 files = os.listdir(plugindir)
 for f in files:
  m = jarpat.match(f)
  if m:
   classpath += ':' + os.path.join(plugindir, f)
 print(classpath)
とても愚直な実装だが。。。このスクリプトは/Applications/eclipse-junoをデフォルトのEclipseインストールディレクトリとしていますから、使う場合には変えたほうがいいでしょう。このスクリプトを searchplugins.py のような名前で保存し
python searchplugins.py
と実行すれば、/Applications/eclipse-juno/pluginsディレクトリの中にあるすべてのjarファイルのフルパスが : 区切りで出力されます。
.:/Applications/eclipse-juno/plugins/ch.qos.logback.classic_1.0.0.v20111214-2030.jar:/Applications/eclipse-juno/plugins/ch.qos.logback.core_1.0.0.v20111214-2030.jar
というような感じに。先頭にカレントディレクトリ.を含めてあるので、この出力をそのまま CLASSPATH に設定すれば、Eclipseのクラス群を利用したアプリが起動できるということになります。

CLASSPATH=`python ../test/searchplugins.py` java com/github/uchan_nos/c_helper/Launcher
実際には上記のようなコマンドを実行することにより、 Eclipse プラグインがすべて CLASSPATH に設定された状態で目的のアプリが起動し、めでたく実行できました。やったね!

0 件のコメント:

コメントを投稿