yamicha.com's Blog - Presented by yamicha.com
Blog yamicha.com's Blog - 2018/12 の記事
[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] [31]

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
ブロッキング対策対策記事
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]
<- 前の記事を参照 次の記事を参照 ->

- Blog by yamicha.com -