yamicha.com's Blog - Presented by yamicha.com
Blog yamicha.com's Blog - 2017/11 の記事
[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23] [24] [25] [26] [27] [28] [29] [30]

yamicha.com's Blog
 諸事情により、現在更新休止中。ご了承ください。もし今後ブログを再開することがあるとすれば、その際にはこのブログスクリプトではなく、新しく開発したものによるかもしれません。
 当ブログ管理者についてはこちらをご参照。
開発魔法(737)
社会問題(733)
お知らせ(11)
質問・バトン回答(15)
ゲスト出演(8)
経済・知的財産(150)
ゲーム開発(182)
[Ada] 勝手に補足
- Note
- 金配りの次の一手


- Endless Ultimate Diary
- 銃世界

漢字バトン
- うるる雑記帳
- 漢字接力棒

ツキアイゲノムバトン
- ブログ@うにうに画像倉庫
- あぶ内閣

縺イ縺セ縺、縺カ縺励ヰ繝医Φ
- 月夜のボヤキ
- 騎士サーラバトン
パスワードを使う
名無し (2012/02/27)


開発者解放裁判
yamicha.com (2010/03/14)
Winnyに関しては、私も「純白」とまでは考えておりませんし、使用し..

開発者解放裁判
通りすがり (2010/03/08)
winnyに関しては「ダウンロードソフト板」なんてところを拠点に開発..

新型インフルエンザの恐怖
いげ太 (2009/11/03)
> C#などの「int Some(int , int)」は、F#では「(int * int) ->..

時効に関する思考
yamicha.com (2009/08/31)
>いげ太さんコメントありがとうございます。手元にドキュメントが少..
Homepage
Blog Top
Normal View
List View
Search
Calendar
Comment List
Trackback List
Blog RSS
Send Trackback
Phone Mode
Administrator
yamicha.com
Blog
るううるる。
Source
法令データ提供システム
FindLaw
Development
Java2 Platform SE 6
Java EE 6 API
MySQL Developer Zone
PHP Reference
MSDN Library
Ada Reference Manual
Objective Caml
Python Documentation
Erlang
Prolog Documents
カテゴリ表示
 カテゴリ 開発魔法 に当てはまるもののみを表示します。

 存在する記事 737 件の中から 16-20 件を表示しています。
新倒壊革
2010/04/24(Sat)05:33:26
 自民党の敗北後より、水面下で不穏な動きを見せていた舛添氏ですが、このほどようやく「舛添新党」の道を選ぶことが明らかになりました。舛添氏ら3氏が改革クラブに合流し、これを衣替えして「新党改革」に変更、舛添氏が党首に就任するという形式を取るようです。一方、舛添氏に反発した2名が同党から離脱し、同党の保有議席は5から6に1つ増えるにとどまります。
 改革クラブ自体が2007年の参院選における民意を裏切って結党された政党であり、民主党のものとして与えられたはずの議席にただ乗りして政党交付金を確保しようとする、大義に乏しい党であることは同党の結党時にも述べましたが、舛添氏がそのような体質の政党に合流し、結果として同党が同様の行為を再び繰り返そうとするのは、皮肉であるとしか言いようがありません。しかも舛添氏は自民党の比例代表として当選しているのですから、こちらは真の意味で自民党の議席にただ乗りしています。
 与謝野氏や舛添氏らのような大物が離党している状況でありながら、ほとんどの自民党議員が呼応しない点からしても、多くの自民党議員は新党騒ぎを非常に冷めた目で見ているようです。事実、舛添氏が引き連れて入党となった議員も3名に過ぎず、独自の新党では政党要件さえも満たせないか、もし満たせたとしても苦しい状況となります。しかし、改革クラブを媒体として使用すれば、引き続き政党交付金も受け取れます。一方、改革クラブは二大政党や各新党の狭間への埋没に危機感を抱いているはずで、自分の党の「色」を犠牲にし、所属議員2名を失ってまで舛添氏を党首に受け入れたのは、まさにそれを打破する意図があるからこそでしょう。すなわち、どうしても実現したい共同の理念があるからというより、両者の利害が一致した結果が、この衣替え新党と見るのが妥当です。
 このようなやり方に対しては、「政党交付金を受け取るのは道理に合わない」との批判が出てくるのは当然ですが、舛添氏は「我々は金のかかる政治と決別したい」などと言っておきながら、政党交付金への批判に対しては「企業や労組から金を受け取れば、彼らは口も出す。我々は政党交付金でやるから国民全体をみている」と意味不明な論理を持ち出して正当化しています。この状況下で政党交付金を受け取るのは道理に合わないから批判が出るのであって、ここでは企業や労組などは全く関係がありません。団体献金を受け取らない姿勢は大いに結構ですが、これでは「政党交付金を受け取るのは道理に合わない」という疑問への説明になっていません。
 そもそも、私が舛添氏を信用しない理由の1つに、氏があまりにも自分勝手でご都合主義、あるいはその場限りの言い分を用いることが挙げられます。例えば、舛添氏が厚生労働相に就任していた時期、年金の記録の散逸が問題になった際には、どう考えても守りようのない期限を自ら掲げた挙句、案の定実現できないと分かったら、今度は開き直りをはじめました。また、自民党の大敗後には「今の自民党に必要なのは、民主党の小沢代表以上の独裁者」などと言っておきながら、後から谷垣体制を批判した際には「批判のない政党は独裁政党」と称して自らの行為を正当化する有様で、まるで発言の整合性が取れていません。今回の「新党改革」の件にしても、まさに当の舛添氏が真っ先に「金目当て」などと批判しそうなやり方ですし、手段を選ばず政党交付金を受け取る行為も「政治とカネ」の問題の一分類に他ならず、これもまた国民の政治不信の一因となっている事実を忘れてはいけません。
 一方、自民党は高い人気を誇る舛添氏を失い、衆院選大敗及びその後の混乱に続いて大きな痛手をこうむっているはずですが、ここは「自ら手を下すまでもなく厄介払いができた」と前向きに考え、党の再生を図るべきでしょう。与謝野氏にせよ、舛添氏にせよ、実際のところ彼らの離党は痛手などではなく、膿が排出されたと考えるべきです。
 舛添氏がここまで新党結成を先延ばしにしたのは、自民党総裁の座を狙っていたと考えるのが妥当です。しかも、国民からの高い人気を背景に、自民党議員の満場一致、円満譲渡のような形で総裁の座に就くことを狙っていたと考えられます。氏が今回離党に踏み切ったのも、谷垣氏や自民党が代表の座を譲渡しようとする気配を見せなかったためでしょう。
 しかし、このまま舛添氏が離党をしていなければ、いずれ自民党は「国民の声」に押しつぶされ、どうしても氏を総裁にせざるを得なくなった可能性が十分にあります。そして、仮に氏が自民党総裁に就任していれば、それこそ自民党ばかりか日本が大混迷に陥ったであろうことは想像に難くありません
 舛添氏は「はっきり物を言う」とみなされている人物であり、それが実直あるいは明快な印象を与え、国民の人気を獲得しているものと考えられます。さらに、マスコミは人気のある人物の批判を避けようとするため、氏の数々の暴言や問題はほとんど報道されておらず、結果として氏を政界の救世主でもあるかのように翼賛する報道ばかりが目立っています。しかし、仮に二大政党の片方を占める大政党の代表に就任したとなれば、氏も口当たりの良い発言ばかりはしていられませんし、問題発言があればマスコミといえど隠し通すのは困難です。
 すなわち、氏が代表就任後も「はっきり物を言う」姿勢を続けるならば、無賃残業合法化など氏が強硬に主張している政策、あるいはこれまで散々繰り返してきたものの、ほとんど報道されてこなかった暴言なども、それからはすべて白日の下にさらされる結果となり、国民の人気を失うのは時間の問題です。一方、氏がその姿勢をある程度改め、二枚舌政治を行うならば、今度は「舛添氏も他の政治家と変わらなかった」という印象を国民に与える結果となるでしょう。
 そして、仮にひとたび舛添氏の人気が落ち始め、マスコミが氏に遠慮しなくなれば、氏の体制が破綻するのは時間の問題です。なぜなら、氏は「小人のざれ言に付き合う暇はない」「バカ市長と言わないだけマシ」などといった暴言を吐いたり、かつて自らが「みなし役員」などの問題を管轄とする省のトップにありながら、「残業代が出なくなれば、みんな早く帰って家庭だんらんができる」などという、およそ実態とかけ離れた理由によって無賃残業合法化を強く推進したり、無賃残業合法化を「家庭だんらん法案」と言い換えさえすれば国民をだませると考えていたりと、実際には人格的・政策的にほとんど見るべき点のない人物であるためです。
 今のところはマスコミが批判的な報道を控えているため、これらの火種は表面化せずに済んでいますが、もしマスコミが手のひらを返し、国民も舛添氏の人格・政策について関心を持てば、まるで螺旋階段を転がり落ちるかのような勢いで、舛添氏は一気に支持を失ってしまうでしょう。もしそうなれば、自民党もただでは済みません。単に支持を失うばかりか、今度こそ壊滅的な打撃を受ける可能性さえ否定できません。
 その舛添氏が自ら党を去ったのですから、これは本来なら自民党にとって「願ってもない話」なのです。確かに自民党は国民からの支持を失っており、かなり苦しい状況にありますが、国民は雨後のたけのこのごとく湧き出る新政党にもほとんど期待してはいません。現在の自民党には、未だに堂々と世襲を続けたり、人気者の世襲議員を重用したりといった問題点もあるものの、民主党も落語家を擁立するなど、負けず劣らずの暴挙に出ています。せっかく与謝野氏や舛添氏のような懸念材料も消えたのですから、これらの点を改善しようと努力し、くだらない人気取りをやめ、「苦い薬」も含めて実直に政策を訴えるようにすれば、党を立て直せる可能性は十分にあります。
 そして当然のことながら、自民党総裁の可能性は当面は薄まったとはいえ、舛添氏の動向には今後とも十分に注意が必要です。現在の閉塞した政治状況において、政界再編が必要であるとする意見は理解できますが、それは舛添氏以外の手によって行われなくてはなりません。

 JAX-RSでは自動的にJAXBの変換を行ってくれるため、特にこれといった変換操作をしなくても、普通にオブジェクトを扱うかのように操作が可能であることは前回に試しました。
 しかし、JAX-RSで自動的に行えるのは、何もJAXBの変換だけではありません。あのいまいましいAjaxのせいで注目されてしまった技術・JSONすら変換できてしまいます。しかも、JSON用に特別なJavaBeanを用意したり、JSON化及び復元するためのコードを書かなくても、XMLをやり取りするのと同様の書き方をしておけば、それでJSONにしたり戻したりする変換が自動的に行われるというのです。
 そうであるならば、何らかの操作について「XMLでのやり取り」と「JSONでのやり取り」の両方を提供するのも非常に容易になりますし、場合によってはAjaxから直接アクセスするといった使い方も考えられます。いずれにしても、かなり面白そうな機能には違いありません。
 今回はとりあえず、前回の計算プログラムをJSONでも使えるよう拡張してみるものとしました。
/WEB-INF
 /classes
  /com
   /yamicha
    /rs
     /server
      @XmlRootElement Calc.java
      @Path CalcService.java
     /client
      @WebServlet CalcServlet.java
 web.xml
