JavaHL
JavaHLを使ってJavaからSubversionリポジトリにアクセスする際のメモあれこれ。
JNIを経由して使用する場合、JavaHLに含まれているDLL(libsvnjavahl-1.dll)の他に、Subversionに含まれている以下のDLLも必要となります。なお、-Djava.library.pathでlibsvnjavahl-1.dllの場所を指定している場合、Subversion由来のDLL群はパスの通っているフォルダに入れておく必要があります(java.library.pathとは限らないので注意)。
SVNClientInterfaceを実装したクラスを初期化する必要があります。標準ではSVNClient/SVNClientSynchronizedの2つが準備されています。実際にテストをしたわけではありませんが、クラス名からすると以下のような感じで使い分けをすることになるかと思います。
なお、SVNKitを併用する場合は、これらに加えてDLLなしでアクセス可能なSVNClientImplも利用可能となります。
簡単に実装を切り替えることができるように、直接初期化するのではなく、以下のような感じでgetSVNClient()のようなメソッドを作成しておきます(さすがにFactory化するほどではないかと・・・)。
上記の例ではusernameおよびpasswordをインスタンス変数として定義しておき、認証が要求されるリポジトリへアクセスする場合は事前にそれらのフィールドをセットしておくことでアクセスできるようにしています。
なお、SVNClientInterfaceにはdispose()というメソッドが定義されております。これは、入出力ストリームのclose()に相当する動作を想定しているため、処理の最後(SVNClientが不要になった時点)でdispose()を呼び出す必要があります。
ワーキングコピーC:\svn\Reposフォルダを、最新版のリビジョンで更新する場合で、かつ下位フォルダも含めて再帰的に処理を行うような場合、
といった感じで記述するだけでOKです。なお、戻り値には更新時のリビジョン番号がセットされています。
リポジトリの指定した場所に含まれているファイル(およびフォルダ)のリストを取得します。戻り値はorg.tigris.subversion.javahl.DirEntryの配列で、ここからいろいろな情報を取得できます。
例えば、リポジトリのルートがhttp://localhost/svn/Test/だとして、上記のような処理を行うと、Test/src以下のファイルのリストを再帰的に取得し、そのパスと最終更新リビジョンを表示することができます。
なお、list処理の場合、Notify2#onNotify(NotifyInformation)は呼び出されないようです。
例えばSVNClientInterface#updateの処理だけだと、どのファイルが更新されたかを知ることができません。その情報を取得する場合は、Notify2インタフェースおよびNotifyInformationクラスを使用することとなります。名前が非常にわかりにくいですが、Notify2インタフェースは「リスナー」で、NotifyInformationが「イベント」と考えるとわかりやすいです(Notify2インタフェースを登録するメソッドがSVNClientInterface#notification2(Notify2)になっているのもわかりにくいところ。NotificationListenerとかNotificationEventとかaddNotificationListenerなら、もっと直感的にわかるのですが)。
Notify2インタフェースにはonNotify(NotifyInformation)が定義されており、updateでファイルが更新されたりする度にonNotifyメソッドが呼び出されますので、必要な処理をこのメソッドに記述しておくこととなります。
単に、update処理の際に追加・更新・削除されたファイルを表示するのであれば、以下のような感じになります。
ちなみに、以下のようにしておくと、とりあえずイベントの発生タイミングをいろいろと知ることができます。
注意点
JNIを経由して使用する場合、JavaHLに含まれているDLL(libsvnjavahl-1.dll)の他に、Subversionに含まれている以下のDLLも必要となります。なお、-Djava.library.pathでlibsvnjavahl-1.dllの場所を指定している場合、Subversion由来のDLL群はパスの通っているフォルダに入れておく必要があります(java.library.pathとは限らないので注意)。
- libapr.dll
- libapriconv.dll
- libaprutil.dll
- libdb44.dll
- libeay32.dll
- ssleay32.dll
- intl3_svn.dll
アクセスする
SVNClientInterfaceを実装したクラスを初期化する必要があります。標準ではSVNClient/SVNClientSynchronizedの2つが準備されています。実際にテストをしたわけではありませんが、クラス名からすると以下のような感じで使い分けをすることになるかと思います。
- SVNClient
- 基本実装。多くの場合はこちらを使うことになると思います。
- SVNClientSynchronized
- 複数スレッドから同時にアクセスする場合があるような使い方をする場合。
なお、SVNKitを併用する場合は、これらに加えてDLLなしでアクセス可能なSVNClientImplも利用可能となります。
SVNClientの取得
簡単に実装を切り替えることができるように、直接初期化するのではなく、以下のような感じでgetSVNClient()のようなメソッドを作成しておきます(さすがにFactory化するほどではないかと・・・)。
private SVNClientInterface getSVNClient() {
SVNClientInterface client = new SVNClient();
// SVNKitを使用する場合、
// SVNClientInterface client = SVNClientImpl.newInstance();
// となります。
if (getUsername() != null) client.username(getUsername());
if (getPassword() != null) client.password(getPassword());
return client;
}
上記の例ではusernameおよびpasswordをインスタンス変数として定義しておき、認証が要求されるリポジトリへアクセスする場合は事前にそれらのフィールドをセットしておくことでアクセスできるようにしています。
なお、SVNClientInterfaceにはdispose()というメソッドが定義されております。これは、入出力ストリームのclose()に相当する動作を想定しているため、処理の最後(SVNClientが不要になった時点)でdispose()を呼び出す必要があります。
update
ワーキングコピーC:\svn\Reposフォルダを、最新版のリビジョンで更新する場合で、かつ下位フォルダも含めて再帰的に処理を行うような場合、
SVNClientInterface client = getSVNClient();
long rev = client.update("C:/svn/Repos", Revision.HEAD, true);
といった感じで記述するだけでOKです。なお、戻り値には更新時のリビジョン番号がセットされています。
status
commit
list
リポジトリの指定した場所に含まれているファイル(およびフォルダ)のリストを取得します。戻り値はorg.tigris.subversion.javahl.DirEntryの配列で、ここからいろいろな情報を取得できます。
DirEntry[] dirs = svnclient.list("http://localhost/svn/Test/src", Revision.HEAD, true);
for (int i=0; i<dirs.length; i++) {
System.out.println(
dirs[i].getPath() +
" (Rev." + dirs[i].getLastChangedRevisionNumber() + ")");
}
例えば、リポジトリのルートがhttp://localhost/svn/Test/だとして、上記のような処理を行うと、Test/src以下のファイルのリストを再帰的に取得し、そのパスと最終更新リビジョンを表示することができます。
なお、list処理の場合、Notify2#onNotify(NotifyInformation)は呼び出されないようです。
処理対象ファイルの状況取得
例えばSVNClientInterface#updateの処理だけだと、どのファイルが更新されたかを知ることができません。その情報を取得する場合は、Notify2インタフェースおよびNotifyInformationクラスを使用することとなります。名前が非常にわかりにくいですが、Notify2インタフェースは「リスナー」で、NotifyInformationが「イベント」と考えるとわかりやすいです(Notify2インタフェースを登録するメソッドがSVNClientInterface#notification2(Notify2)になっているのもわかりにくいところ。NotificationListenerとかNotificationEventとかaddNotificationListenerなら、もっと直感的にわかるのですが)。
Notify2インタフェースにはonNotify(NotifyInformation)が定義されており、updateでファイルが更新されたりする度にonNotifyメソッドが呼び出されますので、必要な処理をこのメソッドに記述しておくこととなります。
単に、update処理の際に追加・更新・削除されたファイルを表示するのであれば、以下のような感じになります。
public class SVNUpdateTest implements Notify2 {
public static void main(String[] args) throws Exception {
new SVNUpdateTest().execute();
}
private void execute() throws Exception {
SVNClientInterface client = getSVNClient();
client.notification2(this);
client.update("C:/svn/Repos", Revision.HEAD, true);
client.dispose();
}
public void onNotify(NotifyInformation arg0) {
String msg = "";
int a = arg0.getAction();
if (a == NotifyAction.update_add) msg = "update_add";
else if (a == NotifyAction.update_delete) msg = "update_delete";
else if (a == NotifyAction.update_update) msg = "update_update";
System.out.println(arg0.getPath() + "/" + msg);
}
(中略)
}
ちなみに、以下のようにしておくと、とりあえずイベントの発生タイミングをいろいろと知ることができます。
SVNClientInterface client = getSVNClient();
client.notification2(new Notify2() {
public void onNotify(NotifyInformation info) {
System.out.println(NotifyAction.actionNames[info.getAction()] + " " +
info.getPath() + " (" + info.getRevision() + ")");
}
});
2007年04月01日(日) 21:03:04 Modified by syo1976