RESTとServlet その2

突然ですが、昨年に書いた↓の日記の続きです。
http://d.hatena.ne.jp/da-yoshi/20061115/1163545695
自分はRailsの簡単さとかには正直あまり興味が無いのですが、1.2で目指されている「RESTfulなWebアプリケーションフレームワーク」という部分にもの凄く惹かれています。この機能の詳細を知る為にRailsを学びたいと思ってます。ただ、自分が今までやってきたJavaにはHttpServletという古くて枯れたフレームワークがあります。Railsに行く前に、もう一度この慣れ親しんだServletでRESTを実現できないか考えてみたい・・・ということを、ことあるごとに思っていました。
・・・で、こんなサンプルを書いてみました。

/**
 * 
 */
package test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TestServlet extends HttpServlet {

	/**
	 * 
	 */
	private static final long serialVersionUID = 5222793251610509039L;

	/* (non-Javadoc)
	 * @see javax.servlet.http.HttpServlet#doDelete(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	@Override
	protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("DELETE");
		execute(request, response);
	}

	/* (non-Javadoc)
	 * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("GET");
		execute(request, response);
	}

	/* (non-Javadoc)
	 * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("POST");
		execute(request, response);
	}

	/* (non-Javadoc)
	 * @see javax.servlet.http.HttpServlet#doPut(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	@Override
	protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("PUT");
		execute(request, response);
	}
	
	private void execute(HttpServletRequest request, HttpServletResponse response) throws IOException {
		PrintWriter writer = response.getWriter();
		BufferedReader reader = request.getReader();
		try {
			String str;
			while ((str = reader.readLine()) != null) {
				writer.println(str);
			}
		} finally {
			reader.close();
		}
	}


}

単純に、送られてきたRequestのBODYをReaderで受け取って、Writerで返すだけのServletです。
これをweb.xmlで登録。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    version="2.4">
  <display-name>test</display-name>

  <servlet>
    <servlet-name>TestServlet</servlet-name>
    <servlet-class>test.TestServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  

  <servlet-mapping>
    <servlet-name>TestServlet</servlet-name>
    <url-pattern>/test</url-pattern>
  </servlet-mapping>


</web-app>

そして以下のHTMLでアクセスします。

<html>
<head>
<script type="text/javascript">

var req;

function createXMLHttpRequest() {
	try {
		return this.XMLHttpRequest ? 
			new XMLHttpRequest() : new ActiveXObject("Msxml2.XMLHTTP");
	} catch (e) {
		return new ActiveXObject("Microsoft.XMLHTTP");
	}
}

function execute() {
	var select = document.getElementById("meth");
	var meth = select.options[select.selectedIndex].value;
	req = createXMLHttpRequest();
	var url = "/testWeb/test";
	req.onreadystatechange = readyStateChangeHandler;
	req.open(meth, url, true);
	req.send("Hello World!");
}

function readyStateChangeHandler() {
	if (req.readyState == 4) {
		if (req.status == 200) {
			var data = req.responseText;
			alert(data);
		}
	}
}
</script>
</head>
<body>
<form action="" id="form">
<select id="meth">
	<option value="GET">GET</option>
	<option value="POST">POST</option>
	<option value="PUT">PUT</option>
	<option value="DELETE">DELETE</option>
</select>
<input type="button" value="送信" onclick="execute()">
</form>
</body>
</html>

結果は・・・GET以外はalertで「Hello World!」が表示されました(GETは空白のALERT)。GETは普通にパラメータ使えばいいとして・・・そうか・・・PUTでどうやってパラメータ受け取ればいいんだろう? とか馬鹿なことを考えていましたが、Readerで受け取りゃよかったのですね・・・
まぁ全然RESTでも無くなんでもない、単にメソッドの動作を確認しただけの例なんですが・・・これだけでも、AjaxServletの組み合わせで、RESTfulなアプリを組める可能性は十分にありそうな気がしました。Reader・Writerでやりとり出来るってことは、JSONを使えばAjaxのリッチクライアントとServletで複雑なやりとりだって出来てしまうってことですし(JDK6使えばJSONからJavaBean変換だって出来そうな気がするし)。後は、RESTで最も重要な、URLを解析するサーバサイド側の仕掛けだけですね。調べてませんが、おそらくRails1.2はそこまで含めてフルのRESTfulなWeb「アプリケーション」環境を提供しているんじゃないかと思います。そこらへんは是非勉強して調べてみたい。
・・・そういえば・・・すっかり過去のものとなってしまった、InvokerServletって、Servletの自動マッピング用途に使えたりはしないかな? 今やStrutsのActionもJSFのManagedBeanも規約で自動登録する時代ですから、「Servletはweb.xmlマッピングしなきゃならん」ってのも過去の話のような気がしないでもありません。
あとは、サーブレットコンテナがServletを生成する仕組みに、DIをかませることが出来れば完璧なんですが・・・ここら辺も、InvokerServlet調べたら何かヒントがあるかも?
・・・というわけで、次はいつになるかわかりませんが(汗)、TomcatのInvokerServletを調べてみたいと思ってます。