calcForm.htm
calcAjax.htm
 今回はあくまで「JSON対応にする」だけですので、web.xmlとCalc.javaの内容は前回と全く同様です。すなわち、データを保持するJavaBeanには全く手を加える必要がないことを意味します。JSONとして用いる場合でも、そのまま使えてしまいます。
 CalcService.javaは以下の通り拡張しました。
package com.yamicha.rs.server;

import javax.ws.rs.*;
import javax.ws.rs.core.*;

@Path("calc") public class CalcService{
	public CalcService(){
	}

	// 計算用メソッド
	private Calc executeCalc(Calc calc){
		try{
			int answer = 0;

			int v1 = Integer.parseInt(calc.getValue1());
			int v2 = Integer.parseInt(calc.getValue2());
			String operator = calc.getOperator();

			if("+".equals(operator))
				answer = v1 + v2;
			else if("-".equals(operator))
				answer = v1 - v2;
			else if("*".equals(operator))
				answer = v1 * v2;
			else if("/".equals(operator))
				answer = v1 / v2;
			else if("**".equals(operator))
				answer = (int)Math.pow(v1 , v2);
			else
				return calc;

			calc.setAnswer(String.valueOf(answer));
		}catch(NumberFormatException e){
		}

		return calc;
	}

	// パラメータを取り、結果を XML 形式で返す
	@GET @Path("query/xml") @Produces("application/xml")
		public Calc queryToXml(
		@QueryParam("value1") String v1 ,
		@QueryParam("operator") String op ,
		@QueryParam("value2") String v2){
		Calc calc = new Calc();
		calc.setValue1(v1);
		calc.setValue2(v2);
		calc.setOperator(op);

		return executeCalc(calc);
	}

	// XML を取り、XML を返す
	@POST @Path("xml/xml") @Consumes("application/xml")
		@Produces("application/xml")
		public Calc xmlToXml(Calc calc){
		return executeCalc(calc);
	}

	// JSON を取り、XML を返す
	@POST @Path("json/xml") @Consumes("application/json")
		@Produces("application/xml")
		public Calc jsonToXml(Calc calc){
		return executeCalc(calc);
	}

	// JSON を取り、JSON を返す
	@POST @Path("json/json") @Consumes("application/json")
		@Produces("application/json")
		public Calc jsonToJson(Calc calc){
		return executeCalc(calc);
	}

	// XML を取り、JSON を返す
	@POST @Path("xml/json") @Consumes("application/xml")
		@Produces("application/json")
		public Calc xmlToJson(Calc calc){
		return executeCalc(calc);
	}
}
 見ての通りですが、XMLを取ってXMLを返すメソッド、JSONを取ってXMLを返すメソッド、XMLを取ってJSONを返すメソッド、JSONを取ってJSONを返すメソッドの各実装は、いずれも全く同じです。すなわち、Calcを受け取ってCalcを返しています。
 CalcServlet.javaは次のように変更しました。今回はコントロールの機能に特化しています。このServletでは、queryToXml、xmlToXml、jsonToXmlの3種類のメソッドを呼び出せるようにしています。
package com.yamicha.rs.client;

import javax.xml.bind.*;
import javax.xml.parsers.*;
import javax.servlet.annotation.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.net.*;
import com.yamicha.rs.server.*;

@WebServlet(name="calcservlet" , urlPatterns={"/client/calc/*"})
  public class CalcServlet extends HttpServlet{
  private final static String REST_SERVER =
    "(このプログラムのURL)/restserver/calc/";

  public void doPost(HttpServletRequest request ,
    HttpServletResponse response) throws IOException{
    doGet(request , response);
  }
  public void doGet(HttpServletRequest request ,
    HttpServletResponse response) throws IOException{
    response.setContentType("text/plain");
    PrintWriter out = response.getWriter();

    String path = request.getParameter("path");

    Calc calc = new Calc();
    calc.setValue1(request.getParameter("value1"));
    calc.setValue2(request.getParameter("value2"));
    calc.setOperator(request.getParameter("operator"));

    try{
      HttpURLConnection c = null;
      JAXBContext jc = JAXBContext.newInstance(Calc.class);

      if("query/xml".equals(path)){
        // GET 方式でパラメータを送り、XML を受け取る
        c = (HttpURLConnection)
          new URL(REST_SERVER + path +
          "?value1=" + URLEncoder.encode(calc.getValue1() , "UTF-8") +
          "&value2=" + URLEncoder.encode(calc.getValue2() , "UTF-8") +
          "&operator=" + URLEncoder.encode(calc.getOperator() , "UTF-8"))
          .openConnection();
        c.setRequestMethod("GET");
        c.setDoOutput(true);

        c.connect();
      }else if("xml/xml".equals(path)){
        // XML を送り、XML を受け取る
        c = (HttpURLConnection)
          new URL(REST_SERVER + path).openConnection();
        c.setRequestMethod("POST");
        c.setDoOutput(true);
        c.setRequestProperty("Content-Type" , "application/xml");

        c.connect();

        OutputStream os = c.getOutputStream();

        Marshaller m = jc.createMarshaller();
        m.marshal(calc , os);

        os.close();
      }else if("json/xml".equals(path)){
        // JSON を送り、XML を受け取る
        c = (HttpURLConnection)
          new URL(REST_SERVER + path).openConnection();
        c.setRequestMethod("POST");
        c.setDoOutput(true);
        c.setRequestProperty("Content-Type" , "application/json");

        c.connect();

        OutputStream os = c.getOutputStream();

        PrintWriter pw = new PrintWriter(os);
        pw.print("{"value1" : "" + calc.getValue1() +
          "" , "value2" : "" + calc.getValue2() +
          "" , "operator" : "" + calc.getOperator() +
          ""}");
        pw.close();

        os.close();
      }else{
        throw new Exception("path 引数が正しくありません。");
      }

      InputStream is = c.getInputStream();

      Unmarshaller u = jc.createUnmarshaller();
      Calc result = (Calc)u.unmarshal(is);

      is.close();
      c.disconnect();

      out.println(result.getValue1() + " " + result.getOperator()
	+ " " + result.getValue2() + " = " + result.getAnswer());

      out.close();
    }catch(Exception e){
      throw new IOException(e.toString());
    }
  }
}
 このServletは、calcForm.htmから呼び出します。
<html>
<head></head>
<body>

<form action="./client/calc" method="POST">

計算式:<br />
<input type="text" name="value1" size="10" value="1" /> 
<input type="text" name="operator" size="3" value="+" /> 
<input type="text" name="value2" size="10" value="1" />
<br />
<br />

リクエストを送りたいサービスのパス:<br />
<input type="radio" name="path" value="query/xml"
 checked="checked" />query/xml 
<input type="radio" name="path" value="xml/xml" />xml/xml
<input type="radio" name="path" value="json/xml" />json/xml
<br />
<br />

<input type="submit" value="計算" />
</form>

</body>
</html>
 正しく動作した場合、3つあるラジオボタンのどれを使用しても表示される結果は同じですが、query/xmlであればGET方式を用い、引数の形でデータを送信しますし、xml/xmlならXML形式で、json/xmlならJSON形式でデータを送信します。いずれの場合もXMLが返され、ServletがそれをJAXBで解析、計算結果をテキスト形式として表示します。
 calcAjax.htmは、xmlToJson、jsonToJsonの2種類のメソッドを呼び出します。こちらはServletなどを使用せず、RESTサーバーに直接アクセスしています。
<html>
<head>
<script language="JavaScript"> 
function createHttpRequest(){
	try{
		return new ActiveXObject("Microsoft.XMLHTTP");
	}catch(e){
		return new XMLHttpRequest();
	}
}

var request = null;
function getResult(){
	var path = "";

	for(var i = 0; i < calc.path.length; i++){
		if(calc.path[i].checked){
			path = calc.path[i].value;
			break;
		}
	}

	var value1 = calc.value1.value;
	var value2 = calc.value2.value;
	var operator = calc.operator.value;

	var senddata = "";
	var ctype = "";

	if(path == "json/json"){
		// JSON 形式でデータを送信
		ctype = "application/json";

		senddata = '{"value1":"' + value1 +
			'" , "value2":"' + value2 +
			'" , "operator":"' + operator +
			'"}';
	}else if(path == "xml/json"){
		// XML 形式でデータを送信
		ctype = "application/xml";

		senddata += '<?xml version="1.0"?>';
		senddata += '<calc>';
		senddata += '<value1>' + value1 + '</value1>';
		senddata += '<value2>' + value2 + '</value2>';
		senddata += '<operator>' + operator +
			'</operator>';
		senddata += '</calc>';
	}else{
		return;
	}

	if(request == null)
		request = createHttpRequest();
	else
		request.abort();

	request.onreadystatechange = function(){
		if(request.readyState == 4 && request.status == 200){
			var calc = eval("(" + request.responseText + ")");
			var str = calc.value1 + " " + calc.operator +
				" " + calc.value2 + " = " + calc.answer;
			document.getElementById("result").innerHTML = str;
		}
	};

	request.open("POST" , "./restserver/calc/" + path , true);
	request.setRequestHeader("Content-type" , ctype);
	request.send(senddata);
}
</script>
</head>

<body>

<form name="calc" onsubmit="getResult();return false">

計算式:<br />
<input type="text" name="value1" size="10" value="1" /> 
<input type="text" name="operator" size="3" value="+" /> 
<input type="text" name="value2" size="10" value="1" />
<br />
<br />

サービスのパス:<br />
<input type="radio" name="path" value="json/json"
 checked="checked" />json/json
<input type="radio" name="path" value="xml/json" />xml/json
<br />
<br />

<input type="submit" value="送信" />

<div id="result">(ここに結果が表示されます)</div>
</form>

</body>
</html>
 json/jsonとxml/jsonのどちらをチェックしても、返されるデータはJSON形式ですので、evalでJavaScriptにそれを解釈させるだけで復元が完了します。

 後は次のURLを開き、いずれのチェックを選択した場合でも正しく動作すれば成功です。

(アプリケーションのURL)/calcForm.htm
(アプリケーションのURL)/calcAjax.htm

 いずれの場合も結果は全く同じですが、CalcServlet.javaとcalcAjax.htmの実装の通り、やり取りされているデータ形式はそれぞれ全くの別物です。
カテゴリ [開発魔法][社会問題] [トラックバック 0][コメント 0]

