JAX-RS - misima RESTful Web Service の実装

本記事は,misima 旧字・旧仮名遣い表記変換サーバ(新字体・現代仮名遣い表記の入力文字列を旧字体・歴史的仮名遣い表記に変換する)と連携して RESTful Web Service を実現するメモである。

Web Service 概要

Web Service は Web HTTP 通信基盤を用いている限りにおいて,通信エンドのプラットフォーム・言語に依存しないサービスが実現できる。通常の Web アプリケーションは Web ブラウザが主なクライアントとなるわけだが,Web Service にはテキストエディタやワードプロセッサ,スプレッドシートなど多様なアプリケーションからリモートプロシジャとして呼び出して使用できる拡張性がある。

Web Service はかつては SOAP (Simple Object Access Protocol) プロトコルで通信する形態が一般的だったが,最近では REST (Representational State Transfer) がメジャーである。REST は SOAP と比べると,XML によるオブジェクト・ラッピングが不要であるなど,より簡易化されている点が特徴だと思う。JSR-311 基づく JAX-RS 1.1 が REST の仕様として標準化されており,この実装には Apache-Wink,Apache-CXF,Jersey などがある。

私はかつて misima SOAP Web Service を公開し,GNU Emacs,秀丸エディタ,Microsoft Word などから旧字・旧仮名遣い変換を行う機能をサポートしていた。しかしながら,認証手段を作り込んでいなかったこともあり,misima サービスを限定公開とした時点で,SOAP サーバ運用を停止した。RESTful Web Service が一般的になったいま,勉強もかねて Apache-Wink を用いて misima RESTful Web Service を作成してみた。この際,ユーザコード認証を入れることで限定ユーザのみが利用できるようにした。この記事の後半部に試行版へのリンクを設置しているので,試していただきたい。(*)

(*) 2014.12.20 に,試行版について一般公開を終了した。現在は,ユーザコードを非公開とすることで友人のための限定公開となっている。

きわめてシンプルな REST アプリケーション例である。既存の BSD Socket インタフェースのサーバと Web Service を接続する JAX-RS RESTful アプリ実装例として参考となる,と私は考える。以下に備忘録を残しておく。

Apache-Wink 1.4

Apache-Wink は JAX-RS 1.1 compatible の Java REST エンジンである。ユーザアプリを REST リソースとして作成し,Wink の REST Servlet から呼び出すことにより Web Service を実現する。クライアントからの GET, POST, PUT, DELETE の通信データ,アプリからのレスポンスデータの仲介を Wink がすべて行ってくれるので,プログラマはデータ編集・サービス処理に注力できる。現時点の最新バージョンは 1.4 である。Apache-Wink サイトからバイナリ版アーカイブをダウンロードして解凍しておく。

misima RESTful Web Service の設計

misima RESTful Web Service の基本設計は以下のとおりである。

  • クライアント要求データを XML フォーマットで POST メソッドで受け取り,変換操作を加え,クライアントに返却する。(misimaRESTful.java)
  • Wink REST Servlet に misimaRESTful クラスを登録するための Application 継承クラスを作成する。(misimaRESTfulApplication.java)
  • クライアント要求データ: 変換対象テキスト,変換オプション,ユーザコード(限定公開ユーザを認証するための秘密コード)の XML データは以下のフォーマットとする。
    <?xml version="1.0" encoding="UTF-8"?>
    <misimaRESTful>
        <misimaParam>misima変換オプション</misimaParam>
        <misimaTarget>変換対象テキスト</misimaTarget>
        <misimaUsercode>ユーザコード</misimaUsercode>
    </misimaRESTful>
    これを JAXB アノテーション @XmlRootElement を介して Java Bean に取得する。(misimaXml.java)
  • 変換操作そのものは,既存の misimaserver 旧字・旧仮名遣い変換デーモンプログラムにソケット接続してこれを行う。(misimaSocket.java)
  • misimaserver ホスト,ポート番号などの初期設定変数は外部プロパティ・ファイルを介して与える。(misimaProperties.java)
  • ロギングは Log4j を使用する。(ここでは詳細割愛)
  • Apache Tomcat 7.0 コンテナにデプロイ(配備)して運用する。
