021 TracやMovableTypeが公開している便利なAPIをXML-RPCで呼んでみよう


こんにちは、id:EC-OneのAkiです。

今日のエントリはEC-Oneの新オフィスにある「裸足専用の会議室」で書いています。
この部屋は会議用というよりは、壁面ホワイトボードにアイデアを書きながらディスカッションをすることに主眼を置いているので、椅子もテーブルもくつろぎ用(?)な感じで、ノートPCを操作するにはちょっとテーブルが低いかな... 会議室のセレクトを間違えた気がします。

TracのチケットをGoogleカレンダーに同期するには?

ある日、ナレッジセンターに「Tracのチケットの終了予定日をGoogleカレンダーに表示するアプリ」を作りたいので、Tracからチケットの情報を取得する方法を教えてほしい、という質問が届きました。

調べてみるとTracには「チケット情報をXML-RPC経由で取得するためのAPI」が公開されている、ということが分かりました。
但しこのAPIを利用するには、「XML-RPCプラグイン」というそのためのプラグインTracに入れる必要があるようです。
ということで、今回はチケット情報の取得方法を検証するために、まずはスタンドアローンJavaプログラムからXML-RPC経由でTracのチケットを取得してみることにしました。

APIを使うにはどんな準備が必要なのか?

対象としたTracEC-Oneイーシー・ワン)の社内にある複数プロジェクト共用のTrac+Subversionサーバです。このTracではHTTPS+Digest認証を利用しており、AccountManagerPluginも入れてあります。OSはLinux系のCentOSです。

ところが、XML-RPCプラグインの説明には

「Problems with Digest HTTP authentication」
「Problems when AccountManagerPlugin is enabled」

XmlRpcPlugin – Trac Hacks - Plugins Macros etc.

という記述があり、どうやら、XML-RPCプラグインの動作確認を行う為にはBasic認証である必要があるようです。