全日本有名人人気投票
2010/04/18(Sun)23:44:24
 今度は民主党が参院選候補として落語家を擁立することが明らかとなりました。民主党は以前にもニュースキャスターを擁立する動きを見せており、それに続くタレント候補となります。その他、自民党や乱立小政党などの他党も有名人を擁立したり、あるいは擁立することを検討、もしくは広告塔に用いるなどしており、参院選には様々な有名人が出馬あるいは登場する可能性が出てきました。
 一体民主党は何を考えているのでしょうか。かつて民主党は「さくらのパパ」なる有名人を擁立したことがありますが、この人は後に賭博が発覚して問題となり、民主党の印象にダメージを与えました。他党の例を出せば、自民党が料理研究家を当選保障で擁立した際には、小選挙区で落選するも比例1位のため復活当選し、その後には「料理番組」を理由に郵政の採決を欠席、批判を浴びています。また、事実上自民党に擁立されて出馬、落選した堀江氏は後に逮捕され、自民党は氏が無所属で出ていた事実を利用し、しっぽ切りに走りました。この通り、有名人を擁立したところで、ろくな結果にならないのは見えています。どうやら民主党は先の教訓から全く何も学んでいなかったようです。
 その上、日本には「世の中を変えなくてはならない」という志を持って勉学に励み、政治家を目指している人も少なからず存在します。客寄せパンダの席を1つ用意するたびに、志ある者の席が1つ減少することを考えれば、タレントを擁立するなどという行為はあまりにバカげており、とても容認できるものではありません。
 ただ、民主党の行動があまりに愚かである点は疑いようもありませんが、これは民主党だけの責任というより、現行の日本政治の責任、ひいては日本国民の責任であることも、指摘しないわけにはいきません。
 2005年の衆院選時、自民党は広告会社スリードの選挙戦略に基づき、具体性を伏せた上で「郵政」のみをひたすら訴え、あらゆる説明責任を意図的に放棄、さらには料理研究家や堀江氏のような有名人を擁立し、話題性によって大量の議席を取得しました。私はこの衆院選の最中、国民は自民党のあまりの侮辱に必ず怒り、その怒りは自民党を揺るがすであろうと考えていましたが、結果は失望に終わりました。
 失望を抱いたのは民主党議員も同じであるらしく、2009年の衆院選でおよそ意味の分からない政策を言い出したのも、2005年の衆院選で消費税増税などの「苦い」政策を掲げたところ、低IQ選挙戦略と有名人擁立を行った自民党に大敗し、まじめに公約を作っても全く無駄であると知らされたため、甘言を言い立てるよりなかったとの事情もあるようです。自分が作った公約が守れずに苦しんでいるのですから、「自業自得」の一言で片付けたくもなりますが、各党が理想論を並べ立てるだけの不健全な選挙がなされる責任の一端は、確かに国民にもあるはずです。
 また、自民党は2005年の衆院選以後にも、タレントの郷ひろみ氏や宮崎県知事の東国原氏を擁立しようとしたり、自分が事実上の解雇にしたはずの文民統制違反者・田母神氏を擁立しようとしたり、「美人すぎる市議」を擁立する動きを見せたりと、姑息な手段を繰り返しています。自民党がこのような擁立を繰り返すため、対抗上民主党も同様の行為に走らなくてはならないのであれば、自民党が悪いともいえますが、もとはといえばそのようなタレントを支持したり、政治家に侮られるような行動ばかり取る国民に問題があるのです。
 2009年の衆院選の際には、新聞コラムなど一部に「国民は前回衆院選のイメージ選挙に懲りた」との見解を表明する者も存在しましたが、実際にはほとんど変化はありません。麻生内閣時に散々世襲議員が批判されたにもかかわらず、逆風の中で小泉進次郎氏があっさり当選した上、同氏の定員50人のツアーに5000人もの応募があったことからも、それが伺えます。世の中、なぜか小泉氏を過大評価する早とちりな人も存在するようですが、有名な元首相・小泉氏の世襲であるがために目立ってはいるものの、就任からの日数を考えれば当然ながら、小泉氏は今のところ答弁を無難にこなす程度の実績しかなく、客観的には特に高く評価できるだけの結果を残してはいません。もし答弁が上手く、人気があるのが良い政治家であるというのなら、麻生氏はその両方を満たしていたはずです。
 さらには、タレント選挙は大政党だけにとどまらず、小政党の間にまで広がってしまう恐れがあります。2005年の衆院選より、自民党はなりふり構わず有名と見た人物を擁立しようとしていますし、民主党もそれに対抗してか、それとも起死回生のためか、今回の参院選では有名人の擁立を進めています。また、小政党も力の弱さをカバーするために話題性が必要であるからと、有名な知事らを広告塔に使おうとするなどしており、今の日本は政策本位の政治が最も必要な状況でありながら、選挙がまたもタレントの人気投票状態になり始めています。二大政党がくだらないタレント選挙を行っており、小政党がそのような選挙に疑問を呈しているならまだしも、これでは小政党も民主・自民と何ら変わるところがありません。
 また、国民の上記のような態度は、人格も政策もおよそ政治家の器に程遠いながら、なぜか人気だけはある舛添氏のような人物をのさばらせる原因ともなっています。無賃残業合法化にあれほど大反対し、政治家の些細な問題発言や空約束にあれほど荒れ狂う世論が、無賃残業合法化を強力に推進するばかりか、これを「家庭だんらん法案」と言い換えれば通ると発言するほど国民を愚弄し、各種暴言や空約束を行っている舛添氏を支持するのは、いかに少なくない国民が政策や人格を見ようとせず、「人気」を見ているかを体現しています。
 いずれにせよ、国民の態度がタレント選挙を生み出しており、タレント選挙がろくな結果を生まないことだけは、これまでの例からもはっきりしています。日本が座礁域の真っ只中にある状況で、果たしてタレントの人気投票で船長を決めてしまうのが正しいやり方なのか、十分に考える必要があります。
 政党の側も同様です。もし民主党が本気で今後の政権運営を行う意思を持っており、国民に理解と支援を求めたいのであれば、同党は今からでもタレントや落語家の擁立を撤回すべきです。小沢代表以後の変質を正し、タレントを擁立するような姑息な真似もやめれば、それが自動的に自民党との差別化にもつながりますし、分かっている人からは支持が得られるに違いありません。
 自民党の側も、例えば小泉進次郎氏を広告塔として利用すれば、確かに短期的にはある程度の人気が得られるでしょう。しかし、同党がこのような世襲を容認している限り、同党が「保守政党の経済政策」として「機会の平等」を唱えても、支持が得られるわけがありません。まして、仮に小泉氏がそれを唱えるようなことがあれば、説得力はゼロに等しいと言わざるを得ません。また、2005年の選挙では政策の長短をしっかり説明せず、低IQ戦略及びタレント選挙に持ち込んだため、案の定襲ってきた「存在しないはずの」副作用によって支持を失い、これが後の敗北の土壌となりました。これの二の舞を演じるつもりがなければ、いい加減にこのような姑息な方法を用いるのはやめるべきです。

 ただ単に結果を返すだけでもServletより簡単なJAX-RSですが、単純にパスやパラメータを受け取って文字列を返すだけでは、せいぜい「簡略化されたServlet」でしかありません。RESTを標榜するからには、XMLによるデータのやり取りも必要となるでしょう。
 JavaによるXMLといえば、今のところSAX、DOM、StAX、JAXBが有名どころです。しかし、前者3つはそれこそ自分でXMLを解析していかなくてはならず、これではServletで処理するのと全く変わりません。そもそもパース処理がコードのほとんどを占める状況にもなりかねず、開発が大変面倒になります。ここはWebServiceでも用いたJAXBを使用するのがよさそうです。
 そして実際、JAX-RSはXMLのオブジェクト化及びオブジェクトのXML化を自動的に行う仕組みを提供しています(マニュアルの記述によれば、String、byte[]、JAXB、JSONなど、様々な形式を普通に読み書きできるようになっているとのこと)。しかもその使い方といえば、引数や返り値に任意の型を用いるだけであるというのです。これが本当であれば、何とも簡単です。
 以下、簡単な計算機を実装しています。RESTの処理を行うクラスに加え、JAXBで変換を行う@XmlRootElementクラスが1つ、それにXMLリクエストを送受信する動作テスト用Servletが1つで、クラスは3つとなりました。
/WEB-INF
 /classes
  /com
   /yamicha
    /rs
     /server
      @XmlRootElement Calc.java
      @Path CalcService.java
     /client
      @WebServlet CalcServlet.java
 web.xml
 アノテーションのおかげで役割分担が明白です。
 web.xmlは前回と全く同様です。Servletは@WebServletで必要な情報を指定していますので、ここでは特に何も書いていません。