restchart.png
misimaRESTful Web Service 概念図

Eclipse 開発準備作業

Java EE 対応 Eclipse(Eclipse Java EE IDE for Web Developers - 現時点の最新バージョンは Kepler ケプラー)で本システムを開発することとした。Eclipse 画面にて,File - New - Project... から Dynamic Web Project を選択し,Next をクリックして,新規プロジェクト misimaRESTful を作成する。このとき,Target runtimeApache Tomcat v7.0 を指定しておく。(図 1)

eclipse-1-project.png
図 1. Eclipse 新規プロジェクト作成

Apache-Wink 解凍ディレクトリの dist 及び lib の配下にある以下のライブラリ jar ファイルを,misimaRESTful プロジェクト - WebContent - WEB-INF - libImport インポートする。さらに Log4j のライブラリも別にダウンロードしてここにインポートする。(図 2)

  • wink-server-1.4.jar (Apache Wink Server API)
  • wink-common-1.4.jar (Apache Wink Common API)
  • geronimo-jaxrs_1.1_spec-1.0.jar (JAX-RS 1.1 API)
  • jaxb-api-2.2.jar (JAXB API)
  • jaxb-impl-2.2.1.1.jar (JAXB Implementation)
  • slf4j-api-1.6.1.jar (slf4j API)
  • slf4j-simple-1.6.1.jar (slf4j API)
  • log4j-1.2.17.jar (Log4j)
eclipse-2-lib.png
図 2. Eclipse lib Import

Java プログラムコード

src - (default package) に Java ソースを作成する。Java package 文を指定する場合はそれに応じたツリー構造になるが,ここではデフォルトパッケージとしている。設計内容で述べたクラスのソースを以下に示す。ソケット接続先バックエンドの旧字・旧仮名遣い変換サーバ misimaserver がなければ動作しないが,このままで java コンパイルが可能なものである。

misimaRESTful クラスは,misima RESTful Web Service の中核クラスとなる JAX-RS リソースである。ここで,misimaRESTful Web Service へのアクセス URI パスを @Path("/convert") アノテーションにより指定している。実際の変換操作を実行する misimaConvert メソッドに対して次を指定している。

@POST
@Produces("text/plain; charset=UTF-8")
public String misimaConvert(misimaXml ixml)

POST で選択されるメソッドであるということを @POST アノテーションで,返却されるデータ形式が text/plain; charset=UTF-8 であることを @Produces アノテーションで,指示している。クラスへのアノテーション @Consumes({"application/xml", "text/xml"}) によって XML 形式データを入力として指示している。以降で示す misimaXml.java Bean に @XmlRootElement アノテーションを付加しておくことにより,JAXB (Java Architecture for XML Binding) によってアンマーシャリングされ,misimaConvert に対してクライアント要求の XML データを Bean に格納された形で渡すことが出来る。

import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.servlet.http.*;
import org.apache.log4j.*;
/**
 *  misimaRESTful.java - misima RESTful Web Service サーバ
 *  Web Service クライアントからの要求を受け取り,旧仮名・旧字変換支援  
 *  misimaserver サーバにソケットで接続して,変換し,結果をクライアントに返信する。
 *  Copyright(c) 2014, isao yasuda, All Rights Reserved.
 */
@Path("/convert")
@Consumes({"application/xml", "text/xml"})
public class misimaRESTful
{
    /** misimaserver host */
    private static String HOST = "localhost";
    /** misimaserver port */
    private static int PORT = 34000;
    /** MAX テキストサイズ */
    private static int MAXSIZE = 8000;
    /** User code */
    private static String USERCODE = "noxinsomniae201402";
    /** プロパティファイル */
    private static String prop = "misima.properties";
    /** ログファイル */
    private static Logger mslog =
        Logger.getLogger(misimaRESTful.class.getName());
    /** リクエスト */
    @Context private HttpServletRequest req;
 