先ほども書きましたが、今回のTracはDigest認証で、かつ AccountManagerPluginが有効ですので、XML-RPCプラグインの動作確認をするためには以下が必要そうです。

  1. TracXML-RPC Pluginをインストール
  2. HttpAuth Pluginをインストール・設定
  3. 当該Trac以下の/login/xmlrpc についてのみ、認証方式をBasic認証に変更
    (TracのURLが「https://myhost/myproj/trac/」ならば「https://myhost/myproj/trac/login/xmlrpc」)

必要なプラグインとサンプルのダウンロード

まずは必要なプラグインをダウンロードします。

  1. http://trac-hacks.org/wiki/HttpAuthPlugin の Download より httpauthplugin-r6395.zip をダウンロード
  2. http://trac-hacks.org/wiki/XmlRpcPlugin の Download and Source より xmlrpcplugin-r6395.zip をダウンロード

ちなみにXML-RPCプラグインの動作を確認するためのサンプルプログラム(Java)は、いろいろ調べて見つけたものから半自作することにしました。このプログラムを動かすために、 http://www.apache.org/dyn/closer.cgi/ws/xmlrpc/ より apache-xmlrpc-3.1.2-bin.zip もダウンロードします。

プラグインのインストールと設定

必要なプラグインが揃ったところでインストールを開始します。
先ずはsftpツール(FileZilla FTP Client)で、httpauthplugin-r6395.zip と xmlrpcplugin-r6395.zip を 当該マシンの /tmp へアップロードします。

# cd /tmp
# unzip xmlrpcplugin-r6395.zip# cd xmlrpcplugin/trunk
# python setup.py install# cd /tmp
# rm -fr xmlrpcplugin

# unzip httpauthplugin-r6395.zip# cd httpauthplugin/0.10
# python setup.py install# cd /tmp
# rm -fr httpauthplugin
# vi <当該プロジェクトのTracのconf/trac.ini>

最後のviでは以下を行います。
まずはtrac.iniの[components]の一番後ろに以下の記述を追加します。

tracrpc.* = enabled
httpauth.* = enabled

次にファイルの一番最後に以下の記述を追加します。

[httpauth]
paths = /login/xmlrpc

これで必要なプラグインのインストールと、設定が完了しました。

Basic認証用の設定

プラグインのインストールが完了したら、次はBasic認証の設定です。
Apachehttpd.conf(またはそこからIncludeしているTrac用の設定)に以下を記述し、対象Tracの/login/xmlrpcにBasic認証を設定します。

<Location "<対象TracのURLのホスト・ポートより後ろ>/login/xmlrpc">
  AuthType Basic
  AuthName bizcreation
  AuthUserFile "<当該サーバの.htpasswdファイルの配置ディレクトリ>/.htpasswd"
  Require valid-user
</Location>

(「<対象TracのURLのホスト・ポートより後ろ>/login/xmlrpc」とは、対象TracのURLが「https://myhost/myproj/trac/」なら「/myproj/trac/login/xmlrpc」)

その後、以下のように設定ミスがないかのチェックを行います。

# /usr/sbin/apachectl configtest

問題がなければApacheを再起動して、Basic認証の設定は完了です。

# /usr/sbin/apachectl graceful

XML-RPC専用のユーザ(xrpcusr)を新規で作成

無事、プラグインBasic認証の設定が済んだところで、XML-RPC用の専用ユーザを用意します。
(なぜ専用ユーザを作るのかというと、Tracのユーザ認証とは別にもうひとつ認証を設定してユーザ名を共用する、かつそのユーザにTracの管理者権限を付けるからです)

当該TracにはWebブラウザからTracの管理を行うための各種プラグインが入っているので、ブラウザで当該Tracにadminでログインし、[管理]→[Users]→[Add external user]で「xrpcusr」を作成します。

また、以下の手順で、当該ユーザにTICKET_VIEW・XML_RPCの権限をつけ、かつ基本認証ファイルに当該ユーザの情報を追加します。

# trac-admin <当該サーバの当該Tracの配置ディレクトリ> permission add xrpcusr TICKET_VIEW XML_RPC
# htpasswd -c <当該サーバの.htpasswdファイルの配置ディレクトリ>/.htpasswd xrpcusr

これでXML-RPC専用のユーザが出来ました。

動作確認

前述の半自作した動作確認用のサンプルプログラム(Java)は以下の通りです。ファイル名はListTracTicket.javaにしました。

import org.apache.xmlrpc.*;
import org.apache.xmlrpc.client.*;

import java.net.URL;
import java.security.cert.X509Certificate;
import java.util.*;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class ListTracTicket {
    private static void install() throws Exception {
        // Create a trust manager that does not validate certificate chains
        TrustManager[] trustAllCerts = new TrustManager[] {
            new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                public void checkClientTrusted(X509Certificate[] certs, String authType) {
                    // Trust always
                }

                public void checkServerTrusted(X509Certificate[] certs, String authType) {
                    // Trust always
                }
            }
        };

        // Install the all-trusting trust manager
        SSLContext sc = SSLContext.getInstance("SSL");
        // Create empty HostnameVerifier
        HostnameVerifier hv = new HostnameVerifier() {
            public boolean verify(String arg0, SSLSession arg1) {
                return true;
            }
        };

        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
    }

    public static void main(String args[]) {
        try {
            ListTracTicket.install();
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }

        XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
        config.setBasicUserName("xrpcusr");
        config.setBasicPassword("<xrpcユーザのパスワード>");

        try {
            config.setServerURL(new URL("<当該TracのURL>/login/xmlrpc"));
              // 当該TracのURLが「https://myhost/myproj/trac/」ならば「https://myhost/myproj/trac/login/xmlrpc」
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }

        XmlRpcClient client = new XmlRpcClient();
        client.setConfig(config);

        Object[] params = new Object[] {"status!=closed"};
        Object[] queryResult = null;
        
        try {
            queryResult = (Object[]) client.execute("ticket.query", params);
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }

        List ticketList = new ArrayList();
        Object matchTicket;

        if (queryResult.length == 0) {
            System.out.println("No ticket");
        } else {
            Object[] params2 = null;
            for (int i = 0; i < queryResult.length; i++) {
                params2 = new Object[] {queryResult[i]};
                try {
                     Object[] Ticketresult = null;
                     matchTicket = new Object();
                     Ticketresult = (Object[]) client.execute("ticket.get", params2);

                     for (int j = 0; j < Ticketresult.length; j++) {
                         System.out.println(Ticketresult[j]);
                     }
                } catch (Exception e) {
                    e.printStackTrace();
                    System.exit(1);
                }
            }
        }
    }
}

今回は「ticket.query」メソッドを呼んでいますが、他にどんなメソッドがあるかは、当該Trac以下の/xmlrpcというURLにアクセスすると、「Remote Procedure Call (RPC) Interface」というタイトルでヘルプが表示されますので、そこで確認してみて下さい。

クライアントPC上の適当なフォルダに 動作確認用のJavaソース ListTracTicket.javaapache-xmlrpc-3.1.2-bin.zip を解凍後そのlib以下にあるすべてのjarファイルを配置して、コマンドプロンプトで下記のように動作確認します。

 set JAVA_HOME=C:\Java\jdk1.6.0_12
 set PATH=C:\Java\jdk1.6.0_12\bin;%PATH%
 
 javac -classpath apache-xmlrpc-3.1.2-bin.zip;ws-commons-util-1.0.2.jar;xmlrpc-common-3.1.2.jar;apache-xmlrpc-3.1.2;commons-logging-1.1.jar;xmlrpc-client-3.1.2.jar;xmlrpc-server-3.1.2.jar ListTracTicket.java
 
 java -classpath .;apache-xmlrpc-3.1.2-bin.zip;ws-commons-util-1.0.2.jar;xmlrpc-common-3.1.2.jar;apache-xmlrpc-3.1.2;commons-logging-1.1.jar;xmlrpc-client-3.1.2.jar;xmlrpc-server-3.1.2.jar ListTracTicket

これで外部からTracからチケットの情報を取得して、表示する事が出来ました!

XML-RPCはどんなことに使える?

今回はたまたまTracのチケットが対象でしたが、他にもXML-RPCでのアクセスの口のあるサイトであれば、上記のソースを元にXML-RPCメソッドを呼び出すことが出来ます。
また上記のソースは「https」「基本認証」という例ですが、それらがなければソースはもっと短く出来るでしょう。

XML-RPCで呼べるAPIは、Tracよりもブログ構築システムの「MovableType」の方が有名かもしれません。XML-RPCを使えば、投稿や記事の取得を外部のプログラムからも行ったり出来ますよ。
お使いのブログがXML-RPC APIを公開しているか調べてみてはいかがでしょう?

ナレッジセンターでは「こんなアプリケーションを作りたいけど、社内システムから情報を取ってくる方法が分からない」という開発のお悩みから、「Tracを導入したいけど、うまく運用するにはどうしたらいいの?」というプロジェクト管理のご相談まで受け付けています。困ったときはお気軽にご相談ください。







JavaRuby及び周辺のOSSを用いた開発に関して、企業があらゆる悩みごとを相談できるのが、ナレッジセンターの「レスキューサービス」です。
どんな相談でも親身に受け付けますので、レスキューサービスってなに?もっと知りたい!と思った方はお気軽に問い合わせ下さい。
問い合わせ画像リンク