<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app>
  <display-name>JAX-RS Servlet</display-name>
  <description>JAX-RS Servlet</description>

  <servlet>
    <servlet-name>jax-rs</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
      <param-name>com.sun.jersey.config.property.packages</param-name>
      <param-value>com.yamicha.rs.server</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
    <servlet-name>jax-rs</servlet-name>
    <url-pattern>/restserver/*</url-pattern>
  </servlet-mapping>
</web-app>
 Calc.javaはデータ保持用のクラスだけに、中身は完全にJavaBeanです。左辺値、右辺値、演算子、答えの4つのデータを保持できるようにしています。
package com.yamicha.rs.server;

import javax.xml.bind.annotation.*;

@XmlRootElement(name="calc") public class Calc{
	private String value1;
	private String value2;
	private String operator;
	private String answer;

	public Calc(){
	}

	@XmlElement(name="value1") public String getValue1(){
		return value1;
	}
	@XmlElement(name="value2") public String getValue2(){
		return value2;
	}
	@XmlElement(name="operator") public String getOperator(){
		return operator;
	}
	@XmlElement(name="answer") public String getAnswer(){
		return answer;
	}

	public void setValue1(String s){
		value1 = s;
	}
	public void setValue2(String s){
		value2 = s;
	}
	public void setOperator(String s){
		operator = s;
	}
	public void setAnswer(String s){
		answer = s;
	}
}
 CalcService.javaはこれを解析して処理を行うクラスなのですが、XMLとの相互変換はJerseyが勝手にやってくれるため、かなりシンプルな記述で済んでいます。同じJAXBでも、WebServiceを書く際にはそれなりに苦労した記憶がありますが、こちらは全く難しい要素がありませんでした。
package com.yamicha.rs.server;

import javax.ws.rs.*;
import javax.ws.rs.core.*;

@Path("calc") public class CalcService{
	public CalcService(){
	}

	// 動作テスト用
	// ブラウザからでも結果 XML の取得が可能
	@GET @Path("query") @Produces("application/xml")
		public Calc queryCalc(
		@QueryParam("value1") String v1 ,
		@QueryParam("operator") String op ,
		@QueryParam("value2") String v2){
		Calc calc = new Calc();
		calc.setValue1(v1);
		calc.setValue2(v2);
		calc.setOperator(op);

		return jaxbCalc(calc);
	}

	// XML を受け取り、計算結果を記入した XML を返す
	@POST @Path("jaxb") @Produces("application/xml")
		public Calc jaxbCalc(Calc calc){
		try{
			// プロパティはいずれも String 型であるため
			// double として扱っても文字列の連結処理をしても
			// 構わないのだが、今回は int として計算している
			int answer = 0;

			int v1 = Integer.parseInt(calc.getValue1());
			int v2 = Integer.parseInt(calc.getValue2());
			String operator = calc.getOperator();

			// 使用できる演算子として
			// とりあえず + , - , * , / , ** を実装
			if("+".equals(operator))
				answer = v1 + v2;
			else if("-".equals(operator))
				answer = v1 - v2;
			else if("*".equals(operator))
				answer = v1 * v2;
			else if("/".equals(operator))
				answer = v1 / v2;
			else if("**".equals(operator))
				answer = (int)Math.pow(v1 , v2);
			else
				return calc;

			calc.setAnswer(String.valueOf(answer));
		}catch(NumberFormatException e){
		}

		return calc;
	}
}
 今回は「POSTでXMLを受け取り、計算結果を格納したXMLを返す」メソッドも実装しているため、クライアント側となるServletも実装しました。名前はCalcServlet.javaとしました。Jerseyにはテスト用の機能も付属しているらしいのですが、どうもJersey固有の機能らしいため、ここではHttpURLConnectionでごく普通に処理を行っています。
package com.yamicha.rs.client;

import javax.xml.bind.*;
import javax.xml.parsers.*;
import javax.servlet.annotation.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.net.*;
import com.yamicha.rs.server.*;

@WebServlet(name="calcservlet" , urlPatterns={"/client/calc/*"})
  public class CalcServlet extends HttpServlet{
  private final static String REST_SERVER = 
    "(このアプリケーションの URL)/restserver/calc/";

  public void doPost(HttpServletRequest request ,
    HttpServletResponse response) throws IOException{
    doGet(request , response);
  }
  public void doGet(HttpServletRequest request ,
    HttpServletResponse response) throws IOException{

    if(request.getParameter("operator") == null){
      // 計算(右辺値・左辺値・演算子)入力フォーム
      response.setContentType("text/html;charset=Shift_JIS");
      PrintWriter out = response.getWriter();

      out.println("<html><head></head><body>");
      out.println("<form method="POST">");
      out.println("<input type="text" name="value1" size="10" value="1" /> ");
      out.println("<input type="text" name="operator" size="3" value="+" /> ");
      out.println("<input type="text" name="value2" size="10" value="1" />");
      out.println("<input type="submit" value="計算" />");
      out.println("</form>");
      out.println("</body></html>");
    }else{
      // 入力されたデータを XML 化して送り、計算結果を受け取って表示
      try{
        response.setContentType("text/plain");
        PrintWriter out = response.getWriter();

        // Calc を作成
        Calc calc = new Calc();
        calc.setValue1(request.getParameter("value1"));
        calc.setValue2(request.getParameter("value2"));
        calc.setOperator(request.getParameter("operator"));

        // JAXBContext を作成
        JAXBContext jc = JAXBContext.newInstance(Calc.class);

        // HttpURLConnection を作成
        // Content-type は application/xml
        // データを POST するので、setDoOutput(true) が必要
        HttpURLConnection c = (HttpURLConnection)
          new URL(REST_SERVER + "jaxb").openConnection();
        c.setRequestMethod("POST");
        c.setDoOutput(true);
        c.setRequestProperty("Content-Type" , "application/xml");

        c.connect();

        // XML を POST する処理
        OutputStream os = c.getOutputStream();

        // Calc を XML に変換してストリームに書き込む
        Marshaller m = jc.createMarshaller();
        m.marshal(calc , os);

        os.close();

        // 結果を受け取る
        InputStream is = c.getInputStream();

        // ストリームから XML を読み取り、Calc に変換
        Unmarshaller u = jc.createUnmarshaller();
        Calc result = (Calc)u.unmarshal(is);

        is.close();
        c.disconnect();

        // 結果を表示
        out.println(result.getValue1() + " " + result.getOperator() + " " +
          result.getValue2() + " = " + result.getAnswer());

        out.close();
      }catch(IOException e){
        throw e;
      }catch(Exception e){
        throw new IOException(e.toString());
      }
    }
  }
}
 無論、これは別に無理にJavaで書く必要はなく、PerlやPHPなどのスクリプト言語からリクエストを送ったり、あるいは通常のクライアントサイドのアプリケーションからリクエストを送るなどしても、XMLさえ正しく作成及び解析できているのであれば、同様に動作するはずです。
 後は実際に実行してみるだけです。せっかくCalcService.javaにGETの場合の処理も書いたことですし、どのようなXMLが生成されるかをチェックしておくのも面白そうですので、ひとまずブラウザから開くことにしました。

(アプリケーションのURL)/restserver/calc/query?value1=左辺値&operator=演算子&value2=右辺値

 今回の実装では、左辺値と右辺値はintの範囲の整数である必要があります。また、演算子には+、-、*、/、**が使用できます。ただ、JAX-RSを使用するような開発者にいちいち断る必要はなさそうですが、URLは当然エンコードしなくてはなりません。+記号は%2B、-は%2D、*は%2A、/は%2Fです。
 実際に以下のURLを開いてみたところ、

(アプリケーションのURL)/restserver/calc/query?value1=5&operator=%2D&value2=3

 次のような結果が得られました。
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> 
<calc>
  <answer>2</answer> 
  <operator>-</operator> 
  <value1>5</value1> 
  <value2>3</value2> 
</calc>
 次はServletですが、こちらは@WebServletアノテーションの記述の通り、以下のURLにマッピングされています。

(アプリケーションのURL)/client/calc

 フォームに必要事項を入力し、正しく計算が行えれば成功です。
カテゴリ [開発魔法][社会問題] [トラックバック 0][コメント 0]

たちどまる日本
2010/04/09(Fri)22:50:48
 与謝野氏や平沼氏などを中心として、新党「たちあがれ日本」が発足となりました。届出上の代表は平沼氏ですが、与謝野氏は同格の共同代表のポストに就任し、参加者は5名で政党要件も満たしています。参院選においては、比例を中心に10名以上の擁立を検討しているようです。
 ところが、新党が標的としている現政権党からの批判ならまだしも、自民党総裁の谷垣氏からも「与謝野氏は小選挙区敗北での復活当選であるが、それなのに離党するのはおかしい」と評されるなど、自民党内にも批判的な見方が多く存在する上、構成人員がベテラン議員ばかり(平均年齢70歳近く)であることを理由として、「シルバー新党」「立ち枯れ日本」と揶揄されたりと、国民や政党の間で支持を集められるかは不透明な情勢です。
 私は麻生政権下の大混迷の時期より、与謝野氏の手腕に一定の期待を持っており、麻生氏失脚後は与謝野氏が自民党を立て直して復帰させ、日本に二大政党制が定着することを期待していましたが、どうやら私は与謝野氏を買いかぶりすぎていたようです。かつて谷垣氏に期待した際には、「和魂党」や田母神氏擁立問題、また理念なき欠席戦術などで大変失望させられましたが、与謝野氏の器も谷垣氏と同じかそれ以下であると評するよりありません。
 与謝野氏の理念の乏しさについては、以前に指摘している通りです。すなわち、与謝野氏は「(鳩山内閣で)普段なら内閣が倒れるような事件が起きているにもかかわらず、自民党の評価が高まっていないことには、深い反省、思いを抱かないといけない」と発言し、谷垣体制のやり方のまずさを批判していますが、相手の過失をあげつらったところで自分の支持が回復するわけではないのは当然です。もし自民党が支持を取り戻したいのであれば、他人の過失に付け込むのではなく、自分の悪い点を改善するよう努め、支持を得られない原因を解消しなくてはなりません。上記の発言から察するに、与謝野氏はそれを自覚できていないらしいため、私は与謝野氏の新党構想に強い懸念を抱いていました。
 そして今回、その懸念は現実のものとなりました。与謝野氏は自身の勉強会の会合で、新党について「自民党を分裂させるためではない。徹底的な反民主党を貫く。捨て石になったつもりで頑張る」と発言していますが、まさに「新党」が新党として意味を成さないことを証明するかのような発言です。
 通常、「政党」は何らかの政策を実現させるための組織ですし、そうであるからこそ選挙では政策を掲げ、その政策に賛同した国民の支持により国会に議席を有し、国の政策決定に参加する仕組みとなっています。したがって、仮に新党が掲げた政策に自民党が反発し、民主党は賛同しているような場合、相手が民主党だからという理由で政策実現を拒否するようなことがあれば、まず道理に合いません。
 しかし、与謝野氏は新党について「反民主党を貫く」と発言しており、完全に手段と目的が逆転しています。どうしても実現しなくてはならない理念があり、自民党の理念では実現できないから党を去るというならまだしも、党の目的が「反民主党」とは、理念や政策以前にあまりにも子どもじみており、あきれて物も言えません。これが本当に「ベテラン」と呼ばれる議員の行動でしょうか。
 このような子どもだましの新党が、自民党にも民主党にも愛想をつかした人を取り込めると本気で考えているなら、与謝野氏や平沼氏はあまりに国民を愚弄しています。ここまで独自の理念を持たない政党となれば、おそらく当面は自民党の衛星政党として機能することになるはずですが、それでいて自民党に失望した人の受け皿になろうとは、自民党に今までの責任をすべて押し付け、自分はおいしいところだけを取ろうとしていると批判されても仕方がありません。
 つくづく、ベテランと呼ばれる人であっても、また手腕に期待できそうな人であっても、実像は分からないものです。当初は与謝野氏に期待していた私も、今となっては「このような理念も正当性もない人間が自民党総裁にならなくて良かった」の一言しかありません。自民党の側も、与謝野氏や平沼氏の行動と連鎖反応に戦々恐々とするよりは、むしろ自分で処置するまでもなく膿が排出されたと好意的に解釈し、党再生に弾みをつけた方が建設的です。
 また、これは平沼・与謝野両氏の新党に限りませんが、私は最近の政治状況に強い危機感を覚えています。小泉氏の次男がもてはやされることに始まり、自民党は自らが事実上の退職処分にしたはずの田母神氏を擁立しようと試みたり、「美人すぎる市議」を立てようとしてみたり、その他様々なタレントや有名人を起用しようとしています。対する民主党も、有名なキャスターを擁立しようとするなど、程度の差こそあれ、やっていることは自民党とほとんど変わりません。さらには首長連合などの小規模集団も、その弱さを有名人の話題性に求めようとしており、各党が大小競い合って人気投票に持ち込もうとしているような状態です。これでは政権交代の定着どころか、時計の針が郵政解散時まで逆戻りしてしまいます。この混迷の状況下で、タレントの人気投票によって国の行方が決まるようなことが許されるのでしょうか。
 そして何より気がかりなのは、舛添氏のように人気だけが先行し、思想や理念が伴わない人物の動向です。これまでの発言や主張内容、主張政策からすれば、明らかにそれにふさわしい人物でないのは明白でありながら、先の世論調査では首相にふさわしい人の1位に舛添氏が挙げられており、どうしても懸念を抱かないわけにはいきません。平沼・与謝野新党がまるで理念の存在しない、ただ自民党の看板を外しただけの政党である以上、ここが第三極として受け皿になる可能性は非常に低いだけに、舛添氏が第三極として名乗りを上げた場合の影響は相当大きくなると予想されるため、強い警戒が必要です。

 Java EE 6には「JAX-RS」なる新たな機能が導入されています。これはJava EEでRESTを実装するためのもので、Webサービスを実装するJAX-WSとは近い関係にあります。APIリファレンスを読む限り、アノテーションがかなり多用されており、EJB 3.0以降のスタイルで容易に開発できるであろうことが想像できます。
 ところで、「REST」とは一体何なのでしょうか。定義は色々考えられますが、厳密な答えを出すのは困難です。なぜなら、当初は意味が厳密に決まっていたものの、途中で意味が拡大解釈されて収拾がつかなくなり、最終的に意味があいまいになってしまった、いわゆる「バズワード」の典型であるためです。
 Wikipediaを開いてみると、以下のように記述してあります。
RESTは、初めはアーキテクチャの原則と制約の集まりを指していたが、次第に、XMLやHTTPを使った簡易なウェブベースのインターフェイスのうち、WebサービスのSOAPプロトコルのような MEP(Message Exchange Pattern; SOAPノード相互のメッセージ交換のパターンを確立するための雛型)ベースの特別な抽象化をしないもののことを、大まかに意味する用語として使われるようになった。RESTは次に述べるように2つのやや異なる意味で使われている。
  • FieldingのRESTアーキテクチャスタイルの原則に合わせたWebサービスシステム。
  • RPCスタイルに合わせた簡易な XML+HTTP インターフェイスを採用したシステム(SOAPは使わない) 。
 すなわち、困ったことに定義が複数存在し、しかも定義の境界があいまいである(これはRESTだが、これはRESTではない、と定めるのが難しい)というのです。
 ひとまず、Java EE 6では主に以下のような操作が提供されているようです。
  • GET、POST、PUT、DELETEなど、任意のメソッドに応じた処理の呼び出し。
  • 拡張パス及びクエリに応じた処理の呼び出し。
  • 送信データを任意の形式(クエリ文字列、単純な文字列、XML、JSONなど)で受け取り、また返却する処理。
  • その他、クッキー周りなど付加的な処理。
 念のために書いておくと、メソッドのうちGETとPOSTは有名ですが、もともとGETはデータ取得、POSTはデータの登録、PUTはデータの更新、DELETEはデータの削除を意図して作られたものです。
 今回はとりあえず、「特定のURLにGETでアクセスすると、任意の結果を文字列で返す」だけのRESTを書いてみます。実際にはPOSTでもPUTでもDELETEでも、またXMLでもJSONでも何でも受け付けてくれますが、もともとRESTは利用者のブラウザと対話するというより、あるサービスが別のサービスに対する操作を行う(例えば、あるブログは関連する書籍を表示する機能を有している。ユーザーがブログにアクセスすると、ブログはRESTを使って書籍検索システムにアクセスし、検索結果を取得する。それをユーザーの画面に表示する)側面が強いため、少し複雑なものになるとXMLなどを送信したりしなくてはならず、単純にブラウザを使ってテストするのが難しくなり、アクセスする側のプログラムもセットで書く必要が出てきて、本来関係のないコードが増えてしまうためです。
 まずは単純明快に、引数も何も受け取らず、ただ単にメッセージを返すだけのものを作成してみます。いわゆるHello Worldです。
 今回用意したのは、単純明快に以下の2つのファイルのみです。
/WEB-INF
 /classes
  /com
   /yamicha
    /rs
     /server
      Hello.java
 web.xml
 上記2つのファイルを用意するだけで、まがりなりにもJAX-RSを利用できるのですから、その簡単さは容易に想像できます。この技術がもしEJB 3.x以前に発表されていたら、おそらく地獄を見たでしょう。
 まずはweb.xmlですが、これはほとんど「お約束」でしょう。事実、以下のXMLもほぼSunのサンプルの丸写しです。
<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app>
  <display-name>JAX-RS Servlet</display-name>
  <description>JAX-RS Servlet</description>

  <servlet>
    <servlet-name>jax-rs</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
      <param-name>com.sun.jersey.config.property.packages</param-name>
      <param-value>com.yamicha.rs.server</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
    <servlet-name>jax-rs</servlet-name>
    <url-pattern>/restserver/*</url-pattern>
  </servlet-mapping>
</web-app>
 やや重要なのがinit-paramで、ここで処理の対象とするパッケージ名を指定しなくてはならないようです。この場合では、com.yamicha.rs.serverパッケージが対象となります。
 また、Sunのサンプルによれば、アプリケーションのクラスを指定する記述として
<init-param>
  <param-name>javax.ws.rs.Application</param-name>
  <param-value>com.example.ClassName</param-value>
</init-param>
 なるものも存在するようです。むしろ、前者のパラメータ名がcom.sun.jersey.config.property.packagesなのに比べ、後者はjavax.ws.rs.Applicationですから、後者の方が標準的な方法であって、前者はJerseyの独自拡張と考えた方が正しいかもしれません。
 servlet-mappingのurl-patternとしては、今回は/restserver/*を用いましたが、当然ながら好きなように記述して構いません。
 Hello.javaは以下の通りです。
package com.yamicha.rs.server;

import javax.ws.rs.*;
import javax.ws.rs.core.*;

@Path("hello") public class Hello{
	@GET @Path("message") public String sayHello(){
		return "Hello JAX-RS!";
	}
}
 何とごく普通のServletより簡単です。むしろ、これで本当に動くのかが不安になってきます。
 後はこれをデプロイし、ブラウザから次のURLにアクセスするだけです。

(このアプリケーションのURL)/restserver/hello/message

 restserverはweb.xmlで定めたurl-patternに基づくもので、helloはクラスの@Pathアノテーションに基づきます。また、messageはメソッドの@Pathアノテーションに基づきます。

 いくら簡単なのが良いこととはいえ、これだけではあまりにも面白くありませんので、ついでに「拡張パスとして文字列を受け取り、それをそのまま表示する実装」と「パラメータとしてv1とv2を受け取り、足し算して返す実装」も追加してみるとしましょう。
package com.yamicha.rs.server;

import javax.ws.rs.*;
import javax.ws.rs.core.*;

@Path("hello") public class Hello{
	public Hello(){
	}

	@GET @Path("message") public String sayHello(){
		return "Hello JAX-RS!";
	}

	@GET @Path("say/{msg}") public String sayMessage(
		@PathParam("msg") String msg){
		return msg;
	}
	@GET @Path("calc") public String calc(
		@QueryParam("v1") String v1 , @QueryParam("v2") String v2){
		try{
			return String.valueOf(
				Integer.parseInt(v1) + Integer.parseInt(v2));
		}catch(NumberFormatException e){
			return "正しい数字ではありません。";
		}
	}
}
 非常に簡単な上、見た目からして意味も明白です。
 後は以下のURLにアクセスするだけです。

(文字列表示)
(アプリケーションのURL)/restserver/hello/say/Hello

(計算)
(アプリケーションのURL)/rs/restserver/hello/calc?v1=16&v2=32

 アノテーションの導入で大きく変わったJava EEですが、いずれもせいぜい「XMLの代わりにアノテーションを使えるようにして、XMLを削減する」程度の消極的なものが多い印象でした(もともとXML前提の仕様がアノテーションでも書けるようになったものであるので当然ですが)。しかし、JAX-RSでようやくそのような消極的なアノテーションから、「XMLなどの記述を不要にするとともに、コードの意味を分かりやすくする」という積極的なアノテーションに転じてきたようです。
カテゴリ [開発魔法][社会問題] [トラックバック 0][コメント 0]

代理十票
2010/04/04(Sun)08:25:19
 参院自民党の若林氏が、何と隣席の青木氏の投票ボタンを本人退席中に勝手に操作したことが発覚し、大問題になっています。民主党は若林氏への懲罰動議を提出しましたが、自民党が若林氏に圧力をかけたこともあってか、氏は自ら議員辞職願を提出して議員辞職、謝罪を行いました。
 このようなことがまさか本当に発生するとは、驚愕を禁じ得ないとしか言いようがありません。しかも、例えば杉村氏のような不見識な「チルドレン」がそれを行ったのならともかく、「良識の府」として被選挙権が衆院より厳しく設定されている参院において、しかも75歳のベテランである若林氏がこのような大失態を犯したのですから、なおさら唖然とさせられます。
 本件に対する反応を見てみると、さすがに社説などでは若林氏を擁護するものは見当たりませんが、中にはなぜか民主党などへの責任転嫁を図ろうとしている内容のものもあり、大変理解に苦しみます。また、個人レベルでは「なぜここまで大騒ぎしなくてはならないのか」といった意見もごく一部に存在しますが、いくら個人の意見であるとはいえ、あまりにも不見識過ぎるとしか評しようがありません。
 本件について、民主党の姿勢を批判したり、あるいは党議拘束について批判したりする意見に関しては、それはそれとして意義のあるものではありますが、その種の議論は本件とは別の議論として行うべきです。なぜなら、仮に民主党の姿勢が評価できるものではなかったり、党議拘束が矛盾のある制度であったとしても、勝手に他の議員の投票を決定する行為の罪はいささかも軽減されず、何の言い訳にもならないためです。氏のような行動は、党議拘束が存在しようがしまいが、民主党がいかなる状況であろうが、等しく重大行為として評価されなくてはならず、民主党がどうこうといったことは何の免罪符にもならない、全く無関係の事柄です。
 ましてや、本件を大した問題でないと評する人間に対しては、唖然とする以外にありません。もし本件のような問題がほとんど、あるいは全く問題視されずに終わってしまえば、他の幾人もの議員が勝手に他人の投票権を行使したり、あるいは欠席・退席する議員が他の議員に代理投票を頼んだりといった行為が日常的に横行し、日本の議会制度が大混乱に陥り、根底から崩壊してしまう状況にもなりかねません。だからこそ、本件における若林氏の行為が最大限の非難を浴びるのは当然ですし、議員辞職でもあがないきれないほど重い問題なのです。
 一方、自民党の「タガの緩み」に原因を求める声もありますが、本件はもはや「タガの緩み」以前の問題です。本件について自民党に責任がないかといえば、全くのゼロであるとまでは言い切れませんが、これまでにも自民党内で同様の行為が横行していたならまだしも、そうでないなら基本的には議員個人の資質や自覚の問題です。タガが緩もうが緩むまいが、他人の分の投票を勝手に行ってはいけない程度のことは、数百分の一もの投票権を行使できる国会議員どころか、一億分の一程度の投票権しか行使できない一般国民でも知っています。
 また、自民党に関しては、衆院選敗北後の首相指名選挙では若林氏に投票する方針として氏を立てておきながら、本件が問題になると「トカゲの尻尾切り」のごとく若林氏を見限って批判に回り、議員辞職に追い込んだ同党の姿勢を批判する意見も一部に存在するようです。
 確かに、党内の都合でこのような不見識な人物を担ぎ上げ、可決はされないにせよ首相にまで指名した点は、自民党にも問題があります。安部氏や麻生氏を担いで失敗した図式そのままで、しかも自民党はその後も田母神氏を立てようとしてみたり、「美人過ぎる市議」なるもので話題づくりに励んだりと、全く反省がありません。自民党に対してそのようなやり方への反省を求めるのは、極めて妥当な意見でしょう。
 しかし、問題発覚後の自民党の厳しい対応は、決して非難されるべきものではありません。本件において自民党が若林氏をかばったのであれば、同党が代理投票行為を「取るに足らない問題」と評価したことになり、そちらの方が大問題であるためです。この問題は議員辞職でも足りないほど重いものですから、もし自民党がその肩を持っていたらと考えるとぞっとしますし、当然ながら許されざる行為です。
 それにしても不思議で仕方ないのが、本件が「若林氏の長男の出馬に影響を与えるかもしれない」という報道です。小泉氏の次男といい、自民党はいつまで時代遅れの世襲行為を繰り返せば気が済むのでしょうか。自民党は「民主党政権は社会主義」などとえらそうなことを言ったりしていますが、元首相の子が世襲し、首相に指名しようとした人物の子まで世襲する以上、少なくとも自民党に「機会の平等」を唱える権利はありません。また、世襲は世襲でも「子に政治家としての実力があり、親がたまたま議員であった」場合の世襲にまで文句をつけるつもりはありませんが、それなら親の議員としての失態がなぜ子に関係するのでしょうか。親の議員としての悪評が子の出馬や選挙に影響するならば、親の知名度や評判もまた子に影響することになりますので、これは世襲者のスタートラインが非世襲者と明らかに異なるという裏づけになります。いずれにせよ大変意味不明で、全くわけが分かりません。
 本件は若林氏というあまりにも非常識な議員が起こした問題であり、しかも自民党は氏をかばっているわけでもなく、その責任の多くを自民党に求めるのには無理があります。しかし、代理投票の問題についてはともかく、これほどまでに非常識な人間を首相にまで指名したこと、また未だに平然と世襲を行っている事実が知れ渡ったことにより、自民党の責任が問われたり、評価を落とすのは仕方のないところでしょう。

 ここまででJSF 2.0のcompositeタグの大部分を使用してみましたが、まだactionSourceやvalueHolderといったものが残っています。何やら少々分かりづらそうなタグですが、ひとまず使用してみなくてはなりません。
 JSF 2.0のAPIドキュメントは非常に不親切で、タグの説明を見ただけでは何が何だか分からない場合が大多数であるため、特に初見のタグを使う場合は開発効率も非常に悪くなりがちなのですが、これらについては例外的にそれなりに親切なサンプルが付加されており、概要をつかむことができます。
 actionSourceのサンプルでは、呼び出し側よりf:actionListenerが渡されており、f:actionListenerとセットで使用できるものであることが読み取れます。f:actionListenerはその名の通りActionListenerを用いるタグですから、actionSourceはリスナにかかわる操作が行えるものであると容易に理解できます。
 valueHolderはf:converterとセットで使用されていますが、実際にはconverterの他にvalidator系統も使用できます。このタグを用いれば、以前に行ったようなスマートでないバリデータの渡し方は回避できそうです。
 以下は、これらのタグを用いた検索プログラム(ただし検索の動作は未実装)のサンプルです。
/resources
 /comp
  searchForm.xhtml
/WEB-INF
 /classes
  /com
   /yamicha
    /custom
     SearchBean.java
     SearchListener.java
     TextValidator.java
 web.xml
customSearchForm.xhtml
searchResult.xhtml
 SearchListenerはActionListenerを実装したクラスで、f:actionListenerで用います。TextValidatorはクラスバリデータで、こちらはf:validatorで使用しています。
 web.xmlは例によって前回と同様です。
<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app>
  <context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Development</param-value>
  </context-param>

  <display-name>JSF 2.0 Custom Component Servlet</display-name>
  <description>JSF 2.0 Custom Component Servlet</description>

  <servlet>
    <servlet-name>jsf20custom</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>jsf20custom</servlet-name>
    <url-pattern>*.jsf</url-pattern>
  </servlet-mapping>
</web-app>
 SearchBean.javaはいくつかのデータを保持する他、ActionListener実装クラスのインスタンスを保持するbindingA及びbindingBプロパティ、同じくValidatorの実装クラスのインスタンスを返すasciiValidatorプロパティを用意しています。
package com.yamicha.custom;

import javax.ejb.*;
import javax.annotation.*;
import javax.faces.validator.ValidatorException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.application.FacesMessage;
import javax.faces.component.html.HtmlInputText;
import javax.faces.bean.*;
import javax.faces.event.*;
import java.util.*;

@ManagedBean @RequestScoped public class SearchBean
	implements java.io.Serializable{
	private String word;
	private String type;
	private SearchListener bindingA;
	private SearchListener bindingB;

	public SearchBean(){
		bindingA = new SearchListener("Binding A");
		bindingB = new SearchListener("Binding B");
	}

	public String getWord(){
		return word;
	}
	public String getType(){
		return type;
	}

	public SearchListener getBindingA(){
		return bindingA;
	}
	public SearchListener getBindingB(){
		return bindingB;
	}

	public void setWord(String w){
		word = w;
	}
	public void setType(String t){
		type = t;
	}

	public void setBindingA(SearchListener s){
		bindingA = s;
	}
	public void setBindingB(SearchListener s){
		bindingB = s;
	}

	public TextValidator getAsciiValidator(){
		return new TextValidator((char)0x0 , (char)0x7F);
	}
}
 SearchListener.javaには、検索ボタンが押された際の動作を記述しています。
package com.yamicha.custom;

import javax.ejb.*;
import javax.annotation.*;
import javax.faces.context.ExternalContext;
import javax.faces.component.UIComponent;
import javax.faces.component.ValueHolder;
import javax.faces.context.FacesContext;
import javax.faces.bean.*;
import javax.faces.event.*;
import java.util.*;

public class SearchListener implements ActionListener{
	private String type;

	public SearchListener(){
		this("Default");
	}
	public SearchListener(String t){
		type = t;
	}

	public void processAction(ActionEvent event)
		throws AbortProcessingException{
		ValueHolder word = (ValueHolder)
			event.getComponent().findComponent("word");
		ExternalContext ec = FacesContext.
			getCurrentInstance().getExternalContext();
		Map<String , Object> request = ec.getRequestMap();

		if(word != null){
			String w = (String)word.getValue();
			if(!w.isEmpty()){
				SearchBean sb = (SearchBean)
					request.get("searchBean");
				if(sb == null)
					sb = new SearchBean();

				sb.setType(type);
				sb.setWord(w);

				request.put("searchBean" , sb);

				try{
					ec.dispatch("searchResult.jsf");
				}catch(java.io.IOException e){
				}
			}
		}
	}
}
 processActionの呼び出しがあると、まずfindComponent("word")で"word"というidを持つコンポーネント(xhtml内部で記述)を取得、それが空でない場合にはSearchBeanのwordプロパティにそれを書き込み、typeプロパティにはSearchListenerが保持するtype文字列を書き込みます。さらにsearchResult.jsfにディスパッチし、結果表示画面を表示するようにします。一方、wordが空の場合には何も行いません。
 TextValidator.javaは単純なバリデータの実装で、単に「文字列の中に指定範囲外のものが見つかったらValidatorExceptionを投げる」だけのものです。
package com.yamicha.custom;

import javax.faces.validator.*;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.application.FacesMessage;
import javax.faces.bean.*;
import javax.faces.event.*;
import java.util.*;

public class TextValidator implements Validator{
	char min;
	char max;

	public TextValidator(char min , char max){
		this.min = min;
		this.max = max;
	}

	public void validate(FacesContext context ,  UIComponent component ,
		Object object) throws ValidatorException{
		String str = (String)object;

		for(int i = 0; i < str.length(); i++){
			if(str.charAt(i) < min || str.charAt(i) > max){
				throw new ValidatorException(
					new FacesMessage(
"入力された文字列の中に、制限の範囲外の文字があります。"));
			}
		}
	}
}
 actionSource及びvalueHolderを使用している、肝心のsearchForm.xhtmlは次の通りです。
<?xml version="1.0" encoding="Shift_JIS" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:c="http://java.sun.com/jsp/jstl/core"
  xmlns:composite="http://java.sun.com/jsf/composite">

  <composite:interface>
    <composite:attribute name="size" />
    <composite:attribute name="buttonLabel" default="Search" />
    <composite:valueHolder name="word" />
    <composite:actionSource name="searchEvent" />
  </composite:interface>

  <composite:implementation>
    <h:inputText id="word" size="#{cc.attrs.size}" />
    <h:commandButton id="searchEvent" value="#{cc.attrs.buttonLabel}" />
  </composite:implementation>
</html>
 これを使用しているのがcustomSearchForm.xhtmlです。
<?xml version="1.0" encoding="Shift_JIS" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:c="http://java.sun.com/jsp/jstl/core"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:cc="http://java.sun.com/jsf/composite/comp">

<h:head>
  <title>JSF 2.0 Custom Component</title>
</h:head>

<h:body>
  <h:form>
    <b>サンプル検索フォーム(type)</b><br />
    <cc:searchForm buttonLabel="検索(type)">
      <f:actionListener for="searchEvent"
        type="com.yamicha.custom.SearchListener" />
    </cc:searchForm>
  </h:form>

  <!-- テキストボックスに入力がなければエラー -->
  <h:form>
    <b>サンプル検索フォーム(type/validateRequired)</b><br />
    <cc:searchForm buttonLabel="検索(type/validateRequired)">
      <f:actionListener for="searchEvent"
        type="com.yamicha.custom.SearchListener" />
      <f:validateRequired for="word" />
    </cc:searchForm>
  </h:form>

  <!-- 0x00 から 0x7F の範囲外の文字が送信されたらエラー -->
  <h:form>
    <b>サンプル検索フォーム(type/CustomValidator)</b><br />
    <cc:searchForm buttonLabel="検索(type/CustomValidator)">
      <f:actionListener for="searchEvent"
        type="com.yamicha.custom.SearchListener" />
      <f:validator for="word" binding="#{searchBean.asciiValidator}" />
    </cc:searchForm>
  </h:form>

  <h:form>
    <b>サンプル検索フォーム(binding A)</b><br />
    <cc:searchForm buttonLabel="検索(binding A)">
      <f:actionListener for="searchEvent" binding="#{searchBean.bindingA}" />
    </cc:searchForm>
  </h:form>

  <h:form>
    <b>サンプル検索フォーム(binding B)</b><br />
    <cc:searchForm buttonLabel="検索(binding B)">
      <f:actionListener for="searchEvent" binding="#{searchBean.bindingB}" />
    </cc:searchForm>
  </h:form>
</h:body>

</html>
 f:actionListenerのリスナ指定方法には2種類があり、typeの場合にはクラス名を指定します。この場合にはおそらくデフォルトコンストラクタが呼び出され、そうして生成されたインスタンスのprocessActionメソッドが呼び出されます。bindingの場合はリスナのインスタンスが格納されたプロパティを指定し、そのインスタンスのメソッドが呼び出されます。
 上記xhtmlのフォームは上から順に、f:actionListenerのtypeにてクラスの指定を行ったもの、type指定かつ標準バリデータであるf:validatorRequredで"word"をチェックするもの、type指定かつカスタムバリデータで"word"をチェックするもの、f:actionListenerにbindingAプロパティを渡すもの、同じくbindingBプロパティを渡すものの5種類となっています。
 後はリダイレクト先のsearchResult.xhtmlを残すのみです。これはサンプルですから検索は実装していませんが、実装の際にはSearchListenerに検索の動作を書き加え、searchResult.xhtmlで結果を表示すれば、おそらく正しく動作するでしょう。
<?xml version="1.0" encoding="Shift_JIS" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:c="http://java.sun.com/jsp/jstl/core"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:cc="http://java.sun.com/jsf/composite/comp">

<h:head>
  <title>JSF 2.0 Custom Component</title>
</h:head>

<h:body>
  <b>
    <h:outputText value="#{searchBean.type}" />
  </b>
  検索フォームにて
  <b>
    <h:outputText value="#{searchBean.word}" />
  </b>
  を検索しました。
</h:body>

</html>
カテゴリ [開発魔法][社会問題] [トラックバック 0][コメント 0]

新しい臓器提供意思表示カードをつくる改正
2010/03/28(Sun)23:41:43
 臓器移植法の改正により、今後は本人の明確な拒否の意思表明がない限り、家族同意で臓器提供が行われる可能性が出てきましたが、それにあわせて臓器提供意思表示カードの様式も見直されることとなりました。現在パブリックコメントが行われており、それも踏まえて様式の改定が行われるようです。
 これまでは臓器提供に本人同意が必須であったのが、今後は拒否の表明がなければ移植の可能性が出てくる点もさることながら、現行のカードはあまりにも分かりづらいものであったため、その意味でも改定は妥当といえるでしょう。所持者が意思を明確に伝えられ、しかもそれが尊重されるよう、カードはあくまで分かりやすいものでなければなりません。
 パブリックコメントのPDFによれば、現行のカードは以下の通りです。


 現行の臓器提供意思表示カード。

 参考までに、私は以下のデザインのカードを携帯しています。かなり初期のカードですので、現行のものとは表面の絵が違いますが、質問はおおむね同様です。


 初期の臓器提供意思表示カード。「厚生省」に時代を感じる。

 文面の主な差異を挙げておくと、私が所持している初期のカードでは、「眼球」の選択肢が2番にしかありませんが、現行のカードでは1番にも「眼球」が加わっています。また、初期のカードには「眼球(角膜)」と書いてあったのが、現行のものでは「眼球」のみとなっています。それ以外はほぼ同じです。
 一方、やはりパブリックコメントのPDFによれば、新しいカード案として以下のようなものが提示されています。


 新しい臓器提供意思表示カード案。

 以前のカードで発生する可能性のあった問題は、新しいカード案ではそれなりに解決されています。旧来のカードでは、それぞれの項目の下に臓器名が並べられていましたが、
(該当する1.2.3.の番号を○で囲んだ上で提供したい臓器を○で囲んで下さい)
  1. 私は、脳死の判定に従い、脳死後、移植の為に○で囲んだ臓器を提供します。
    (心臓・肺などの臓器名...)
  2. 私は、心臓が停止した死後、移植の為に○で囲んだ臓器を提供します。
    (腎臓・眼球などの臓器名...)
  3. 私は、臓器を提供しません。
 提供したい臓器名を○で囲んでいたとしても、番号を○で囲み忘れるとアウトでした。実は私も当初、このミスを犯したままでカードを携帯しており、新聞社のサイトで「記載不備が多い」旨の記事を読んでようやく気づくに至りました。途中からはある程度弾力的に解釈を行うようになり、記載に少々の不備があっても提供意思が認められるようにはなった模様ですが、臓器移植の開始当初は特に意思が厳密に解釈されていたため、このような些細な記載不備で臓器を提供できない状況が発生していました。
 また、旧カードでは「該当する1.2.3の番号を○で囲」むよう指示されていますが、「自分に該当するものを1つ選べ」という意味か、はたまた「自分に該当するものをすべて選べ」という意味なのかがあいまいです。その上で、仮に前者の意味として1のみを選択していると、「脳死の判定に従った脳死後に臓器を提供するのは構わないが、心臓停止した死後に臓器を提供するのには同意していない」とも解釈されうるという全く意味不明な状況が発生しかねませんでした。さらに、1と2の両方を選択していた場合でも、1については各種臓器に○をつけておいて、2では○を省略していた場合、やはり「脳死後に腎臓などを提供するのは構わないが、心臓停止後に腎臓を提供するのには同意していない」とみなされる余地がありました。
 新しい臓器移植法では、そもそも拒否の意思表示がない限りは臓器提供の可能性があるため、記載不備があっても拒否とみなされない限りは問題がなく、このようなミス自体があまり重要なものではなくなっていますが、それでも文面はある程度分かりやすく修正されています。
(1.2.3.いずれかの番号を○で囲んでください)
  1. 私は、脳死後及び心臓が停止した死後のいずれでも移植の為に臓器を提供します。
  2. 私は、心臓が停止した死後に限り、移植の為に臓器を提供します。
  3. 私は、臓器を提供しません。
(太字は引用者による。提供臓器選択欄は1と2で統一され、提供したい臓器にマル印をつける方式から、提供を希望しない臓器にバツ印をつける方式に変更)
 番号は単一選択であると明確に規定され、原理上おかしかった「脳死後に臓器は提供するが、心臓が停止した死後には臓器を提供しない」という誤った意思表明は存在しなくなっています。また、拒否の意思がなければ臓器提供の可能性がある新移植法を踏まえ、臓器も提供したいものを○で囲む方式から、提供したくないものを除外する方式に変わっています。臓器選択欄も1と2で統一され、意味不明な意思表示が発生しないようになっています。

 ただ、以前のカードに存在した問題はある程度解決されているとはいえ、新しいカード案にも疑問がないわけではありません。
 旧臓器移植法に基づいた旧来のカードには、主に次のような役割がありました。
  • 所持者が脳死判定に同意しているかを明確にすること
  • 所持者が臓器提供に同意しているか、いかなる臓器を提供するかを明確にすること
 これは以前の臓器移植法からして当然の要請でした。旧臓器移植法においては、「脳死は個体死か」という問題もある意味で棚上げされており、脳死判定を行うのにも臓器提供にも本人の同意が必要でした。したがって、本人が脳死判定に同意しているか(すなわち「脳死」を「自らの死」と認めるか)、また脳死判定に同意する場合は脳死後に、そうでなければ従来の方法での個体死認定後に、臓器を提供する意思があるかを確認するのが意思表示カードの主な役割となっていました。
 ところが、新臓器移植法では逆に、本人が拒否の意思を示さない限りは臓器提供がなされる可能性が出てきました。この場合、カードは以下のような役割を果たすことになります。
  • 所持者が条件付きで、あるいはいかなる場合でも臓器を提供しない意思を表明すること
  • 所持者が臓器提供自体には同意していても、特定の臓器は提供しない意思を表明すること
  • 所持者が臓器提供の意思があることを家族に対して明確にすること
 ここで重要なのは3番目です。
 これまでの臓器移植法においては、臓器を提供したくない場合はカードを持っても持たなくても同じでした。本人が書面(カード)で同意していなければ臓器提供は行われませんし、本人が同意している場合は遺族に確認がなされ、その同意があれば臓器提供が行われていました。この場合、そもそも本人の提供意思が明確でない限り、臓器提供の対象とはならず、遺族への確認は行われないわけですから、遺族に確認がなされる場合は必ず故人が提供意思を持っていることになり、「所持者が家族に意思を明確にする」という機能を考える必要はありませんでした。
 一方、新臓器移植法ではこれが逆転し、本人の拒否がない限り臓器提供の可能性があります。このケースでは、本人が提供の意思を表明している場合もあれば、していない場合もあります。すなわち、カードを持っても持たなくても提供がなされる可能性があるという点では同じなのですが、こちらは以前の場合とは違い、カードがなければ遺族が故人の意思を測りかねる恐れがあります。そうなると、本人が提供の意思を示していれば提供に同意したであろう遺族が、本人の意思が不明瞭であることを理由に提供を拒む可能性があり、せっかく臓器移植法を改定したにもかかわらず、移植の機会があまり増えない状況にもなりかねません。
 新カード案は、上で示した最初の2つの役割はおおむね満たしているものの、この役割については十分に満たしているか疑問があります。新しい制度自体が「何も表明しなければ提供の可能性あり」なのですから、カードが簡略化されること自体は当然の流れなのですが、それによって意思伝達の側面が希薄になるとすれば、問題があることは否めません。
 例えば、世の中の多くの人は移植についてあまり知識を持たないわけですが、そのような遺族が「故人の眼球の移植に同意するか」と問われたら、果たして抵抗なく同意できるでしょうか。しかも、旧来のカードであれば「眼球」に○をつける必要があり、眼球の提供は故人の意思であると分かりますが、新しいカードではバツ印さえついていなければ同意とみなされます。「バツがついていないから、提供は故人の意思だ」とみなすのは、「マルがついているから、提供は故人の意思だ」とみなすよりも明らかに困難です。せめて「提供の意思を明確にするために、臓器名を○で囲んでも構いません」の注意書きの1つでも入れておけば、それなりに改善される問題ではないでしょうか。
 また、以前に比べて大幅に改善されたとはいえ、例の「番号を○で囲む」スタイルにはあまり賛同できません。私が誤記した経験から申し上げて、あの方法は非常に見落としやすいのです。ここで誤記が発生すると、やはり所持者の意思があいまいになってしまい、意思表示媒体としての役目を十分果たせなくなる懸念があります。この方法を新カードでも用いるのであれば、せめて番号の手前にチェックボックスを置くなど、「ここはただの箇条書き項目ではなく、所持者が記入しなくてはならない部分」と印象付けるような工夫が欲しいところです。
 それから、大変に些細なことではありますが、このブログで以前にQRコードメーカーを作成した際に読んだ仕様書には、「QRコードの周囲4ピクセル分は、コード内の白部分と同じ色の余白でなくてはならない」と書かれていたよう記憶しています。まだ実物のカードが存在しないため、実際の寸法は分かりませんが、パブリックコメントのPDFファイルの画像を見る限り、背景のオレンジ色の部分がQRコードの余白に侵食しているようです。また、こちらは4ピクセル分離れているようにも離れていないようにも見えますが、もし「臓器移植ネットワーク」の「ク」の文字が4ピクセル以内に入っているなら、完全に仕様に反しています。最近の読み取り機器の性能からして、そうそうエラーは出ないはずですが、撮影時の周囲の明るさなどでも彩度は変化するのですから、誤って読み取られる可能性は常に存在しており、利用者に優しいとはいえません。
 また、せっかく良いカードを作っても、所持する人が増えなければ意味がありません。もし今後もカードがあまり普及せず、カード不所持につき遺族同意によって誰かの臓器が提供されたとして、もしその人が周囲に臓器提供反対の意を話していたり、カードによらない方法で提供を拒む意思を遺していたことが後で発覚すれば、新臓器移植法の概念自体が窮地に追い込まれかねません。拒否の意思を担保する意味でも、カードの普及を今以上に図る必要があります。

 JSF 2.0のカスタムコンポーネントでは、属性を使って値やメソッドを受け取ることができました。プロパティやメソッドも使えるとあって、これだけでもそれなりに様々な使い方が可能です。
 ただ、属性だけでは柔軟性の高いコンポーネントの作成は不可能ですし、できたとしても大量の属性を取らなくてはならず、逆に見通しが悪くなります。何らかの要素を記述できるなど、もっと柔軟性のある方法を使用したいところです。
 そんなこんなで探してみたところ、その方法はやはり存在していました。各種資料を読む限り、やり方はいくつか存在するようですが、今回はcomposite:insertChildren及びcomposite:renderFacetを使用しています。
 composite:insertChildrenは単純に、カスタムタグが持つ要素などの子ノードをそのまま貼り付けるもので、使い方は非常に簡単です。カスタムコンポーネントの側ではcomposite:interface内に特に何も書く必要がなく、単にcomposite:implementation内の好きな場所に<composite:insertChildren />を書くだけです。カスタムコンポーネントを使用する際には、その子ノードとして任意の要素なり何なりを持たせておけば、後はinsertChildrenの部分がそれに置き換わります。
 composite:renderFacetは名前つきinsertChildrenのようなものらしく、composite:interfaceで名前の記述が必要な上、renderFacetタグを使用する際にも名前を指定しなくてはならず、呼び出し側でも渡したいノードをf:facetでくくらなくてはなりませんが、より柔軟です。
 これらは併用しても動作するようで、その際にはf:facetの子ノードがそれぞれ対応するcomposite:renderFacetの部分に表示され、f:facetに含まれていない部分がcomposite:insertChildrenに表示されました(GlassFish v3 Previewの場合。他の実装では実験していません)。
 以下、前回のフォームの改良版として、これらの方法をそれぞれ用いたカスタムコンポーネントを作成及び使用しています。
/resources
 /comp
  customFormInput.xhtml
  customLabelInput.xhtml
/WEB-INF
 /classes
  /com
   /yamicha
    /custom
     CustomFormBean.java
 web.xml
customForm.xhtml
customLabel.xhtml
customResult.xhtml
 このうち、customFormInput.xhtml及びcustomForm.xhtmlがcomposite:insertChildrenを用いており、customLabelInput.xhtml及びcustomLabel.xhtmlがcomposite:renderFacetやf:facetを用いています。それ以外の点はほとんど同じです。CustomFormBeanはManagedBean、customResult.xhtmlは結果表示用ページで、これらは両者で同じものを使用しています。
 web.xmlは前回と全く同じです。
<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app>
  <context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Development</param-value>
  </context-param>

  <display-name>JSF 2.0 Custom Component Servlet</display-name>
  <description>JSF 2.0 Custom Component Servlet</description>

  <servlet>
    <servlet-name>jsf20custom</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>jsf20custom</servlet-name>
    <url-pattern>*.jsf</url-pattern>
  </servlet-mapping>
</web-app>
 CustomFormBean.javaも前回のCustomForm.javaと似たり寄ったりですが、今回はnameプロパティがfirstNameとlastNameになり、addressプロパティはaddress1とaddress2になっています。
package com.yamicha.custom;

import javax.ejb.*;
import javax.annotation.*;
import javax.faces.validator.ValidatorException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.application.FacesMessage;
import javax.faces.component.html.HtmlInputText;
import javax.faces.bean.*;
import javax.faces.event.*;
import java.util.*;

@ManagedBean @RequestScoped public class CustomFormBean
	implements java.io.Serializable{
	private String fname;
	private String lname;
	private String mail;
	private String webPage;
	private String address1;
	private String address2;

	public CustomFormBean(){
	}

	public String getFirstName(){
		return fname;
	}
	public String getLastName(){
		return lname;
	}
	public String getMail(){
		return mail;
	}
	public String getWebPage(){
		return webPage;
	}
	public String getAddress1(){
		return address1;
	}
	public String getAddress2(){
		return address2;
	}

	public void setFirstName(String n){
		fname = n;
	}
	public void setLastName(String n){
		lname = n;
	}
	public void setMail(String m){
		mail = m;
	}
	public void setWebPage(String w){
		webPage = w;
	}
	public void setAddress1(String a){
		address1 = a;
	}
	public void setAddress2(String a){
		address2 = a;
	}

	public void requiredValidator(FacesContext context ,
		UIComponent component , Object value){
		if(((String)value).isEmpty()){
			HtmlInputText input = (HtmlInputText)component;
			throw new ValidatorException(new FacesMessage(
				input.getLabel() + " は必須項目です。"));
		}
	}
}
 本題はここからです。まずはcomposite:insertChildrenを使用しているカスタムコンポーネント・customFormInput.xhtmlより。
<?xml version="1.0" encoding="Shift_JIS" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:c="http://java.sun.com/jsp/jstl/core"
  xmlns:composite="http://java.sun.com/jsf/composite">

  <composite:interface>
    <composite:attribute name="labelStyleClass" default="" />
    <composite:attribute name="inputStyleClass" default="" />
    <composite:attribute name="indent" default="15" />
    <composite:attribute name="label" />
  </composite:interface>

  <composite:implementation>
    <table border="0" width="90%">
      <tr>
        <td class="#{cc.attrs.labelStyleClass}">
          <h:outputText value="#{cc.attrs.label}" />
        </td>
      </tr>
      <tr>
        <table border="0" width="100%">
          <tr>
            <td width="#{cc.attrs.indent}"></td>
            <td class="#{cc.attrs.inputStyleClass}">
              <composite:insertChildren />
            </td>
          </tr>
        </table>
      </tr>
    </table>
    <br />
  </composite:implementation>
</html>
 前回作成したcustomInput.xhtmlとの違いといえば、せいぜいh:inputTextを使用していた部分が、今回はcomposite:insertChildrenに変わっているだけです。それに伴ってcomposite:interfaceでの属性の指定も少なくなっていますが、これは副次的な変化です。
 これはcustomForm.xhtmlで使用しています。
<?xml version="1.0" encoding="Shift_JIS" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:c="http://java.sun.com/jsp/jstl/core"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:cc="http://java.sun.com/jsf/composite/comp">

<h:head>
  <title>JSF 2.0 Custom Component</title>
  <style type="text/css">
    td.label { background-color: #CCDDFF; }
  </style>
</h:head>

<h:body>
  <b>送信フォーム</b><br />
  <small>(*)必須項目</small>

  <h:form>
    <cc:customFormInput label="氏名(*)" labelStyleClass="label">
      氏名を入力してください。<br />
      First <h:inputText value="#{customFormBean.firstName}"
        validator="#{customFormBean.requiredValidator}"
        label="First Name" /> / 
      Last <h:inputText value="#{customFormBean.lastName}"
        validator="#{customFormBean.requiredValidator}"
        label="Last Name" />
    </cc:customFormInput>

    <cc:customFormInput label="メールアドレス(*)" labelStyleClass="label">
      メールアドレスを入力してください。<br />
      <h:inputText value="#{customFormBean.mail}" size="40"
        validator="#{customFormBean.requiredValidator}"
        label="メールアドレス" />
    </cc:customFormInput>

    <cc:customFormInput label="Web ページ" labelStyleClass="label">
      Web ページをお持ちなら、アドレスを入力できます。<br />
      <h:inputText value="#{customFormBean.webPage}" size="60" />
    </cc:customFormInput>

    <cc:customFormInput label="在住地域" labelStyleClass="label">
      公開可能な範囲で在住地域を入力できます。<br />
      <br />

      国・都道府県・州・市区町村<br />
      <h:inputText value="#{customFormBean.address1}" size="60" /><br />
      地域・番地<br />
      <h:inputText value="#{customFormBean.address2}" size="60" />
    </cc:customFormInput>

    <h:commandButton action="customResult" value="送信" />
  </h:form>
</h:body>

</html>
 今回はここで入力フォームを記述しています。これで前回のようにバリデータを渡す必要がなくなった他、何でも自由に記述できるようになっているため、上記のように複数個のh:inputTextを用意できたり、h:inputText以外のものを配置できたりと、自由度が増しています。
 これに対して、component:renderFacetを使用するコンポーネントも作成してみます。まずはカスタムコンポーネントのcustomLabelInput.xhtmlより。
<?xml version="1.0" encoding="Shift_JIS" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:c="http://java.sun.com/jsp/jstl/core"
  xmlns:composite="http://java.sun.com/jsf/composite">

  <composite:interface>
    <composite:attribute name="labelStyleClass" default="" />
    <composite:attribute name="inputStyleClass" default="" />
    <composite:attribute name="indent" default="15" />
    <composite:facet name="label" />
    <composite:facet name="form" />
  </composite:interface>

  <composite:implementation>
    <table border="0" width="90%">
      <tr>
        <td class="#{cc.attrs.labelStyleClass}">
          <composite:renderFacet name="label" />
        </td>
      </tr>
      <tr>
        <table border="0" width="100%">
          <tr>
            <td width="#{cc.attrs.indent}"></td>
            <td class="#{cc.attrs.inputStyleClass}">
              <composite:renderFacet name="form" />
            </td>
          </tr>
        </table>
      </tr>
    </table>
    <br />
  </composite:implementation>
</html>
 今度はcomponent:interface内にcomposite:facetを記述しています。ここでは、label及びformという名前のfacetを用いることを指定しています。また、insertChildrenの代わりにrenderFacetを用いています。
 ちなみに、これとは別にcomposite:insertFacetなるタグが存在しているようですが、こちらは使用しても全く機能しませんでした。どうもJSF 2.0人口は恐ろしく少ないらしく、検索してもこれといった資料が出てきませんでしたが、何か別の使い道があるのでしょうか。
 このカスタムコンポーネントは、customLabel.xhtmlで使用しています。
<?xml version="1.0" encoding="Shift_JIS" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:c="http://java.sun.com/jsp/jstl/core"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:cc="http://java.sun.com/jsf/composite/comp">

<h:head>
  <title>JSF 2.0 Custom Component</title>
  <style type="text/css">
    td.label { background-color: #CCDDFF; }
  </style>
</h:head>

<h:body>
  <b>送信フォーム</b>

  <h:form>
    <cc:customLabelInput labelStyleClass="label">
      <f:facet name="label">
        氏名<small style="color: red">(必須)</small>
      </f:facet>
      <f:facet name="form">
        氏名を入力してください。<br />
        First <h:inputText value="#{customFormBean.firstName}"
          validator="#{customFormBean.requiredValidator}"
          label="First Name" /> / 
        Last <h:inputText value="#{customFormBean.lastName}"
          validator="#{customFormBean.requiredValidator}"
          label="Last Name" />
      </f:facet>
    </cc:customLabelInput>

    <cc:customLabelInput labelStyleClass="label">
      <f:facet name="label">
        メールアドレス<small style="color: red">(必須)</small>
      </f:facet>
      <f:facet name="form">
        メールアドレスを入力してください。<br />
        <h:inputText value="#{customFormBean.mail}" size="40"
          validator="#{customFormBean.requiredValidator}"
          label="メールアドレス" />
      </f:facet>
    </cc:customLabelInput>

    <cc:customLabelInput labelStyleClass="label">
      <f:facet name="label">
        Web ページ
      </f:facet>
      <f:facet name="form">
        Web ページをお持ちなら、アドレスを入力できます。<br />
        <h:inputText value="#{customFormBean.webPage}" size="60" />
      </f:facet>
    </cc:customLabelInput>

    <cc:customLabelInput labelStyleClass="label">
      <f:facet name="label">
        在住地域
      </f:facet>
      <f:facet name="form">
        公開可能な範囲で在住地域を入力できます。<br />
        <br />

        国・都道府県・州・市区町村<br />
        <h:inputText value="#{customFormBean.address1}" size="60" /><br />
        地域・番地<br />
        <h:inputText value="#{customFormBean.address2}" size="60" />
      </f:facet>
    </cc:customLabelInput>

    <h:commandButton action="customResult" value="送信" />
  </h:form>
</h:body>

</html>
 今回は入力フォームに加え、ラベルも自分で書けるようにしています。
 この両者はどちらも、customResult.xhtmlを結果表示ページとしています。
<?xml version="1.0" encoding="Shift_JIS" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:c="http://java.sun.com/jsp/jstl/core"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:cc="http://java.sun.com/jsf/composite/comp">

<h:head>
  <title>JSF 2.0 Custom Component - Result</title>
</h:head>

<h:body>
  以下のデータが送信されました。

  <h:panelGrid border="1" columns="2">
    <h:outputText value="名前" />
    <h:panelGroup>
      <h:outputText
        value="#{customFormBean.firstName} #{customFormBean.lastName}" />
    </h:panelGroup>

    <h:outputText value="メールアドレス" />
    <h:outputText value="#{customFormBean.mail}" />

    <h:outputText value="Web ページアドレス" />
    <h:outputText value="#{customFormBean.webPage}" />

    <h:outputText value="在住地域" />
    <h:panelGroup>
      <h:outputText value="#{customFormBean.address1}" />
      <h:outputText value="#{customFormBean.address2}" />
    </h:panelGroup>
  </h:panelGrid>
</h:body>

</html>
カテゴリ [開発魔法][社会問題] [トラックバック 0][コメント 0]

<-前のページ [1] [2] [3] [4] [5] [6] [7] [8] 次のページ->
- Blog by yamicha.com -