    /** 
     * 初期処理
     * - プロパティ入力
     * - 開始メッセージ
     */
    static {
        try {
            misimaProperties mprop = new misimaProperties(prop);
            String hostp = mprop.getValue("hostname");
            if (hostp != null) HOST = hostp;
            String portno = mprop.getValue("port");
            if (portno != null) PORT = Integer.parseInt(portno);
            String maxsz = mprop.getValue("maxsize");
            if (maxsz != null) MAXSIZE = Integer.parseInt(maxsz);
            String usercd = mprop.getValue("usercode");
            if (usercd != null) USERCODE = usercd;
        }
        catch (Exception e) {
            mslog.error("Error occured in handling properties: " + 
                e.getMessage());          
        }
        finally {
            mslog.info("misimaRESTful server initialization.");
            mslog.info("- misimaserver host: " + HOST);
            mslog.info("- misimaserver port: " + PORT);
            mslog.info("- max input size: " + MAXSIZE);
            mslog.info("- usercode: " + USERCODE);
        }
    }
     
    /**
     * misima 変換サービス
     * @param ixml 変換対象XML
     * @return ct 変換結果テキスト
     */
    @POST
    @Produces("text/plain; charset=UTF-8")
    public String misimaConvert(misimaXml ixml)
    {
        /** 対象パラメータを取得 */
        String misimaParam = ixml.getmisimaParam();
        String misimaTarget = ixml.getmisimaTarget();
        String misimaUsercode = ixml.getmisimaUsercode();
 
        /** 変換結果 */
        String ct = null;
 
        /**  1. リモートクライアント IP アドレス取得 */
        mslog.info("* Client IP: " + req.getRemoteAddr());
 
        /**  2. user code チェック */
        if (misimaParam == null) {
            misimaParam = "-qkyit -s c";
        }
        if (misimaTarget == null) {
            misimaTarget = "";
        }
        if (misimaUsercode == null) {
            misimaUsercode = "";
        }
        if (!misimaUsercode.equals(USERCODE)) {
            ct = "\nmisima ERROR: not authorized.\n" + misimaTarget;
            mslog.info("Usercode unmatched: " + misimaUsercode);
            return ct;
        }
 
        /**  3. 入力テキストサイズチェック */
        int len = misimaTarget.length();
        if (len > MAXSIZE) {
            ct = "\nmisima ERROR: text (" + len + 
                ") has exceeded MAXSIZE (" + MAXSIZE + ").\n" + 
                misimaTarget;
            mslog.info("Input Text too large: " + len + ".");
            return ct;
        }
        mslog.info("- Params: " + misimaParam +
                   "; length: "  + len);
        mslog.info("- Target: |" + misimaTarget + "|");
 
        /**  4. misimaserver 送信メッセージ生成 */
        StringBuffer mes = new StringBuffer();
        mes.append("<misima_param>" + misimaParam + 
            "</misima_param>" + misimaTarget);
 
        /**  5. misimaserver 接続ソケット生成 */
        misimaSocket ms = new misimaSocket(HOST, PORT);
        try {
            ct = ms.convert(mes.toString());
        }
        /**  6. 接続エラーの場合, ログにエラー出力 */
        catch (Exception e) {
            ct = "\nmisima ERROR: " + e.getMessage() + "\n" + misimaTarget;
            mslog.error("Error occured in connection: " + e.getMessage());
        }
        finally {
            ms = null;
        }
 
        /**  7. 結果を返して終了 */
        mslog.info("- Result: |" + ct + "|");
        return ct;
    }
}

misimaRESTfulApplication クラスは,misimaRESTful リソースを Wink JAX-RS エンジンに登録するためのものである。JAX-RS 実装,コンテナによってはこの手続きは不要であるかも知れない。Apache-Wink 以外の JAX-RS 実装を使う場合は,当該マニュアルを参照していただきたい。

import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;
/**
 *  misimaRESTfulApplication.java - REST Application
 *  misimaRESTful クラスを REST リソースに登録する
 *  Copyright(c) 2014, isao yasuda, All Rights Reserved.
 */
public class misimaRESTfulApplication extends Application 
{
    @Override public Set<Class<?>> getClasses() {
        Set<Class<?>> classes = new HashSet<Class<?>>();
        classes.add(misimaRESTful.class);
        return classes;
    }
}

