yamicha.com's Blog - Presented by yamicha.com
Blog yamicha.com's Blog - 2017/09 の記事
[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
ブログ - yamicha.com's Blog

 存在する記事 776 件の中から 11-15 件を表示しています。
カン菅
2010/06/05(Sat)22:31:34
 鳩山氏の突然の辞任劇の後、後任の民主党代表には菅氏が選出され、新首相となりました。代表選は菅氏と樽床氏の対決でしたが、岡田氏や前原氏など有力者が相次いで菅氏の支持に回り、反小沢勢力の多くを取り込んだ菅氏が勝利しました。鳩山氏の残り任期が菅氏の任期となるため、今回の代表選における任期自体は9月末までと非常に短いですが、参院選はこの体制で行われることになります。
 民主党としても党内事情はあるはずですが、期待感に欠ける代表選であると言わざるを得ません。現状では民主党も自民党も支持を完全に失っていますが、それは双方が旧来的な体質を保持しているためです。政党どころか日本の政治自体が大混乱に陥っているのですから、ここで古い体質を払拭する必要があり、そのためには若手を代表にして大ナタを振るうのが早道でした。
 ところが、今回の民主党代表選の候補は、反小沢ではあってもベテランと評して差し支えない菅氏と、小沢氏の影響力がささやかれる樽床氏でした。仮に樽床氏が選ばれたとしても、小沢氏が体制に介入してくるようなら、当然ながら大ナタを振るうことはできませんから、今回の代表選はどう転んでも大きな期待は得られにくかったはずで、党の事情による性急な日程もあり、実質的に盛り上がりのない代表選でした。
 これだけの窮地にあって、果たして民主党には本当に体制を刷新する気があるのでしょうか。自民党政権下でも安部・福田・麻生各氏と1年程度での首相交代が続きましたが、3度目の麻生氏の時点では最初から非常に苦しい状況に置かれていました。つまり、もし2度目の菅氏で失敗してしまえば、「3度目」は非常に厳しい立場に置かれるのです。それを防ぐためには、当面は菅氏の体制で刷新を進めていくしかありませんが、ここで体制を刷新できるかといえば、道は険しいと評するよりありません。
 また、党内に小沢氏の勢力が残っているのも気がかりです。仮に人事面で小沢氏の影響力を排除できたとしても、政策面で小沢氏が余計な口出しをすれば、民主党は間違いなく混乱に陥りますし、支持も得られなくなります。国民が望んでいるのは、小沢氏が単に幹事長などのポストを去ることではなく、その影響力をも返上することに他なりません。党内に絶大な影響力が残っている限り、党を旧自民党的体質から脱却させるのは困難です。
 国民の審判を受ける参院選が迫っている今のタイミングは、これまでの政策を見直すまたとない機会でもあります。無意味なバラマキを改善し、財政を立て直す政策を示せば、支持を集められる可能性は十分にあります。しかし、小沢氏の影響力を気にしている限り、小沢氏の選挙目当ての政策を覆すのは非常に難しいはずで、政策面で不要なものを見直す行為の足かせにすらなります。そして、ここで政策見直しが上手く行えなければ、後に政策見直しを断行したくなったとしても、国民の負託もなしに政策を変更するか、解散に打って出るしかなくなるため、極めて選択肢が限られます。
 すなわち、菅氏は外からは期待を集められなくなりかねず、中からは小沢氏に脅かされ、最初から非常に苦しい立場に立たされているといえます。世論の後押しも限られてしまい、小沢氏と対立しようにもなかなか上手くいかないはずですし、かといって融和の姿勢を見せようものなら、即座に支持を失うのは間違いありません。
 ただ、民主党自体は決して能力が低い政党ではありませんので、小沢氏の勢力を上手く抑え込んだ上で、菅氏が積極的に能力のある若手を用い、大ナタを振るうことができるようにすれば、変化する可能性がないわけではありません。自民党にも第三党にも期待できない状況下では、それを望む以外にはありません。

 JPA 1.0では@OneToManyと@ManyToOneをセットで、あるいは@ManyToManyを両側に書かなくてはなりませんでしたが、JPA 2.0ではUnidirectionalの機能が導入されており、片側に書くだけでも動作させられるようになっています。この機能は初期のGlassFish v3 Previewでは使えませんでしたが、最近のGlassFishでは使えるようになっています。
 ひとまず簡単に使用してみました。
/com
 /yamicha
  /unidirect
   Category.java
   Content.java
   UnidirectAccess.java
   UnidirectServlet.java
/META-INF
 persistence.xml
 persistence.xmlはこれまで同様です。
<?xml version="1.0" encoding="UTF-8"?>

<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="MySQL" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/MySQL</jta-data-source>
<properties>
<property name="eclipselink.jdbc.driver"
value="com.mysql.jdbc.Driver" />
<property name="eclipselink.ddl-generation" value="create-tables" />
<property name="eclipselink.ddl-generation.output-mode" value="database" />
<property name="eclipselink.target-database" value="MySQL" />
<property name="eclipselink.logging.level" value="FINE"/>
</properties>
</persistence-unit>
</persistence>
 通常の書き方とUnidirectの違いが出るのはここからです。Category.javaには@OneToManyと@JoinColumnの両方を書きます。
package com.yamicha.unidirect;

import javax.sql.*;
import javax.persistence.*;
import java.util.*;

@Entity @Table(name="unidirect_category" , schema="yamicha")
	public class Category implements java.io.Serializable{
	private int id;
	private String name;
	private List<Content> contents;

	public Category(){
		contents = new ArrayList<Content>();
	}
	public Category(String s){
		this();
		name = s;
	}

	@Id @GeneratedValue @Column(name="id") public int getId(){
		return id;
	}
	@Column(name="name") public String getName(){
		return name;
	}
	@OneToMany(fetch=FetchType.EAGER , cascade=CascadeType.ALL)
		@JoinColumn(name="category" , referencedColumnName="id")
		public List<Content> getContents(){
		return contents;
	}

	public void setId(int i){
		id = i;
	}
	public void setName(String s){
		name = s;
	}
	public void setContents(List<Content> c){
		contents = c;
	}
}
 ここで混乱しがちなのが@JoinColumnです。これはもともと@ManyToOneの側につけるものであるため、nameは「Content側が持つ、Categoryとのリレー用IDを格納する」カラム名、referencedColumnNameは「Category側が持つリレー用ID」となっています。うっかり逆に書くと大変です。
 Content.javaも普通のEntityですが、@ManyToOneをつけるべきプロパティ自体が不要である点が異なります。
package com.yamicha.unidirect;

import javax.sql.*;
import javax.persistence.*;

@Entity @Table(name="unidirect_content" , schema="yamicha")
	public class Content implements java.io.Serializable{
	private int id;
	private String name;

	public Content(){
	}
	public Content(String s){
		name = s;
	}

	@Id @Column(name="id") @GeneratedValue public int getId(){
		return id;
	}
	@Column(name="name") public String getName(){
		return name;
	}

	public void setId(int i){
		id = i;
	}
	public void setName(String s){
		name = s;
	}
}
 Categoryを保持するプロパティは不要です。Many側からOne側にアクセスする必要がない場合、もしくはJAXBのように循環参照しているとまずい場合には効果を発揮しそうです。
 Many側がOne側を保持していない点を除けば、使い方は通常のものと全く同じです。
// UnidirectAccess.java
package com.yamicha.unidirect;

import javax.ejb.*;
import javax.annotation.*;
import javax.persistence.*;
import java.util.List;
import java.util.ArrayList;

@Remote @Stateless(name="UnidirectAccess" ,
	mappedName="ejb/UnidirectAccess")
	public class UnidirectAccess{
	@PersistenceContext(unitName="MySQL") private EntityManager em;

	public void regist(){
		Category c1 = new Category("資産");
		c1.getContents().add(new Content("現金"));
		c1.getContents().add(new Content("売掛金"));
		c1.getContents().add(new Content("社債発行差金"));

		Category c2 = new Category("負債");
		c2.getContents().add(new Content("未払金"));
		c2.getContents().add(new Content("当座借越"));

		Category c3 = new Category("収益");
		c3.getContents().add(new Content("売上"));
		c3.getContents().add(new Content("受取手数料"));

		em.persist(c1);
		em.persist(c2);
		em.persist(c3);
	}
	public List<Category> getCategories(){
		return em.createQuery("SELECT c FROM Category c" ,
			Category.class).getResultList();
	}
	public Category getCategory(Object id){
		return em.find(Category.class , id);
	}
}

// UnidirectServlet.java
package com.yamicha.unidirect;

import javax.servlet.annotation.*;
import javax.ejb.*;
import javax.annotation.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.persistence.*;
import java.io.*;
import java.util.List;
import java.util.ArrayList;

@WebServlet(name="unidirectservlet" , urlPatterns={"/*"})
	public class UnidirectServlet extends HttpServlet{
	@EJB(beanName="UnidirectAccess") private UnidirectAccess ua;

	public void doGet(HttpServletRequest request ,
		HttpServletResponse response) throws IOException{
		doPost(request , response);
	}
	public void doPost(HttpServletRequest request ,
		HttpServletResponse response) throws IOException{
		response.setCharacterEncoding("UTF-8");
		response.setHeader("Content-type" ,
			"text/plain;charset=UTF-8");
		PrintWriter out = response.getWriter();

		ua.regist();

		List<Category> categories = ua.getCategories();
		for(Category category : categories){
			out.println(category.getName());
			for(Content c : category.getContents()){
				out.println("t" + c.getName());
			}
		}

		out.close();
	}
}
 JAXBと組み合わせれば@XmlTransientを書く必要もなくなるなど、様々な使い方ができそうです。
カテゴリ [開発魔法][社会問題] [トラックバック 0][コメント 0]

ブロッキング対策対策記事
2010/05/30(Sun)23:56:41
 児童ポルノを遮断するためのブロッキングについて、政府の児童ポルノ排除対策ワーキンググループは、コンテンツ発見直後のブロッキングが現行法でも可能であるとの結論で合意しました。通信の秘密の観点から「他に取りうる手段がない場合」に限定して行われるべきとの意見も出ていたものの、最終的には積極的なブロッキングを可能とする結論が出たようです。このグループがまとめた対策が実現された場合、ISPなどが利用者の通信を監視し、問題のあるコンテンツへのアクセスを遮断できるようになります。
 児童ポルノを規制する必要性については、おそらく大半の人が同意するところでしょう。インターネット上に広まった児童ポルノは半永久的に拡大し続け、被害者のダメージは際限なく拡大します。したがって、それを食い止めるための取り締まりは行われるべきですし、それ自体に異論を挟む人はほとんど存在しないはずです。異論が出るとすれば、取り締まり自体が悪いのではなく、やり方に問題があるからに他なりません。
 実際、今回のグループ内でも積極的なブロッキングに慎重な意見が出されている点からも、懸念の存在は明白です。積極的なブロッキングが「通信の秘密」などの権利を侵害するものである以上、ブロッキングそのものはただちに否定されるべきではないにせよ、八方手を尽くした上で他に手段がない場合にのみ、謙抑的に行使すべきである、という意見には一定の合理性があります。
 さらに、ブロック対象を誰がいかなる基準で定めるのか、それが本当に妥当なブロックであるかを誰が確認・保証するのかという点についても、各所から疑問が呈されています。仮に児童ポルノの単純所持が禁止された場合、「いかなるものであれ、警察が児童ポルノとみなしたものが児童ポルノ」となってしまい、不当逮捕や別件逮捕などに用いられてしまう危険がありますが、ブロッキングの場合も「いかなるサイトであれ、判断する人が児童ポルノサイトとみなしたものが児童ポルノサイト」となってしまう危険があります。これを防止するためには、判断組織は十分に透明性のあるものでなくてはなりませんし、基準も拡大解釈の余地がないほど厳格なものでなくてはなりませんが、実際には「18歳未満と推測される人物のわいせつな図画」のように非常にあいまいな基準が制定される可能性が極めて高く、懸念を抱かないわけにはいきません。
 また、こちらは児童ポルノ問題とは直接関係はありませんが、ISPが利用者の通信履歴を保管し、それを広告配信などに使用する技術について、総務省が容認する方針を示しました。利用者がいかなるサイトを閲覧し、何に興味を持ち、何を購入したことがあるかなどを調べ、それに応じた広告を配信するというものです。しかし、インターネットの通信というものは、時として利用者を丸裸にしてしまいかねず、プライバシーを侵害する懸念が著しく強いものですし、万が一情報が流出してしまった場合の深刻さは計り知れません。ブロッキング問題といい、政府は「通信の秘密」をあまりに甘く見ているのではないでしょうか。
 ただ、通信の秘密を侵害する懸念を背負ってもなお、児童ポルノの蔓延を防ぐために積極的なブロッキングがどうしても必要であるというならば、条件を非常に厳格に定めることが大前提ですが、私は必ずしもそれに反対する気はありません。ただしその場合、政府は「どうしてブロッキングなどの対策が必要なのか」という「そもそも」の部分を明確に示す必要があります。
 私がインターネット上の児童ポルノを問題視するのは、これを放置すると被害者の写真などが永久に広まってしまい、被害者が際限なくダメージを受けてしまう現状があるためです。しかし一方で、一部の団体やマスコミは「児童ポルノの犯罪誘発効果」をも根拠に挙げることがあります。これは今のところ何の根拠もない言い分ですが、一部団体はあたかもそれが明白であるかのような主張を行っています。
 そして、「被害者のダメージ」を根拠として児童ポルノを規制する場合、被害者が存在しないコンテンツを規制する理由がないのに比べ、「犯罪誘発効果」を根拠として規制する場合、創作物など被害者が存在しないコンテンツも規制される可能性が出てきますし、「犯罪誘発効果がある」と判断されさえすれば、いかなるものでも規制されてしまいます。そうなると、規制対象が際限なく広がってしまう恐れがあります。
 そもそも、政府は何の理由もなく自由や表現を規制するようなことをしてはいけないはずで、もし「犯罪誘発効果」を理由に規制を行いたいのであれば、根拠を明示する必要があります。もし根拠もなくそのような規制が行えるなら、適当な理由をでっち上げさえすれば、いかなるコンテンツでも好き勝手に規制が可能となります。
 すなわち、「どうして対策が必要なのか」という部分によって、規制する必要がある範囲、あるいは規制する根拠が存在しない範囲もおのずと定まってきますし、政府の証明責任も明確になります。間違ってもいい加減な理由で規制を開始し、「犯罪誘発効果」などを後付けして規制対象を広げていくようなことがあってはいけません
 児童ポルノの流通が被害者に深刻なダメージを与えており、何らかの規制が必要なのは論を待ちません。しかし、「児童ポルノの被害者救済」を錦の御旗とすれば何でも認められるとなれば、ポルノを名目に通信を取り締まる中国のような状況にもなりかねませんし、もし「児童ポルノを建前にした通信の秘密の侵害・通信制限」や「家に踏み込んで子どもの写真を探し、別件逮捕」のような懸念が本当に発生した場合、このような取り締まりは人権を侵害するばかりか、決して児童ポルノ根絶の役にも立ちません。ブロッキングにせよ、単純所持にせよ、規制に対しては慎重である必要があり、議論が尽くされなくてはならないのは言うまでもありません。

 2009年11月時点のGlassFish v3 Previewでは、一応Persistence 2.0が銘打ってはあるものの、CriteriaばかりかUnidirectionalもOrderColumnも使えない体たらくでした。MapKeyに関しては、かろうじて使えないわけでもなかったものの、本来なら勝手に準備してくれるはずのプロパティを自分で作らなければ機能せず、「Preview」の看板に偽りなしのリリースでした。
 これでは非常に困るため、4月の終わりごろに再度入手してみたところ、今度はようやくCriteriaもUnidirectionalもOrderColumnも使えるようになっていました。今回はOrderColumnを使用します。
 通常、SQLにせよJPAにせよデータの順番というものは保証されておらず、SQLの仕様でも「特定の順番が必要であれば、ORDER BYを使わなければならない」とされています。元のSQLがそうなのですから、JPAのOneToManyやManyToManyのリストの順番も保証などされていません。ただ、Many側にソートに使えるようなプロパティを用意しておいて、リストに対して@OrderByをつけておけば、並び替え自体は1.0でも可能です。
 2.0で追加された@OrderColumnは@OrderByに似ていますが、こちらは「リストの順番をそのまま保存する」ような機能となっているようで、テーブルにインデックス用カラムが自動的に用意されます。リスト上のインデックスがそのままテーブルに保存されるため、開発者の側で何かを書く必要はありません。一方、@OrderColumnは@OrderByに変わるものではなく、日付や値段などといったものでソートしたい場合であれば、@OrderByを使用することになるでしょう。また、@OrderColumnはOneToManyとManyToManyの両方に使えます。各種資料にも両方の例が記載されており、実際に使用してみた際にも動作しました。
/com
 /yamicha
  /ordercolumn
   Ranking.java
   Country.java
   OrderColumnAccess.java
   OrderColumnServlet.java
/META-INF
 persistence.xml
 persistence.xmlは通常通りです。
<?xml version="1.0" encoding="UTF-8"?>

<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="MySQL" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/MySQL</jta-data-source>
<properties>
<property name="eclipselink.jdbc.driver"
value="com.mysql.jdbc.Driver" />
<property name="eclipselink.ddl-generation" value="create-tables" />
<property name="eclipselink.ddl-generation.output-mode" value="database" />
<property name="eclipselink.target-database" value="MySQL" />
<property name="eclipselink.logging.level" value="FINE"/>
</properties>
</persistence-unit>
</persistence>
 Entityには@OrderColumnの1つをつけるだけでよく、特別なプロパティなどを用意する必要はありませんでした。今回はManyToManyを使用しました。
// Ranking.java
package com.yamicha.ordercolumn;

import javax.persistence.*;
import java.util.*;

@Entity @Table(name="ordercolumn_ranking" , schema="yamicha")
	public class Ranking implements java.io.Serializable{
	private int id;
	private String name;
	private List<Country> countries;

	public Ranking(){
		countries = new ArrayList<Country>();
	}
	public Ranking(String n){
		this();
		name = n;
	}

	@Id @GeneratedValue @Column(name="id") public int getId(){
		return id;
	}
	@Column(name="name") public String getName(){
		return name;
	}
	@ManyToMany @JoinTable(name="ordercolumn_ranking_country" ,
		joinColumns=@JoinColumn(name="ranking_id" ,
		referencedColumnName="id") ,
		inverseJoinColumns=@JoinColumn(name="country_id" ,
		referencedColumnName="id"))
		@OrderColumn(name="rank")
		public List<Country> getCountries(){
		return countries;
	}

	public void setId(int i){
		id = i;
	}
	public void setName(String n){
		name = n;
	}
	public void setCountries(List<Country> c){
		countries = c;
	}
}

// Country.java
package com.yamicha.ordercolumn;

import javax.persistence.*;
import java.util.*;

@Entity @Table(name="ordercolumn_country" , schema="yamicha")
	public class Country implements java.io.Serializable{
	private int id;
	private String name;
	private String capital;
	private String leader;
	private List<Ranking> rankings;

	public Country(){
		rankings = new ArrayList<Ranking>();
	}
	public Country(String n , String c , String l){
		this();
		name = n;
		capital = c;
		leader = l;
	}

	@Id @GeneratedValue @Column(name="id") public int getId(){
		return id;
	}
	@Column(name="name") public String getName(){
		return name;
	}
	@Column(name="capital") public String getCapital(){
		return capital;
	}
	@Column(name="leader") public String getLeader(){
		return leader;
	}
	@ManyToMany(mappedBy="countries")
		public List<Ranking> getRankings(){
		return rankings;
	}

	public void setId(int i){
		id = i;
	}
	public void setName(String n){
		name = n;
	}
	public void setCapital(String c){
		capital = c;
	}
	public void setLeader(String l){
		leader = l;
	}
	public void setRankings(List<Ranking> r){
		rankings = r;
	}
}
 使用する際にも特別な操作は必要なく、ただリストに任意の順番でデータを登録していけば、その順番が保存されます。
// OrderColumnAccess.java
package com.yamicha.ordercolumn;

import javax.ejb.*;
import javax.annotation.*;
import javax.persistence.*;
import java.util.*;

@Remote @Stateless(name="OrderColumnAccess" , mappedName="ejb/OrderColumnAccess")
	public class OrderColumnAccess{
	@PersistenceContext(unitName="MySQL") private EntityManager em;

	public void regist(){
		// 2400万人 , 12万km^2
		Country dprk = new Country("朝鮮民主主義人民共和国" ,
			"平壌" , "金正日");

		// 30000 , 936
		Country us = new Country("アメリカ合衆国" ,
			"ワシントンD.C." , "バラク・オバマ");

		// 3350 , 997
		Country canada = new Country("カナダ" , "オタワ" ,
			"スティーヴン・ハーパー");

		// 13000 , 38
		Country japan = new Country("日本" , "東京" ,
			"鳩山由紀夫");

		// 8100 , 36
		Country germany = new Country("ドイツ連邦共和国" ,
			"ベルリン" , "アンゲラ・メルケル");

		// 5000 , 68
		Country myanmar = new Country("ミャンマー連邦" ,
			"ヤンゴン" , "タン・シュエ");

		// 2.3 , 0.013
		Country akune = new Country("阿久根市" , "鶴見町" ,
			"竹原信一");

		em.persist(dprk);
		em.persist(us);
		em.persist(canada);
		em.persist(japan);
		em.persist(germany);
		em.persist(myanmar);
		em.persist(akune);

		// ただ任意の順番で登録すればよい
		Ranking pop = new Ranking("人口ランキング");
		pop.getCountries().add(us);
		pop.getCountries().add(japan);
		pop.getCountries().add(germany);
		pop.getCountries().add(myanmar);
		pop.getCountries().add(canada);
		pop.getCountries().add(dprk);
		pop.getCountries().add(akune);
		em.persist(pop);

		Ranking area = new Ranking("面積ランキング");
		area.getCountries().add(canada);
		area.getCountries().add(us);
		area.getCountries().add(myanmar);
		area.getCountries().add(japan);
		area.getCountries().add(germany);
		area.getCountries().add(dprk);
		area.getCountries().add(akune);
		em.persist(area);

		Ranking total = new Ranking("全体主義国家ランキング");
		total.getCountries().add(dprk);
		total.getCountries().add(myanmar);
		total.getCountries().add(akune);
		em.persist(total);
	}
	public List<Ranking> getRankings(){
		// ようやく使用できるようになった TypedQuery
		// キャストが不要となるため、コンパイラから
		// 警告を受けずに済む
		return em.createQuery("SELECT r FROM Ranking r" ,
			Ranking.class).getResultList();
	}
	public void removeAll(){
		em.createQuery("DELETE FROM Country c").executeUpdate();
		em.createQuery("DELETE FROM Ranking r").executeUpdate();
	}
}

// OrderColumnServlet.java
package com.yamicha.ordercolumn;

import javax.servlet.annotation.*;
import javax.ejb.*;
import javax.annotation.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.persistence.*;
import java.io.*;
import java.util.*;

@WebServlet(name="ordercolumnservlet" , urlPatterns={"/*"})
  public class OrderColumnServlet extends HttpServlet{
  @EJB(beanName="OrderColumnAccess") private OrderColumnAccess oa;

  public void doGet(HttpServletRequest request ,
    HttpServletResponse response) throws IOException{
    doPost(request , response);
  }
  public void doPost(HttpServletRequest request ,
    HttpServletResponse response) throws IOException{
    response.setCharacterEncoding("UTF-8");
    response.setHeader("Content-type" , "text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();

    oa.removeAll();
    oa.regist();

    out.println("<html>");
    out.println("<head>");
    out.println("<title>OrderColumn のテスト</title>");
    out.println("</head>");

    out.println("<body>");

    List<Ranking> rankings = oa.getRankings();
    for(Ranking r : rankings){
      out.println("<b>" + r.getName() + "</b>");

      out.println("<table border="1">");

      List<Country> cs = r.getCountries();
      for(int i = 0; i < cs.size(); i++){
        out.println("<tr>");
        out.println("<td>" + (i + 1) + "</td>");
        out.println("<td>" + cs.get(i).getName() + "</td>");
        out.println("</tr>");
      }

      out.println("</table><hr />");
    }

    out.println("</body>");
    out.println("</html>");

    out.close();
  }
}
 OneToManyの場合はMany側にインデックス用カラムが作られ、ManyToManyであればマップ用テーブルにカラムが作られます。インデックスは0から始まります。
SHOW CREATE TABLE ordercolumn_ranking_country;

ordercolumn_ranking_country | CREATE TABLE `ordercolumn_ranking_country` (
`country_id` int(11) NOT NULL,
`ranking_id` int(11) NOT NULL,
`rank` int(11) DEFAULT NULL,
PRIMARY KEY (`country_id`,`ranking_id`),
KEY `FK_ordercolumn_ranking_country_ranking_id` (`ranking_id`),
CONSTRAINT `FK_ordercolumn_ranking_country_ranking_id` FOREIGN KEY (`ranking_i
d`) REFERENCES `ordercolumn_ranking` (`id`),
CONSTRAINT `FK_ordercolumn_ranking_country_country_id` FOREIGN KEY (`country_i
d`) REFERENCES `ordercolumn_country` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=sjis |
 もう1つ気になるのが、リストの末尾以外の部分に後からデータを登録した場合の挙動ですが、これはmergeで正しく更新されました(新しく登録したデータより後ろにあるものにはインデックスが加算される)。ただし、ログによれば1つ1つUPDATEを発行してインデックスを再設定しているようで、非常に効率が悪そうです。
カテゴリ [開発魔法][社会問題] [トラックバック 0][コメント 0]

口蹄疫に不見識な者は・・・
2010/05/23(Sun)22:11:10
 宮崎で口蹄疫が猛威を振るい、畜産業界に大打撃を与えています。ウイルスに感染した家畜の処分に加え、感染拡大防止のための周辺地域の牛や豚の処分、処分した家畜の埋立地の確保など課題は非常に多く、また長らく研究開発されてきた種牛も処分され、各地への子牛の供給も滞る恐れが出てくるなど、影響は相当な規模になりそうです。
 ひとまず、今回は今までほど風評被害が出ていない点が唯一の救いでしょう。これに関しては、県や政府の警戒に加え、あるいは今まで散々風評をあおってきたマスコミも多少は気を使っているようで、口蹄疫が「得体の知れないもの」とみなされてパニックを起こすような事態は避けられています。
 口蹄疫ウイルスは非常に感染力が強く、畜産業界にとっては恐ろしいウイルスですが、牛肉の主に危険部位から感染する疑いが濃厚なBSEと異なり、感染した牛や豚の肉を食べても何ら問題はありません。また、感染した家畜や食肉は処分されるため、市場に出回ることはまずありません。これも人間に対して害を与えるからではなく、感染拡大を防止するための措置とされています。「狂牛病」(BSEのかつての名称)と混同してしまっている人も一部には存在するようですが、BSEは(ウイルス関連説もあるものの)基本的には異常プリオンが原因とみられており、口蹄疫とは何の接点もありません。なお、非常に紛らわしいことに、似た名前の「狂犬病」はウイルスによる病気です。
 口蹄疫自体は必ずしも致命的な病気ではなく、実際に致死率はそれほど高くありませんが、これに感染した家畜は「売り物にならなくなる」点で非常に深刻で、畜産業界のダメージは相当なものとなります。感染力が極めて高く、問題が多数の農場に派生すると取り返しがつかない結果を招くため、徹底的な殺処分によってウイルスを封じ込め、根絶する作戦が採られます。
 鳥インフルエンザ問題で養鶏業界がダメージを受け、その後さらに口蹄疫問題とあっては、宮崎は非常に気の毒であるとしか言いようがありません。タレントから地政の世界に転身した東国原氏としても、まさに苦難の連続でしょう。ただ、本件で東国原氏が努力しているのは確かで、しかも知名度を利用した鳥インフルエンザ問題からの回復に加え、今回も口蹄疫問題に国民の目を向けさせるとともに、風評被害を抑制することにもある程度成功しており、タレント地方政治家として成功した稀有な例といえそうです。
 しかし、一方でマスコミや政治家の一部には不見識な者が存在しており、ただ珍妙なことを騒ぎ立てているだけならまだしも、下手をすると対策を妨害してしまう、あるいは間接的に邪魔になる可能性さえ否定できません。以前の記者会見では、マスコミの無思慮な言い分に対し、東国原氏が怒って退席する一幕がありましたが、あれなどはまさにマスコミの不見識が凝縮された場面でした。
 また、四日市市議の民主・諸岡氏は自身のブログで「(県は)あんな判りやすい病気を『ただの発熱』と処理した。バカじゃないかと」「県から要請を受けても放置していた国は同等のバカ」「腹を切って死ぬべきである」などと述べる有様で、不見識極まりないと言わざるを得ません。
 よく「風邪は万病のもと」と言いますが、何百何千という牛が一般的な風邪の症状を呈する中で、そのうちの1頭が数年あるいは数十年に一度といった程度の頻度で発生する口蹄疫であると特定するのが相当に難しいのは想像に難くありません。特に今回の口蹄疫は、発生当初は特徴的な症状が確認できなかったといいますので、なおさらです。また、そのような現場レベルの問題を県や国政レベルにすり替え、「バカ」「腹を切って死ぬべき」などというのは無茶にもほどがあります。その理屈でいけば、どこかの牛が発熱するたびに知事や農水相は即座に連絡を受けて陣頭指揮を執らなくては「バカ」で「腹を切って死」ななくてはならないはずですが、荒唐無稽とはまさにこのことです。
 今回は実に1000件もの抗議が寄せられ、記事は削除されたといいますので、さほど大きな問題は出ませんでしたが、仮にこのような言い分が広まってしまった場合に恐ろしいのは、政府や県といった関係者同士が責任のなすりあいを始めてしまうことです。
 本来、口蹄疫のような自然災害に悪者は存在しないはずですが、人々がやり場のない怒りや絶望感を抱くのは避けようがなく、ある関係者にほんの少しでも過失が見つかろうものなら、その人に災害の全責任が押し付けられてしまいます。そして、もしマスコミが諸岡氏のようなことを大々的に言い出していたならば、ほぼ確実に県と政府の責任合戦が始まっていたでしょう。
 無論、問題終息後に防疫体制の問題点を確認し、関係各所の責任を明確にし、それを次回の災害に生かすというのであれば、責任を確認する意義は十分にあります。しかし、現時点で関係各所が責任のなすりあいを始めれば、感染拡大阻止の足並みは確実に乱れますし、対策をダシにけん制しあう状況にもなりかねません。実際に一部では相手に責任を押し付けるような言動もあるようですが、1手遅れれば数万頭が犠牲になるのですから、明らかに争っていられる場面ではありません。
 また、もう1つ気になる点として、仮に県や国が即座に口蹄疫に対応し、大規模な殺処分作戦で感染を今よりも抑えられていたならば、一体マスコミは何を言い出したでしょうか。あれだけ不見識なマスコミのことですから、今度は「畜産農家を破壊した政府」「対策の所要額は数十億」と言い出すなど、別の批判を行っていた可能性は十分に考えられるのです。今でこそ口蹄疫の恐ろしさが認知され、英国が大量の殺処分を行った例も引き合いに出されるようになりましたが、これも今回の件が大事に至ったがためです。結局のところ、どう転んでもマスコミには「犯人」が必要なのです。
 畜産農家や行政などの関係者が口蹄疫と戦う際には、ウイルスと同時に風評被害や不見識とも戦わなくてはなりません。そして、ウイルスはともかく後の2つはいずれも人災で、状況次第ではウイルスより大きな被害をもたらしたり、ウイルスとの戦いを妨害したりします。十分な注意が必要です。

 前回は書評らしきプログラムのサーバー側実装を作成しましたが、今回は簡素なクライアント側実装を行ってみます。
 RESTですからいかなる言語を使用しても構いませんが、今回も例によってJSF 2.0を使用しています。RESTを使ってデータをやり取りし、JAXBによる変換を行っている部分を除けば、書き方はEJB + JPAを使用したJSFとさほど変わらないはずです。
 以下、下線部が追加部分です。
WEB-INF
 /classes
  /com
   /yamicha
    /rs
     /server
      @Path BookReviewService.java
      @Entity Book.java
      @XmlElement Books.java
      @Entity Review.java
      @XmlElement Reviews.java
      @Stateless BookReviewAccess.java
     /client
       @ManagedBean BookBean.java
       @ManagedBean ReviewBean.java
  /META-INF
   persistence.xml
 web.xml
book.xhtml
review.xhtml
reviewForm.xhtml
 今回、「本を選択する」操作においてListDataModelを使用しているため、SessionScopeを使用しています。まずキーワードによって本を検索すると、booksプロパティに検索した本のデータが格納され、h:dataTableなどのforeach系統のタグによってそれが表示されます。ユーザーがその中から望みの本をクリックすると、クリックした本が何番目のものであるかが伝えられ、セッションに格納された本の中から選択された本が取り出される、という寸法です。
 しかし、せっかくそのような機構があるからと使ってはみましたが、実際のところ私はJSFのSessionScoped + DataModelが少々嫌いです。ユーザー側の表示とサーバー側のデータが食い違う可能性があるためで、例えばユーザーがまず"Java"で検索し、次に"SQL"で検索(ここでサーバーのbooksにはSQL本の検索結果が格納される)、その後ブラウザの「戻る」を使ってJavaの検索結果に戻り、何か本をクリックすると、(ユーザーにとっては)なぜかSQL本が表示されてしまいます。サーバーの状態からすれば当然の結果ですが、実際に発生すると意外に面食らいます。
// BookBean.java
package com.yamicha.rs.client;

import javax.faces.bean.*;
import javax.faces.context.*;
import javax.faces.model.*;
import javax.xml.bind.*;
import javax.xml.parsers.*;
import java.io.*;
import java.net.*;
import java.util.*;
import com.yamicha.rs.server.*;

@SessionScoped @ManagedBean public class BookBean
	implements java.io.Serializable{
	public final static String REST_SERVER = 
		"(アプリケーションの URL)/restserver/book/";

	private String word;

	private ListDataModel<Book> books;
	private Book book;

	public BookBean(){
		word = "";
		books = new ListDataModel<Book>();
	}

	public String getWord(){
		return word;
	}
	public void setWord(String s){
		word = s;
	}

	public void readBooks() throws Exception{
		if(word == null || word.isEmpty())
			return;

		JAXBContext jc = JAXBContext.newInstance(Books.class);

		HttpURLConnection c = (HttpURLConnection)
			new URL(REST_SERVER + "books/" +
			URLEncoder.encode(word , "UTF-8")).
			openConnection();
		c.setRequestMethod("GET");
		c.setRequestProperty("Content-Type" , "application/xml");

		c.connect();

		InputStream is = c.getInputStream();

		Unmarshaller u = jc.createUnmarshaller();
		setBooks(new ListDataModel(((Books)u.unmarshal(is)).
			getBooks()));

		is.close();

		c.disconnect();
	}
	public ListDataModel<Book> getBooks(){
		return books;
	}
	public void setBooks(ListDataModel<Book> l){
		books = l;
	}

	public void setSelectedBook(){
		book = books.getRowData();
	}
	public void readBook(int id) throws Exception{
		JAXBContext jc = JAXBContext.newInstance(Book.class);

		HttpURLConnection c = (HttpURLConnection)
			new URL(REST_SERVER + "book/" + id).
			openConnection();
		c.setRequestMethod("GET");
		c.setRequestProperty("Content-Type" , "application/xml");

		c.connect();

		InputStream is = c.getInputStream();

		Unmarshaller u = jc.createUnmarshaller();
		book = (Book)u.unmarshal(is);

		is.close();

		c.disconnect();
	}
	public void refreshBook() throws Exception{
		readBook(book.getId());
	}
	public Book getBook() throws Exception{
		return book;
	}
}

// ReviewBean.java
package com.yamicha.rs.client;

import javax.faces.bean.*;
import javax.faces.context.*;
import javax.faces.model.*;
import javax.xml.bind.*;
import javax.xml.parsers.*;
import java.io.*;
import java.net.*;
import java.util.*;
import com.yamicha.rs.server.*;

@SessionScoped @ManagedBean public class ReviewBean
	implements java.io.Serializable{
	@ManagedProperty(value="#{bookBean}") private BookBean bookBean;
	private String name;
	private String message;

	private ListDataModel<Review> reviews;
	private Review review;

	public ReviewBean(){
	}

	public String getName(){
		return name;
	}
	public String getMessage(){
		return message;
	}
	public ListDataModel<Review> getReviews(){
		return reviews;
	}
	public BookBean getBookBean(){
		return bookBean;
	}

	public void setName(String s){
		name = s;
	}
	public void setMessage(String s){
		message = s;
	}
	public void setReviews(ListDataModel<Review> r){
		reviews = r;
	}
	public void setBookBean(BookBean b){
		bookBean = b;
	}

	public String showReviews() throws Exception{
		// 選択された本を book プロパティにセット
		bookBean.setSelectedBook();

		// book のレビューデータを読み込む
		readReviews();

		return "review";
	}

	public void setSelectedReview(){
		review = reviews.getRowData();
	}

	// PUT 用レビュー投稿フォーム設定関数
	public String editForm(){
		// 選択されたレビューを review プロパティにセット
		setSelectedReview();

		name = review.getName();
		message = review.getMessage();

		return "reviewForm";
	}
	// POST 用
	public String postForm(){
		review = null;

		name = "";
		message = "";

		return "reviewForm";
	}

	// bookBean.book プロパティのレビューリストを取得
	public void readReviews() throws Exception{
		JAXBContext jc = JAXBContext.newInstance(Reviews.class);

		HttpURLConnection c = (HttpURLConnection)
			new URL(BookBean.REST_SERVER + "book/reviews/" +
			bookBean.getBook().getId()).openConnection();
		c.setRequestMethod("GET");
		c.setRequestProperty("Content-Type" , "application/xml");

		c.connect();

		InputStream is = c.getInputStream();

		Unmarshaller u = jc.createUnmarshaller();
		reviews = new ListDataModel(((Reviews)
			u.unmarshal(is)).getReviews());

		is.close();

		c.disconnect();
	}

	// 任意のレビューを取得
	public void readReview(int id) throws Exception{
		JAXBContext jc = JAXBContext.newInstance(Review.class);

		HttpURLConnection c = (HttpURLConnection)
			new URL(BookBean.REST_SERVER + "review/" +
			id).openConnection();
		c.setRequestMethod("GET");
		c.setRequestProperty("Content-Type" , "application/xml");

		c.connect();

		InputStream is = c.getInputStream();

		Unmarshaller u = jc.createUnmarshaller();
		review = (Review)u.unmarshal(is);

		is.close();

		c.disconnect();
	}
	// 現在選択中のレビューを再読み込み
	public void refreshReview() throws Exception{
		readReview(review.getId());
	}

	// レビューを投稿
	public String sendReview() throws Exception{
		Review r = review;

		String method = null;
		if(r == null){
			method = "POST";
			r = new Review();
		}else{
			method = "PUT";
		}

		r.setName(name);
		r.setMessage(message);
		r.setBookId(bookBean.getBook().getId());

		JAXBContext jc = JAXBContext.newInstance(Review.class);

		HttpURLConnection c = (HttpURLConnection)
			new URL(BookBean.REST_SERVER +
			"review").openConnection();
		c.setRequestMethod(method);
		c.setDoOutput(true);
		c.setRequestProperty("Content-Type" , "application/xml");

		c.connect();

		OutputStream os = c.getOutputStream();

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

		os.close();

		InputStream is = c.getInputStream();
		is.read();
		is.close();

		c.disconnect();

		readReviews();	// レビューリストを再読み込み

		name = "";
		message = "";

		review = null;

		return "review";
	}
	// レビューを削除
	public void removeReview() throws Exception{
		// 削除するよう選択されたレビューを取得
		setSelectedReview();

		HttpURLConnection c = (HttpURLConnection)
			new URL(BookBean.REST_SERVER + "review/" +
			review.getId()).openConnection();
		c.setRequestMethod("DELETE");

		c.connect();

		InputStream is = c.getInputStream();
		is.read();
		is.close();

		c.disconnect();

		readReviews();	// レビューリストを再読み込み
	}
}
 RESTですから、取得はGET、作成はPOST、更新はPUT、削除はDELETEです。
 book.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">

<h:head>
  <title>JAX-RS Book Review</title>
</h:head>

<h:body>
  <b>JAX-RS Book Review</b>

  <h:form>
    本の検索<br />
    <h:inputText value="#{bookBean.word}" />
    <h:commandButton action="#{bookBean.readBooks}" value="Search" />
  </h:form>

  <h:form>
    <h:dataTable border="1" value="#{bookBean.books}" var="book">
      <h:column>
        <f:facet name="header">書名</f:facet>

        <h:commandButton action="#{reviewBean.showReviews}"
          value="書評" />
        <h:outputText value="#{book.title}"/>
      </h:column>

      <h:column>
        <f:facet name="header">著者</f:facet>
        <h:outputText value="#{book.author}"/>
      </h:column>

      <h:column>
        <f:facet name="header">出版</f:facet>
        <h:outputText value="#{book.publisher}"/>
      </h:column>
    </h:dataTable>
  </h:form>
</h:body>

</html>
 review.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">

<h:head>
  <title>JAX-RS Book Review</title>
</h:head>

<h:body>
  <b>JAX-RS Book Review</b>
  <hr />

  <table border="1">
    <tr>
      <td><b>書名</b></td>
      <td><h:outputText value="#{bookBean.book.title}" /></td>
    </tr>
    <tr>
      <td><b>著者</b></td>
      <td><h:outputText value="#{bookBean.book.author}" /></td>
    </tr>
    <tr>
      <td><b>出版社</b></td>
      <td><h:outputText value="#{bookBean.book.publisher}" /></td>
    </tr>
    <tr>
      <td><b>価格</b></td>
      <td><h:outputText
        value="#{bookBean.book.price}" /> 円</td>
    </tr>
  </table>

  <h:form>
    レビュー:
    <c:choose>
      <c:when test="${reviewBean.reviews.getRowCount() > 0}">
        <h:dataTable border="1" value="#{reviewBean.reviews}"
          var="review">
          <h:column>
            <f:facet name="header">投稿者</f:facet>
            <h:outputText value="#{review.name}"/>
          </h:column>

          <h:column>
            <f:facet name="header">内容</f:facet>
            <h:outputText value="#{review.message}"/>
          </h:column>

          <h:column>
            <f:facet name="header">投稿日時</f:facet>
            <h:outputText value="#{review.date}"/>
          </h:column>

          <h:column>
            <f:facet name="header">編集</f:facet>
            <h:commandLink action="#{reviewBean.editForm}">
              編集
            </h:commandLink>
          </h:column>

          <h:column>
            <f:facet name="header">削除</f:facet>
            <h:commandLink action="#{reviewBean.removeReview}">
              削除
            </h:commandLink>
          </h:column>
        </h:dataTable>
      </c:when>
      <c:otherwise>
        <br />
        レビューは投稿されていません。<br />
        <br />
      </c:otherwise>
    </c:choose>

    <h:commandButton action="#{reviewBean.postForm}"
      value="レビューの新規投稿" /><br />
    <br />

    <h:commandButton action="book" value="戻る" />
  </h:form>
</h:body>

</html>
 reviewForm.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">

<h:head>
  <title>JAX-RS Book Review</title>
</h:head>

<h:body>
  <b>JAX-RS Book Review</b><br />
  <br />

  「<b><h:outputText
    value="#{bookBean.book.title}" /></b>」へのレビュー

  <h:form>
    <table border="1">
      <tr>
        <td><b>投稿者名</b></td>
        <td><h:inputText value="#{reviewBean.name}" /></td>
      </tr>
      <tr>
        <td><b>コメント</b></td>
        <td><h:inputText value="#{reviewBean.message}"
          size="60" /></td>
      </tr>
    </table>

    <h:commandButton action="#{reviewBean.sendReview}"
      value="この内容を投稿" /><br />
    <br />

    <h:commandButton action="review" value="戻る" />
  </h:form>
</h:body>

</html>
 後は適当なキーワードで検索し、レビューを書くなり更新するなり削除するなり任意の捜査を行うだけです。前回の実装ではサーバー側のReview.messageプロパティにCLOBを使っていないため、文字数はMySQLだと255文字までです。
 次のURLが検索フォームです。

(アプリケーションのURL)/book.jsf

 ぽち出版はともかく、麻斐閣の本は面白そうです。
カテゴリ [開発魔法][社会問題] [トラックバック 0][コメント 0]

人気者の府
2010/05/16(Sun)00:47:05
 参院選を控え、各党で有名人の擁立が相次いでいます。民主党は柔道の谷氏を候補に立て、歌手の庄野氏の出馬も確定させましたが、対する自民党もスポーツ選手などを擁立し、国民新党も元野球選手に出馬要請を行っています。また、たちあがれ日本もスポーツ選手を擁立するばかりか、奇異な言動で注目を集めた杉村氏をも擁立するとしていますし、やや色彩は異なりますが、みんなの党は「イケメン経営者」として人気を博しているというタリーズコーヒー創業者・松田氏を擁立するようです。
 第三極を含め、どこもかしこも有名人ばかりといった状況ですが、まさに見るに耐えないという言葉がこれほど合う場面もありません。そもそも参院選、特に比例はその特性からタレント候補が登場しやすく、支持を失ってしまった民主・自民も、また党の規模が小さい弱小政党も厳しい状況であるため、ある程度のタレント候補が登場するのは十分に予想の範疇ですが、いくら何でも度が過ぎています。ここまで極端では選挙なのか人気投票なのか分かりません。
 そして、単に政権交代に伴う政治の混乱が生じただけであれば、それほど問題はありませんでしたが、実際の日本の政界は最悪のシナリオに陥りつつあります。かつて2005年の衆院選では、政策も何もない人気投票によって自民党が大勝し、後から時間差で小泉路線に批判の嵐が吹き荒れるというおかしな状態になっていましたが、このデタラメな状態が再び発生しようとしています。
 このようなくだらないタレント選挙を回避する方法は、1つしかありません。すなわち、政策も何も考慮しない投票者が大量に人気者・人気政党に投票し、当選させてしまうのですから、政策について理解している投票者が対立政党に投票し、政治家や各政党に「タレント選挙は行うだけ無駄である」と知らしめなくてはならないのです。もしそれが実現されなければ、味を占めた政党は再びタレントを立て、他党もタレントで応じざるを得なくなり、選挙が人気投票化する恐れがあります。事実、2005年の時点では「苦い薬」を訴えていた民主党が変質してしまったのは、その際の自民党大勝で「まじめに政策を訴えても無駄」という意識が出てきたことが一因のようです。
 ところが、今回の参院選では民主・自民ともにタレントやスポーツ選手を大量に擁立し、第三極さえも有名人を擁立しています。特に「たちあがれ日本」に至っては、小泉チルドレンの中でも特に多大な功績を残したわけでもなく、奇異で非常識な発言により名前だけが売れている杉村氏に白羽の矢を立てており、知名度目当てであるのは火を見るより明らかです。新党改革に至っては、現党首自身が知名度を利用して党首の座に滑り込む有様で、人気投票を嫌って他党に投票しようにも、選択肢がほとんど存在しない状態です。
 しかも2005年の衆院選の場合、スリードの戦略に基づく低IQ選挙を積極的に仕掛けていたのは自民党のみで、他党にも人気取り行為がなかったわけではないものの、一応は受け皿といえるものが存在していましたが、今回は大小問わず多くの党が人気取りに走っており、先祖がえりどころか状態はさらに悪くなっています。
 人気投票状態もここまでになると、政策などあってないようなものです。つまり、各政党ともいい加減な公約を掲げたり、難しい政策を廃して目先に利のある政策をぶら下げたり、後から適当な理屈でごまかしたりするようになったりしかねませんし、あるいは逆に政策としてしっかり掲げておいたものが、人気投票の影に隠れて注目されなくなってしまい、後から「そんなことは聞いていない」と批判されたりすることも考えられます。いずれにせよ、人気投票はまともな政治を著しく妨げます。
 そもそも、各党が申し合わせたかのようにタレント選挙に走った点からして、今の日本に存在する政党が自民党2つと多数のミニ自民党に他ならず、選択肢が存在しないことを裏付けています。本来であれば、民主党がタレント選挙に走ったとしても自民党は受け入れず、自党が低レベルなタレント選挙から脱却した姿を見せるべきですし、民主党も人気首相の世襲議員に頼るなどしている自民党との差別化を図るべきであって、タレント作戦に出るべきではありませんでした。第三極にしても、英国の自民党のような立場を目指したいのであれば、決して人気投票に加担しないようにすればそれだけで差別化を図れたものを、特に「たちあがれ日本」などは完全にどうかしています。また、タレント擁立というわけではないものの、旧改革クラブは思想の差異を無視して客寄せパンダを党首に迎え入れる有様で、やっていることは同じです。みんなの党に関しては、世襲・中川氏の擁立からして程度は知れているといえますが、それでも経営者・松田氏をタレント候補と評するべきかは微妙なところで、一応「第三極」として他党より頭1つ抜き出ているとはいえなくもありません。
 民主党の混乱やバラマキ政策などは、実際のところ政治にとって深刻な問題ではありません。事実上の戦後初と言っても過言ではない政権交代なのですから混乱しない方が不自然ですし、事業仕分けや子ども手当て財源のための意味不明な控除の廃止などは、自民党政権下ではまず起こりえなかった変化ですから、そこは評価されてしかるべきです。その上で、次のリーダーが子ども手当てなどのバラマキを廃止し、確保した財源を必要なところに振り向けるなり、借金を返すなりすれば良いのです。しかし、その混乱が全党挙げてのタレント選挙を招いたとすれば、これこそ最悪のシナリオです。
 次の参院選がタレント選挙になることがほぼ確定した以上、選挙の結果はどうあれ政治の混迷は避けられないでしょう。民主党にせよ自民党にせよ、あるいは乱立した小政党にせよ、少しの変革で「総自民党」状態から抜け出し、政策本位の支持を集めることができるところを、まとめてくだらないタレント選挙に走ってしまったのは残念でなりません。

 前回の簡易チャットでは@POSTで投稿、@GETで取得を行いましたが、(目的外利用が多いとはいえ)POSTとGETとは何とも普通で、@PUTも@DELETEも使用していません。そこで今回は、@PUTによる更新、@DELETEによる削除も実装した、簡素な「書評」らしきプログラムのサーバー側コードを書いてみます。
/WEB-INF
 /classes
  /com
   /yamicha
    /rs
     /server
      @Path BookReviewService.java
      @Entity Book.java
      @XmlElement Books.java
      @Entity Review.java
      @XmlElement Reviews.java
      @Stateless BookReviewAccess.java
  /META-INF
   persistence.xml
 web.xml
 このうちweb.xmlとpersistence.xmlは以前と全く同じで、ディレクトリ構成も同じです。私の環境では実際に以前の簡易チャットと共存させています。@Pathで別々のパスさえ設定すれば、当然ながら異なるRESTの共存は可能です。
// BookReviewService.java
package com.yamicha.rs.server;

import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ejb.*;
import javax.naming.Context;
import javax.naming.InitialContext;

@Path("book") public class BookReviewService{
	private BookReviewAccess ba;

	public BookReviewService() throws Exception{
		Context c = new InitialContext();
		ba = (BookReviewAccess)c.lookup(
			"java:global/rs/BookReviewAccess");
	}

	// サンプルデータを作成するメソッド
	@GET @Path("regist") public String registSampleBooks(){
		Book books[] = {
		new Book("Java EE プログラミング" ,
			"Cafe Babe Team" , "技術評論社" , 2600) ,
		new Book("どんなバカでもSQLが分かる本" , "El Escue" ,
			"ソフトウェアパブリッシング" , 1500) ,
		new Book("PHP + MySQL プログラミング" , "Zend" ,
			"パイソン・エデュケーション" , 4500) ,
		new Book("Java文法の基礎" , "Esp Resso" ,
			"ソフトウェアパブリッシング" , 980) ,
		new Book("改正刑法基礎知識" , "麻斐閣" ,
			"麻斐閣" , 2600) ,
		new Book("Java Servlet" , "Tom Cat" ,
			"ASFパブリッシング" , 2000) ,
		new Book("支配された日本・告発の本" , "ブログ市長" ,
			"ぽち出版" , 850)
		};

		for(Book b : books)
			ba.addBook(b);

		return "サンプルデータを登録しました。";
	}

	@GET @Path("books/{word}") public Books getBooks(
		@PathParam("word") String word){
		return new Books(ba.getBooks(word , 20));
	}
	@GET @Path("book/{id}") public Book getBook(
		@PathParam("id") int id){
		return ba.getBook(id);
	}
	@GET @Path("book/reviews/{id}") public Reviews getReviews(
		@PathParam("id") int bookId){
		return new Reviews(ba.getReviews(bookId));
	}

	@POST @Path("review") public void addReview(Review r){
		ba.addReview(r);
	}

	@PUT @Path("review") public void mergeReview(Review r){
		ba.mergeReview(r);
	}

	@DELETE @Path("review/{id}") public void removeReview(
		@PathParam("id") int id){
		ba.removeReview(id);
	}
}

// BookReviewAccess.java
package com.yamicha.rs.server;

import javax.ejb.*;
import javax.annotation.*;
import javax.persistence.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Date;

@Remote @Stateless(name="BookReviewAccess" , mappedName="ejb/BookReviewAccess")
	public class BookReviewAccess{
	@PersistenceContext(unitName="MySQL") private EntityManager em;

	public List<Book> getBooks(String word , int max){
		if(word != null)
			word = "%" + word.replace("%" , "\%") + "%";
		else
			word = "%";

		Query q = em.createQuery(
			"SELECT b FROM Book b WHERE b.title LIKE ?1");
		q.setParameter(1 , word);
		if(max != -1)
			q.setMaxResults(max);

		return (List<Book>)q.getResultList();
	}
	public List<Review> getReviews(int bookId){
		Query q = em.createQuery(
			"SELECT r FROM Review r WHERE r.book.id = ?1" +
			" ORDER BY r.date DESC");
		q.setParameter(1 , bookId);

		return (List<Review>)q.getResultList();
	}

	public Book getBook(int id){
		return em.find(Book.class , id);
	}
	public Review getReview(int id){
		// XML として送受信する場合のために
		// r.bookId プロパティに対して
		// book の id を格納しておく
		Review r = em.find(Review.class , id);
		r.setBookId(r.getBook().getId());
		return r;
	}

	public void addBook(Book b){
		em.persist(b);
	}
	public void addReview(Review r){
		// r.bookId を ID に使って Book を取得し
		// その参照を r.book に格納する
		if(r.getBookId() != 0)
			r.setBook(em.getReference(Book.class ,
				r.getBookId()));

		r.setDate(new Date());
		em.persist(r);
	}

	public void removeBook(int id){
		em.remove(em.getReference(Book.class , id));
	}
	public void removeReview(int id){
		em.remove(em.getReference(Review.class , id));
	}

	public void mergeBook(Book b){
		em.merge(b);
	}
	public void mergeReview(Review r){
		if(r.getBookId() != 0)
			r.setBook(em.getReference(Book.class ,
				r.getBookId()));
		em.merge(r);
	}
}

// Books.java
package com.yamicha.rs.server;

import java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement(name="booksRoot")
	public class Books implements java.io.Serializable{
	private List<Book> books;

	public Books(){
		books = new ArrayList<Book>();
	}
	public Books(List<Book> b){
		setBooks(b);
	}

	@XmlElement public List<Book> getBooks(){
		return books;
	}
	public void setBooks(List<Book> b){
		books = b;
	}
}

// Book.java
package com.yamicha.rs.server;

import javax.sql.*;
import javax.persistence.*;
import javax.xml.bind.annotation.*;
import java.util.*;

@Entity @Table(name="rest_book" , schema="yamicha") @XmlRootElement
	public class Book implements java.io.Serializable{
	private int id;
	private String title;
	private String author;
	private String publisher;
	private int price;
	private List<Review> reviews;

	public Book(){
		id = 0;
		reviews = new ArrayList<Review>();
	}
	public Book(String t , String a , String p , int i){
		this();
		title = t;
		author = a;
		publisher = p;
		price = i;
	}

	@Id @Column(name="id") @GeneratedValue @XmlElement
		public int getId(){
		return id;
	}
	@Column(name="title") @XmlElement public String getTitle(){
		return title;
	}
	@Column(name="author") @XmlElement public String getAuthor(){
		return author;
	}
	@Column(name="publisher") @XmlElement
		public String getPublisher(){
		return publisher;
	}
	@OneToMany(mappedBy="book" , cascade=CascadeType.ALL)
		@XmlElement public List<Review> getReviews(){
		return reviews;
	}
	@Column(name="price") @XmlElement public int getPrice(){
		return price;
	}

	public void setId(int i){
		id = i;
	}
	public void setTitle(String s){
		title = s;
	}
	public void setAuthor(String s){
		author = s;
	}
	public void setPublisher(String s){
		publisher = s;
	}
	public void setReviews(List<Review> l){
		reviews = l;
	}
	public void setPrice(int i){
		price = i;
	}
}

// Reviews.java
package com.yamicha.rs.server;

import java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement(name="reviewsRoot")
	public class Reviews implements java.io.Serializable{
	private List<Review> reviews;

	public Reviews(){
		reviews = new ArrayList<Review>();
	}
	public Reviews(List<Review> r){
		setReviews(r);
	}

	@XmlElement public List<Review> getReviews(){
		return reviews;
	}
	public void setReviews(List<Review> b){
		reviews = b;
	}
}

// Review.java
package com.yamicha.rs.server;

import javax.sql.*;
import java.util.Date;
import javax.persistence.*;
import javax.xml.bind.annotation.*;

@Entity @Table(name="rest_review" , schema="yamicha") @XmlRootElement
	public class Review implements java.io.Serializable{
	private int id;
	private String name;
	private String message;
	private Date date;
	private Book book;
	private int bookId;
	// bookId は XML 用のプロパティ
	// book をそのまま受け渡そうとすると循環参照になるため
	// book は @XmlTransient
	// bookId は @Transient にしてある

	public Review(){
		id = 0;
	}
	public Review(String n , String m){
		this();
		name = n;
		message = m;
	}
	public Review(String n , String m , int i){
		this(n , m);
		bookId = i;
	}

	@Id @Column(name="id") @GeneratedValue @XmlElement
		public int getId(){
		return id;
	}
	@Column(name="name") @XmlElement public String getName(){
		return name;
	}
	@Column(name="message") @XmlElement public String getMessage(){
		return message;
	}
	@Column(name="date") @XmlElement
		@Temporal(TemporalType.TIMESTAMP) public Date getDate(){
		return date;
	}
	@JoinColumn(name="book" , referencedColumnName="id")
		@XmlTransient
		public Book getBook(){
		return book;
	}
	@Transient @XmlElement public int getBookId(){
		return bookId;
	}

	public void setId(int i){
		id = i;
	}
	public void setName(String s){
		name = s;
	}
	public void setMessage(String s){
		message = s;
	}
	public void setDate(Date d){
		date = d;
	}
	public void setBook(Book b){
		book = b;
	}
	public void setBookId(int i){
		bookId = i;
	}
}
 もう少しまともな書評プログラムであれば、レビューを行うユーザーを登録制にしてUser.javaなどのEntityを作成し、それをReview.javaに持たせるなどした上、そのユーザーにしか編集・削除権を与えないようにすべきですが、RESTに関係のないコードがかなり増えてしまうため、その辺は省略しています。とはいえ、実装するのは必ずしも難しくはないでしょう。
 後はせいぜい、Reviewにおいて循環参照が発生しないように対処している程度です。

 後はクライアント側のプログラムを作成してアクセスすれば良いのですが、とりあえずブラウザで

(アプリケーションのURL)/restserver/book/regist

 これを開いてサンプルを登録し、さらに

(アプリケーションのURL)/restserver/book/books/Java
("Java"の部分は任意の語句。ただし、日本語などエンコードが必要な文字ならエンコードすること)

 これでキーワードに合致する書籍の一覧がXMLで取得できれば成功です。
カテゴリ [開発魔法][社会問題] [トラックバック 0][コメント 0]

再生腹案
2010/05/09(Sun)18:31:21
 小沢氏の問題に加え、今度は米軍基地移転問題に対する鳩山氏の迷走も重なり、民主党は危機的状況に陥っています。明らかに約束違反の格好となった基地問題について、鳩山氏は「自分の主張であって党の公約ではない」と主張し、失笑を買う有様です。今後も特に民主党に有利といえる材料はなく、鳩山氏への風当たりはますます強まっています。
 もし民主党がこの状況を一気に打開したいのであれば、体制の大変革を行うよりありません。民主党自体は決して能力のない政党ではなく、閣僚も必ずしも無能ではないはずですが、なぜここまで力が空回りするのかといえば、小沢氏の圧力と鳩山氏の迷走があるためです。これらの体制を何とかしない限り、民主党の活躍には期待できません。
 現在の民主党は「小沢独裁」と評されていますが、民主党の活力がなくなっているとすれば、それは小沢氏の責任に他なりません。2005年時点では消費税増税を公約していた民主党を、社会主義とも批判されるバラマキ政党にしてしまったのは小沢氏によるところが大きく、おかげで以前の民主党を支持していた人からは失望された上、実際に政権を取ってからは大混迷に陥る羽目になりました。
 しかも小沢氏は、高速道路の建設を指示しつつ料金値上げには怒るなど、非常に矛盾あるいは無理がある政策を閣僚に押し付け、閣僚は本来の力量を発揮できなくなっています。加えて、閣僚は子ども手当てなどの必要性が薄い政策に振り回され、その一方で年金改革など必要性・重要性の高い目玉政策は、話題にも上がらなくなっています。内閣の構成員が全く持ち味を発揮できないのですから、民主党政権がろくに成果を出せないのは当然というべきです。
 さらに、小沢氏に対して批判的な発言を行った生方氏は「誅殺」されるなど、まさに党内は独裁国家の様相を呈しています。これでは党内の活力がなくならないわけがありませんし、自浄作用にも期待できなくなります。その上、小沢氏は必死で地位にしがみつき、独裁者として好き勝手に振舞っていますが、そのとばっちりを食うのは末端の民主党議員なのです。
 また、鳩山氏は党首かつ首相でありながら小沢氏の独裁行為を容認する一方で、自身も「公約ではない」ことを勝手に言い出し、党や閣僚に多大な迷惑をかけています。首相が何か方針を打ち出せば、内閣としてもそれに沿った行動を取るよりありませんので、勝手な思いつきで無茶としか言いようがないことばかり決められては、内閣全体が振り回されてしまいます。これでは閣僚としても、まともに政治を行うどころではありません。
 したがって、民主党がまともな能力を取り戻すには、現行の混迷した体制の一新、すなわち鳩山氏と小沢氏に米軍基地やバラマキ問題などの責任を負わせて退陣させ、党首を若返らせる以外にありません。ある意味でトカゲの尻尾切りのようではありますが、実際にバラマキを主導したり、政治を混乱させたり、疑惑を持たれているのは小沢氏ですし、米軍基地問題で勝手なことを言い出したのは鳩山氏ですから、尻尾というよりは病巣を切除すると考える方が正解でしょう。
 党首が若返れば、若手や中堅から優秀な人間を選出してポストに就ける機会も増えるはずですし、何より自民党の旧体質を引きずっている体制が終焉することで、自民党とそのミニチュアしか存在しない政党集団から一足先に抜け出せます。この意義は非常に大きいといえるでしょう。
 その上で、ちょうど参院選で信を問えることを利用し、小沢氏の意向を汲んだバラマキ政策、鳩山氏が勝手に言い出した基地問題などをすべて見直し、バラマキによらない新たな政策を提示すれば、支持を回復する余地は十分にあります。
 特に子ども手当てはバラマキの代表格ですが、実際には子ども手当てにも功績はあります。諸控除の不公平さは以前からたびたび指摘されていますが、「子ども手当ての財源」の名目で控除の廃止を訴えていなければ、当面は既得権益として残っていたに違いありません。つまり、これを廃止した上で子ども手当ても撤回し、確保した財源を教育や育児支援に振り向けたり、現金支給も必要なところにピンポイントで行うようにすれば、矛盾した控除を廃止できる上に、子どもへの予算も増加します。このように、全体として見ると評価に値しなくても、一部を切り出せば評価できる政策もあり、完全に撤回して別の政策を作るより手間を削減できる上、受け入れられやすいはずですので、新しい政策を提示する環境も整っています。
 かつて小沢氏が大連立問題を起こした際、慰留すればどうなるかは分かっていたはずですし、党首選で鳩山氏を選べばどうなるかも分かっていたはずですが、関係者はそれを行ったために案の定の結果をもたらしました。そして今回、鳩山・小沢体制の一新がなければどうなるかは明らかです。仮に選挙に勝てたとしても、もう内閣は回らないでしょう。
 今の自民党は絶対安静状態にあり、とても政権を運営できる体調ではありませんし、かといって理念も何もないミニ自民党に権力を握らせるなど論外です。民主党が連立相手であるはずの国民新党や社民党にさえ苦慮しているのを見れば分かりますが、ここでミニ自民党がねじれ状態を起こそうものなら、日本にとってろくなことにならないのは見えています。しかし、小沢氏や鳩山氏の独裁や迷走に加え、子ども手当てなどのバラマキのせいで、民主党に支持が集まらないのです。
 現状では旧態依然とした自民党とミニ自民党が足の引っ張り合いをしており、それを国民もあきれて見ているなど、本来なら民主党にとってまたとない機会です。もしここで体制の変革ができず、あっさり自民党やミニ自民党の思惑にはまるとすれば、もはやお笑い種以外の何者でもありません。

 今回は前回に引き続き、簡易チャットの実装です。今回はRESTクライアント側を実装しています。
 実際には別にJavaで書く必要はなく、いかなる言語で書いても構いませんが、ここではJSF 2.0を使用しています。また、普通にページ変移でやり取りしても構いませんが、せっかく使用できるのですから、Ajaxを使用してみました。
 下線のあるファイル・ディレクトリが追加部分です。
/WEB-INF
 /classes
  /com
   /yamicha
    /rs
     /server
      @Path SimpleChat.java
      @Entity ChatMessage.java
      @XmlElement ChatMessages.java
      @Stateless ChatMessageAccess.java
     /client
      @ManagedBean ChatBean.java
  /META-INF
   persistence.xml
 web.xml
simplechat.xhtml
 データのXML化や復元、送信などはChatBean.javaで行っています。
package com.yamicha.rs.client;

import javax.faces.bean.*;
import javax.xml.bind.*;
import javax.xml.parsers.*;
import java.io.*;
import java.net.*;
import com.yamicha.rs.server.*;

@ViewScoped @ManagedBean public class ChatBean
	implements java.io.Serializable{
	private final static String REST_SERVER =
		"(アプリケーションの URL)/restserver/chat/";

	private String name;
	private String message;
	private ChatMessages messages;

	public ChatBean() throws Exception{
		readMessages();
	}

	public String getName(){
		return name;
	}
	public String getMessage(){
		return message;
	}
	public ChatMessages getMessages(){
		return messages;
	}

	public void setName(String n){
		name = n;
	}
	public void setMessage(String m){
		message = m;
	}
	public void setMessages(ChatMessages m){
		messages = m;
	}

	// 「発言」メソッド
	public void writeMessage() throws Exception{
		JAXBContext jc = JAXBContext.newInstance(
			ChatMessage.class);

		// /restserver/chat/write に送信
		HttpURLConnection c = (HttpURLConnection)
			new URL(REST_SERVER + "write").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(new ChatMessage(name , message) , os);

		os.close();

		InputStream is = c.getInputStream();
		is.read();
		is.close();

		c.disconnect();

		readMessages();

		message = "";
	}
	// 発言データの読み込み
	public void readMessages() throws Exception{
		JAXBContext jc = JAXBContext.newInstance(
			ChatMessages.class);

		// /restserver/chat/all を開く
		HttpURLConnection c = (HttpURLConnection)
			new URL(REST_SERVER + "all").openConnection();
		c.setRequestMethod("GET");
		c.setRequestProperty("Content-Type" , "application/xml");

		c.connect();

		InputStream is = c.getInputStream();

		Unmarshaller u = jc.createUnmarshaller();
		messages = (ChatMessages)u.unmarshal(is);

		is.close();

		c.disconnect();
	}
}
 言うまでもなく、writeMessage()が発言、readMessages()が発言データ読み込みのメソッドです。writeMessage()では発言データをXMLに変換して送信した後、readMessage()を使用して新しいデータを取得、さらにmessageフィールドを空にして、発言欄がクリアされるようにしています。
 simplechat.xhtmlは書き方次第でログインと会話を分けたりなども簡単にできるはずですが、ここではシンプルな実装としました。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<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">

<h:head>
  <title>JAX-RS SimpleChat Ajax</title>
</h:head>

<h:body>
  <b>JAX-RS SimpleChat Ajax</b>

  <h:form id="chatform">
    <h:inputText value="#{chatBean.name}" />:
    <h:inputText id="message" value="#{chatBean.message}" size="60" />
    <h:commandButton action="#{chatBean.writeMessage}" value="Say">
      <f:ajax execute="chatform" render="chatform:message :chatlog" />
    </h:commandButton>
  </h:form>

  <h:commandButton action="#{chatBean.readMessages}" value="Reload">
    <f:ajax render="chatlog" />
  </h:commandButton>

  <hr />

  <h:form id="chatlog">
    <ui:repeat value="#{chatBean.messages.messages}" var="message">
      <b>#{message.name}</b>: 
        #{message.message} - #{message.date}
      <hr />
    </ui:repeat>
  </h:form>
</h:body>

</html>
 リロードの場合に比べ、発言の場合はchatform:messageもAjaxで更新している(writeMessage()ではmessageを空にしているので、発言欄がクリアされる)点がチャットらしい部分ですが、それ以外は単純です。
 後は次のURLを開き、まがりなりにもチャットらしきものが動作すれば成功です。

(アプリケーションのURL)/simplechat.jsf

 見た目はただのぞんざいなチャットですが、実は裏でRESTが使われているという、手抜きなのか手が込んでいるのか分からないアプリケーションです。
カテゴリ [開発魔法][社会問題] [トラックバック 0][コメント 0]

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