misimaXml は,ユーザクライアントから送信された XML データを格納する Java Beans クラスである。@XmlRootElement(name="misimaRESTful") JAXB アノテーションを指定することで,JAX-RS エンジンが misimaRESTful タグをルートとする XML データ構造を解析し変数に値をセットしてくれる。

import javax.xml.bind.annotation.*;
/**
 *  misimaXml.java - XML 要求データ Java Beans
 *  Web Service クライアントからの要求を格納する Bean  
 *  Copyright(c) 2014, isao yasuda, All Rights Reserved.
 */
@XmlRootElement(name="misimaRESTful")
public class misimaXml 
{
    /** 変換オプション */
    private String misimaParam;
    /** 変換対象テキスト */
    private String misimaTarget;
    /** ユーザコード */
    private String misimaUsercode;
 
    /** Constructors */
    public misimaXml(String misimaParam, 
                String misimaTarget,
                String misimaUsercode) {
        this.misimaParam = misimaParam;
        this.misimaTarget = misimaTarget;
        this.misimaUsercode = misimaUsercode;
    }
    public misimaXml() {}
     
    /** Getter */
    public String getmisimaParam() {
        return misimaParam;
    }
    public String getmisimaTarget() {
        return misimaTarget;
    }
    public String getmisimaUsercode() {
        return misimaUsercode;
    }
    /** Setter */
    public void setmisimaParam(String misimaParam) {
        this.misimaParam = misimaParam;
    }
    public void setmisimaTarget(String misimaTarget) {
        this.misimaTarget = misimaTarget;
    }
    public void setmisimaUsercode(String misimaUsercode) {
        this.misimaUsercode = misimaUsercode;
    }
}

misimaSocket は,misimaserver デーモンプログラムにソケット接続して,データを送受信する Java クラスである。デーモンの仕様により送受信データの改行コードを置換している以外は,ごくありふれたクライアント・サイド・ソケット処理である。

import java.io.*;
import java.util.regex.*;
import java.net.*;
import org.apache.log4j.*;
/**
 *  misimaSocket.java - misimasever ソケットクライアント
 *  受け取った文字列を,旧仮名・旧字変換支援 misimaserver にソケット 
 *  接続して,変換し,結果をコール元に返却する。
 *  Copyright(c) 2014, isao yasuda, All Rights Reserved.
 */
public class misimaSocket
{
    /** Server host */
    private static String HOST;
    /** Server port */
    private static int PORT;
    /** Socket */
    private Socket sock;
    /** ロガー */
    private static Logger mslog =
        Logger.getLogger(misimaSocket.class.getName());
     
    /** Constructors */
    misimaSocket(String host, int port) {
        HOST = host; PORT = port; sock = null;
    }
    misimaSocket() {
        HOST = "localhost"; PORT = 34000; sock = null;
    }
 
    /**
     * misimaserver 変換
     * @param message misima 変換対象メッセージ
     * @return 変換結果テキスト
     */
    public String convert(String message) throws IOException
    {
        /** \n を :#;~ に置換 - misimaserver 仕様による  */
        Pattern ptn  = Pattern.compile("\n");
        Matcher mtc  = ptn.matcher(message);
        String  sbuf = mtc.replaceAll(":#;~");
        StringBuffer rbuf = new StringBuffer();
         
        /** ソケット接続 */
        try {
            sock = new Socket(HOST, PORT);
 
            /** データを送信する */
            Writer send = new OutputStreamWriter(
                sock.getOutputStream(), "UTF-8");
            send.write(sbuf + "\n");
            send.flush();
 
            /** データを受信する */
            InputStreamReader recv = new InputStreamReader(
                new BufferedInputStream(sock.getInputStream()), "UTF-8");
            int c;
            while ((c = recv.read()) != -1) {
                rbuf.append((char)c);
            }
        }
        catch (Exception e) {
            mslog.error(e.printStackTrace());
            return "Error occured in misimaSocket: " + e.getMessage();
        }
        finally {
            if (sock != null) sock.close();
            sock = null;
        }
 
        /** 行末 \n を削除 */
        ptn = Pattern.compile("\n");
        mtc = ptn.matcher(rbuf.toString());
        String ct = mtc.replaceAll("");
 
        /** :#;~ を \n に復元 */
        ptn = Pattern.compile(":#;~");
        mtc = ptn.matcher(ct);
        return mtc.replaceAll("\n");
    }
}

misimaProperties は,外部ファイルに記述したプロパティを取得するクラスである。misima.properties ファイルに キー=値 を書いておくと,プログラム初期値と異なる動作環境設定値を与えることが出来る。

import java.io.IOException;
import java.util.Properties;
/**
 *  misimaProperties.java - プロパティを提供する
 *  Copyright(c) 2014, isao yasuda, All Rights Reserved.
 */
public class misimaProperties
{
    private Properties conf = null;
 
    /** Constructor 引数 properties file name */
    public misimaProperties(String propfile) 
            throws IOException {
        conf = new Properties();
        conf.load(this.getClass().
                getResourceAsStream(propfile));
    }
     
    /** Key 値のプロパティを取得 */
    public String getValue(String key) {
        return conf.getProperty(key);
    }
}

プロパティ・ファイルの準備

プロパティ・ファイル misima.properties は以下のような内容である。これに基づいて,misimaserver 旧字・旧仮名遣い変換デーモンが稼働するホスト名,ポート番号,テキスト最大サイズ,ユーザコードを外部から与えることができる。Eclipse において misimaRESTful Java ソースと同じ場所に作成しておく。こうしておくと,Eclipse によって classes ディレクトリにコピーされ,つまり,運用時にクラスファイルと同じ場所に置かれる。

# misimaRESTful properties
hostname=localhost
port=34000
maxsize=8000
usercode=noxinsomniae201402

web.xml 準備・デプロイ

Eclipse はコーディングしつつ,コンパイルエラーが確認できる。エラーが解消されたら,デプロイメント・ディスクリプタ web.xmlWEB-INF 配下に作成する。JAX-RS 実装によってこれの書き方は変わって来る。Apache-Wink on Tomcat の場合は,下記のとおり,servlet 定義の servlet-classorg.apache.wink.server.internal.servlet.RestServlet を指定し,init-param において javax.ws.rs.Application に対してリソース登録クラス(misimaRESTfulApplication)を指示しなければならない。

servlet-mappingurl-pattern として /misima/* を指定している。よって misima 変換のための POST URI は http://host:8080/コンテキストルート/misima/convert となる。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">
 
    <display-name>misima RESTful Web Service</display-name>
    <description>misima Convert for RESTful Web Service</description>
 
    <servlet>
        <servlet-name>misimaRESTful</servlet-name>
        <servlet-class>
            org.apache.wink.server.internal.servlet.RestServlet
        </servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>misimaRESTfulApplication</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
 
    <servlet-mapping>
        <servlet-name>misimaRESTful</servlet-name>
        <url-pattern>/misima/*</url-pattern>
    </servlet-mapping>
 
</web-app>

これでデプロイ(配備)の準備ができた。Eclipse で misimaRESTful プロジェクト一式を WAR ファイルに Export エクスポートする。ファイル名を misimaRest.war とする。ルートパスは http://host:8080/misimaRest となる。

Tomcat 7.0 のマネージャ画面(http://host:8080/manager/html)からデプロイする。「配備」-「WARファイルの配備」からこれを行う。配備が成功したら,OK のメッセージとともに,misimaRest がアプリケーション一覧に表示される。(図 3)

rest-tomcat-mgr-0.png
図 3. Tomcat 7 デプロイ・マネージャ画面

curl を用いた試験

配備が完了したら,端末(ターミナル)から curl コマンドで試験してみる。カレント・ディレクトリに test.xml という名で以下の XML ファイルを用意する。これは POST されるデータである。misimaUsercode タグのデータ noxinsomniae201402 は暫定的なもので,限定公開とする際に変更する予定である。

<?xml version="1.0" encoding="UTF-8"?>
<misimaRESTful>
  <misimaParam>-q -kyit -s c</misimaParam>
  <misimaTarget>森鴎外はこう言い,内田百間を団扇であおいだ。
  </misimaTarget>
  <misimaUsercode>noxinsomniae201402</misimaUsercode>
</misimaRESTful>

さて,実行。

$ curl -X POST -H 'Content-Type: text/xml' \
--data-binary @test.xml \
http://yasuda.homeip.net:8080/misimaRest/misima/convert
森鷗外はかう言ひ,內田百閒を團扇であふいだ。
$

旧字・旧仮名遣い変換されたテキストが表示され,成功である。curl コマンドがインストールされていれば,XML ファイルのテキストを変えて試すことができる。

シェルスクリプト

curl コマンドを使えば,以下のようなシェルスクリプトを作成しておくと,変換対象テキストを標準入力から食わせて変換できる。

#!/bin/sh
# misimaRESTful curl script
URL=http://yasuda.homeip.net:8080/misimaRest/misima/convert
IT=`awk '{ print $0 }' < /dev/stdin`
XML="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
<misimaRESTful>\
  <misimaParam>-q $*</misimaParam>\
  <misimaTarget>${IT}</misimaTarget>\
  <misimaUsercode>noxinsomniae201402</misimaUsercode>\
</misimaRESTful>"
curl -X POST -H 'Content-Type: text/xml' --data-binary "${XML}" ${URL}
echo ""

実行は以下のとおり。

$ cat test.txt
森鴎外はこう言い,
内田百間を団扇であおいだ。
$ misimaRESTful.sh -kyitn -s c < test.txt
森鷗外ハカウ言ヒ,
內田百閒ヲ團扇デアフイダ。
$

Web ブラウザからの利用

ブラウザから変換できるページ を用意したので,試していただきたい。変換の様子のスクリーンショットを以下に示す。ただし,misimaRESTful Web Service は,しばらく公開したのち,削除ないし,ユーザコードを変更して限定公開とするので悪しからず。

20140220-webscreen.png
misima RESTful Web Service ブラウザ版

misima RESTful Web Service へのアクセスは jQuery ajax 関数を用いた非同期 POST による。フォームの入力から XML を組立てている。HTML 及び JavaScript を以下に掲載しておく(一部省略しているところがある)。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <link rel="stylesheet" type="text/css" href="./css/misima-style.css" />
    <title>misima RESTful Web Service</title>
</head>
<body>
    <div style="width: 470px; text-align: center;">
        <h2>misima 旧字・旧仮名遣い変換 RESTful Web Service</h2>
    </div>
    <div class="option">
        <select id="bopt">
            <option value="1" selected>旧字/旧仮名/用語/繰返</option>
            <option value="2">旧字/旧仮名/用語</option>
            <option value="3">旧字/旧仮名</option>
            <option value="4">旧字</option>
        </select>&nbsp;
        <input type="checkbox" id="topt" />LaTeX&nbsp;
        <input type="checkbox" id="nopt" />仮名反転&nbsp;
        <input type="checkbox" id="lopt" />簡体字&nbsp;
        <input type="checkbox" id="dopt" />形態素解析出力<br />
        <textarea id="obj" cols="40" rows="20"
            style="width: 470px; height: 84px; overflow: auto;"></textarea>
    </div>
    <div style="width: 470px;">
        <div style="float: left; width: 70%">
            Usercode:&nbsp;
            <input type="text" id="ucode" size="30" value="noxinsomniae201402" />
        </div>
        <div style="float: left; text-align: right; width: 30%">
            <input type="button" value="変 換" onclick="misimaConvert();" />
            <input type="button" value="クリア" onclick="clearText();" />
        </div>
    </div>
    <div id="status"></div>
    <div id="out"></div><!-- ここに変換結果を挿入  -->
 
    <!-- JavaScript Library -->
    <script type="text/javascript" src="./js/jquery-1.10.2.min.js"></script>
    <script type="text/javascript" src="./js/misima-rest.js"></script>
</body>
</html>
/*
    misima RESTful Web Service convert
    2014(c) isao yasuda, All Rights Reserved.
 */
 
// Global Valuables
var postUrl = "/misimaRest/misima/convert"; // Server path
var maxSize = 8000; // Max text size
var xmlQuery; // XML query to be posted
 
// サーバに検索リクエストを非同期 POST する 
function invokeServer() {
    // processing
    $('#status').html("misima 処理中...");
    // Ajax Communication to POST XML data
    $.ajax({
        url: postUrl, // misima RESTful Web Service URL
        type: "POST",
        contentType: "application/xml; charset=UTF-8",
        dataType: "text",
        cache: false,
        data: xmlQuery
    }).done(function(result, textStatus, jqXHR) {       // 通信成功
        result = result.replace(/\r?\n/g, "<br />");
        $('#out').html(result); // 変換結果挿入
        $('#status').html("Normally ended.");
    }).error(function(jqXHR, textStatus, errorThrown) { // 通信失敗
        $('#status').html("Error occured. status: " + textStatus + 
            " thrown: " + errorThrown);
    }).complete(function(jqXHR, textStatus) {           // 通信完了
        window.status = "misimaConvert completed, textStatus: " + 
            textStatus;
    });
}
 
// misima 変換処理を実行する
function misimaConvert() { 
    // 変換対象テキストを取り出し,テキスト長をチェック
    var it = $('#obj').val();
    if (it.length == 0) {
        alert("対象テキストを指定してください");
        return;
    }
    if (it.length > maxSize) {
        alert("入力テキストが最大値" + maxSize + "を越えています");
        return;
    }
    // Usercodeを取り出す
    var uc = $('#ucode').val();
    if (uc.length == 0) {
        alert("Usercode を指定してください");
        return;
    }
    // misima オプション + テキスト(改行文字変換) で電文を作成する
    var ps = makeParams();
    var pt = /-x /;
    var le = "";
    if (pt.test(ps)) {
        le = it.replace(/\r?\n/g, " :#;~" );
    } else {
        le = it.replace(/\r?\n/g, ":#;~");
    }
    // XML を組み立てる
    xmlQuery = '<?xml version="1.0" encoding="UTF-8"?>' +
        '<misimaRESTful>' + 
        '<misimaParam>' + ps + '</misimaParam>' + 
        '<misimaTarget>' + le + '</misimaTarget>' + 
        '<misimaUsercode>' + uc + '</misimaUsercode>' +
        '</misimaRESTful>';
    // サーバに要求を出す
    invokeServer();
}
 
// misima オプションを組み立てる
function makeParams() {
    var params = "-q"; // 初期値: quiet mode
    // -s:旧字/-k:旧仮名/-y:用字/-t:単純補正/-i:繰返符号変換
    var bopt = $('#bopt').children(':selected').val();
    switch (bopt) {
        case "1": params += " -kyit -s c"; break;
        case "2": params += " -kyt -s c";  break;
        case "3": params += " -kt -s c";   break;
        case "4": params += " -t -s c";    break;
        default: break;
    }
    // LaTeX 変換: -x 漢文・多国語サポート, ドイツ語モード
    params += ($('#topt').prop('checked')) ? " -x kuit -g" : "";
    // 仮名反転: -n
    params += ($('#nopt').prop('checked')) ? " -n" : "";
    // 簡体字-繁体字変換: -l
    params += ($('#lopt').prop('checked')) ? " -l" : "";
    // 形態素解析出力: -d
    params += ($('#dopt').prop('checked')) ? " -d" : "";
    return params;
}
 
// 入力テキストをクリアする
function clearText() {
    $('#obj').val('');
}
 
// 初期状態のフォーカス
$(function() {
    $('#obj').focus();
});

参考文献

JAX-RS RESTful Web Service について詳しく解説している参考図書のなかで,何をおいてもまずは,オライリー,Bill Burke の本をあげるべきだろう。Ruby の著書はクライアント実装の記述も充実している。

RESTful Webサービス
Leonard Richardson Sam Ruby
オライリー・ジャパン

misima RESTful Web Service クライアントの実装例 [ 付記 ]

上記に,Web ブラウザから利用するための JavaScript 及び,curl コマンドを用いたコマンドライン型クライアントを示した。本記事を書いたのち,いくつかのアプリケーションから misima RESTful Web Service を利用するためのクライアントの実装例を試作した。以下にそれら記事へのリンクを設置しておく。

[ 2015/02/02 付記 ]
misima RESTful Web Service は 2014/12 より友人のためだけの限定公開といたしました。上記ユーザ認証コードでは動作しません。