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/01/18(Mon)00:27:51
 驚異的な発展を遂げつつある大国でありながら、未だに前時代的な厳しい検閲を続けており、各国から批判を浴びている中国ですが、ついにGoogle(現地名「谷歌」、「クーコー」と発音)が撤退をほのめかす事態となりました。Googleはすでに現地の検索エンジン「百度」に次ぐシェアを誇っており、非常に影響力の大きい企業であるだけに、中国政府としても神経を尖らせているようです。
 中国政府は厳しいインターネット検閲を導入しており、政府にとって都合の悪い情報を遮断したり、活動家らの通信を監視する上、参入してくる外資系企業には「協力」を求めるなど、ありとあらゆる手段で情報統制を実行しています。また、「金盾」といった強力な検閲システムの開発も進められており、総書記の胡氏はインターネット規制の甘さに不満をもらすなど、インターネットの自由がなおさら強く制限される可能性すら考えられる状況です。
 こうした政府の検閲を嫌う中国人は、内容が秘匿できない中国のメールアカウントではなく、Gmailなどの欧米のメールアカウントを使用し、通信内容の秘匿を図ろうとする傾向にあります。ところが、このほど中国人権活動家らのGmailアカウントが大規模なクラッキングを受けたというのです。
 クラッカーの正体や目的は不明ですが、中国政府が主導して攻撃を行っている可能性があるとされています。当然ながら中国側はこれを否定し、表面上は協力的な発言を行っていますが、実際に中国政府が本件を主導していたとしても、中国の体質からして全く不思議なことではありません。Googleが「撤退」を言い出した原因の1つとして、本件があることはおそらく間違いないでしょう。
 Googleは対抗措置として「協力」を一部解除し、今まで中国版Googleでは閲覧できなかった一部の情報を閲覧可能としました。Googleが中国政府をけん制し、譲歩を引き出すために「撤退」を言い出したのか、あまりの検閲のひどさに3億人市場を本気で捨てる覚悟をしているのかは定かではありませんが、ともかく現在の中国の言論統制が許されざるものであるのは言うまでもなく、悲観的な見方も決して少なくないながらも、本件が「アリの一穴」となることを期待します。
 かつて東欧の国々が連鎖的に民主化した際には、テレビの力も大きかったとされています。国家がどれほど情報を規制しようとも、海外から電波に乗って入ってくる情報まで統制することはできず、国民はリアルタイムに国外の情報を入手できたため、これが連鎖的な民主化の一助になったというのです。
 それからおよそ四半世紀後の現代においては、世界各国で瞬時にして情報の共有が可能なインターネットが普及し、より早く容易に様々な情報が手に入る時代となりました。現在の中国と東欧革命時の諸国とでは状況も違い、あれほどの成果を望むのは難しいとはいえ、少なくとも中国政府がインターネットの力に脅威を感じているのは確かです。「テレビの力による民主化」の次の世代では、果たして「インターネットの力による民主化」は実現されるのでしょうか。

 ところで、中国にインターネットの自由が存在しないのは前述の通りですが、中国政府がGoogleのメールなどへの接続を遮断したり、インターネット規制を強化するための方便として、次のような言葉が良く使われています。

「Googleがポルノ情報を流している」
「わいせつな有害情報を広める行為を取り締まる」

 以前の記事で日本での児童ポルノ規制問題を取り上げましたが、中国のケースは「有害情報の規制」の御旗が政府や捜査権力の力を強める結果となることを非常に明確に示す実例です。ただ、これが単に政府の権力行使の言い訳として使われている分には、まだ問題が大きいとはいえません。最も問題なのは、この御旗が絶対的な正義として担ぎ出されてしまった場合です。
 大変残念なことですが、各種詐欺やチェーンメールの中には、他人の善意を利用したものが少なからず存在しています。このほどハイチで発生した大地震に関しても、早くも便乗した詐欺の発生が確認されているそうです。うっかりこの種の詐欺やチェーンメールに引っかかると、自分では善意で行動を起こしたつもりでも、他人に迷惑をかけてしまったり、詐欺師に原資を提供してしまう結果ともなりかねません。
 また、以前に「スマイリーキクチ事件」なるものが発生したことがありました。これは「タレントのスマイリーキクチ氏がコンクリート詰め殺人事件にかかわっていた」なる事実無根のデマが流布され、結果として氏が悪質な脅迫や名誉毀損を受けたもので、氏にとっては迷惑以外の何者でもない事件です。しかし、加害者の中には遊び半分の者も多かったとみられますが、中には本気でこの情報を信じてしまい、正義感に基づいてキクチ氏への攻撃を行っていた者も存在したのではないでしょうか。このように、「正義感の暴走」は時として逆方向に作用し、大変望ましくない結果をもたらします
 児童ポルノ規制問題にも、この懸念は当てはまります。確かに、実写の児童ポルノには確実に被害者が存在しますので、作成は到底容認できるものではありません。また、不特定多数への流布によって被害が際限なく拡大していくため、流通を抑制する仕組みも望まれるのは言うまでもありません。これらの点に関しては、おそらくほとんどの人が同意されるのではないでしょうか。
 しかしながら、ここで児童ポルノの規制に「善意」や「正義」を見出してしまうと、単純所持規制の多大な弊害も忘れ、単純所持規制を徹底することこそ正義という錯覚に陥ってしまいかねません。これがいかなる危険をはらんでいるかは、中国の状況を見れば明らかでしょう。「わいせつな有害情報を広める行為を取り締まる」との御旗の下に、国民の自由が取り締まられてしまうのです。
 さらに、児童ポルノ問題に強い怒りと問題意識を覚え、規制こそ正義であるとの錯覚に陥った状態では、「児童ポルノを見ると犯罪を起こす」「創作画像の児童ポルノにも同様の効果がある」などといった全く事実無根のデマでさえ、スマイリー事件のデマ同様に信じ込んでしまう恐れがあります。情報を注意深く分析さえしていけば、この程度のデマになど大抵は気づけるはずなのですが、錯覚に陥った状態ではそこまでの分析は難しいどころか、規制こそ正義で反対者は反正義とまで思い込むに至り、理性的な反論さえも感情論によって否定されてしまう事態ともなりかねません。児童ポルノ規制を情報統制の面から懸念している人に対して「それは言い訳にならない。被害者の苦痛が分からないのか」と理由も根拠もない感情論で反論したり、果ては「反対者は児童ポルノ愛好家」などと事実無根の偏見に基づく主張を始めるなど、人格否定に結びつく場合すらあります。
 今の日本にはインターネットの自由がありますが、中国の一件は決して遠い世界の出来事ではありません。民主党は単純所持の規制に消極的ですが、自民党はかなり積極的に単純所持を禁止しようとしており、さらには創作物をも規制する動きも一部に存在しています。今後自民党が政権を取り返す可能性は十分にありますし、そうでなくてはならないと私も考えていますが、ともかく日本でも単純所持や創作物も含めた規制が導入される可能性は目の前に存在するのです。
 その上、マスコミの一部や規制を主張する団体などは、すでに単純所持も含めた児童ポルノ規制を「絶対的正義」であるかのように報じており、信じ込んでしまう人も出かねない状況です。また、規制の範囲や方法はともかくとして、児童ポルノを何らかの形で規制する制度自体の必要性については、おそらく多くの人の見解の一致するところですので、情報統制の懸念を抱く者でも規制自体には反対しないという、一見すると分かりづらい構図ともなっています。これらのことから、今後決して遠くないうちに、主に情報統制への危機感が薄い人を中心として「正義感の暴走」が発生し、そのまま危険な規制の制定にまで至る可能性は十分にあります。しかし、それがいかなる結果を招くかといえば、中国が非常に分かりやすい実例を示してくれています。
 そのような意味で、中国の一件は日本にも大きな教訓を与えているといえるでしょう。

 JPA 2.0で新しく追加されたアノテーションに、@MapKeyColumnや@MapKeyJoinColumnがあります。Wikibooksの説明によれば、@OneToManyなどのプロパティに対してこれらを付加すると、それらのデータをMapとして扱えるようになるものであるようです。すなわち、通常の@OneToManyではListやSetなどのコレクション、あるいは配列が使用され、要素を順次取得できる一方、@MapKeyColumnや@MapKeyJoinColumnではキーを基に値を取得できる模様です。私は使ったことがありませんが、@MapKeyなるものは1.0から存在しているようで、似たようなものかもしれません。
 Wikibooksのサンプルでは、「従業員の所有する電話の種類」がキーとして用いられています。「phones.get("WORK")」なら仕事用の電話番号データを記録したエンティティのインスタンスが取得でき、「phones.get("CELL")」なら携帯電話のデータのインスタンスといった具合です。
 実際にこれを使うべき状況は、かなり限定されるのではないでしょうか。基本的に以下の2つの要件を満たさなくては、わざわざ@MapKeyColumnや@MapKeyJoinColumnを使う必要性に乏しいためです。

1.複数のキーに対し、必ず値が割り振られるとは限らないこと。あるいは、作成時点ではいかなるキーが使用されるか分からないこと。
 電話の例で言えば、もし最初から「仕事場」「自宅」「携帯電話」の3種類の電話番号データの登録が必要であると分かっているなら、work,home,cellの3つのプロパティを記述し、それぞれを@OneToOneにすれば済む話であり、いちいち本機能を使用する必要はありません。
 本機能を使用するのであれば、後から区分が増える可能性がある場合(例えば「事務所」「個人用携帯電話」「緊急連絡先」など)、あるいは区分が大量に存在し、しかも大抵はその大半がnullとなり、わざわざ@OneToOneプロパティを大量に書くと逆に非効率的な場合などになるでしょう。

2.キーが重複しないこと。
 Mapの仕様上当然です。電話の場合であれば、仕事用、固定、携帯電話などの番号データを各1つずつしか持たないのが原則となります。携帯電話を2つも3つも持っている場合、わざわざ「CELL1」「CELL2」などと名づけるのは、分かりづらい上に非効率的です。

 @MapKeyColumnと@MapKeyJoinColumnの違いは、キーの扱い方にあります。@MapKeyColumnの場合は、次のようなテーブルが生成されます。
employee
id	fname	lname
1	Larry	Wall
2	Ada	Lovelace
3	Agner	Erlang

phone
id	empid	type	number
1	1	home	11111
2	2	work	22222
3	2	cell	33333
4	3	home	44444
5	3	cell	55555
 この場合、例えばAdaの電話番号Mapから"cell"を取得すると、phoneテーブルのid = 3にあたるデータのインスタンスが得られます。
 @MapKeyJoinColumnの場合は以下のようになります。
state
id	name
1	StateA
2	StateB
3	StateC

position
id	name
1	Governer
2	PosA
3	PosB

officer
id	state	pos	name
1	1	1	Haskell Curry
2	1	2	Ada Lovelace
3	2	1	Agner Erlang
4	3	1	Grace Pascal
5	3	3	Larry Wall
 この場合、キーはpositionにあたるエンティティのインスタンスです。

 どちらかといえば@MapKeyJoinColumnの方に目新しさがあるため、今回はひとまず@MapKeyJoinColumnを使用してみました。@MapKeyColumnより若干面倒ですが、割と簡単な部類です。
/WEB-INF
 /classes
  /com
   /yamicha
    /mapkeyjoin
     Office.java
     Account.java
     Value.java
     MapKeyJoinAccess.java
     MapKeyJoinServlet.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は以下の通り実装しました。
// Office.java
package com.yamicha.mapkeyjoin;

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

@Entity @Table(name="mapkeyjoin_office" , schema="yamicha")
	public class Office implements java.io.Serializable{
	private int id;
	private String name;
	// 今回はサンプルにつき資産(asset)のみ
	private Map<Account , Value> assets;

	public Office(){
		assets = new Hashtable<Account , Value>();
	}
	public Office(String n){
		this();
		name = n;
	}

	@Id @GeneratedValue @Column(name="id") public int getId(){
		return id;
	}
	@Column(name="name") public String getName(){
		return name;
	}
	@OneToMany(mappedBy="office" , fetch=FetchType.EAGER ,
		cascade=CascadeType.PERSIST)
		@MapKeyJoinColumn(name="account")
		public Map<Account , Value> getAssets(){
		return assets;
	}

	public void setId(int i){
		id = i;
	}
	public void setName(String n){
		name = n;
	}
	public void setAssets(Map<Account , Value> a){
		assets = a;
	}

	public void link(){
		for(Value v : assets.values())
			v.setOffice(this);
	}
}

// Account.java
package com.yamicha.mapkeyjoin;

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

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

	public Account(){
	}
	public Account(String n){
		name = n;
	}

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

	public void setId(int i){
		id = i;
	}
	public void setName(String n){
		name = n;
	}
}

// Value.java
package com.yamicha.mapkeyjoin;

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

@Entity @Table(name="mapkeyjoin_value" , schema="yamicha")
	public class Value implements java.io.Serializable{
	private int id;
	private int price;
	private Office office;
	private int account;

	public Value(){
	}
	public Value(int p){
		price = p;
	}

	@Id @GeneratedValue @Column(name="id") public int getId(){
		return id;
	}
	@Column(name="price") public int getPrice(){
		return price;
	}
	@ManyToOne @JoinColumn(name="office") public Office getOffice(){
		return office;
	}
	@Column(name="account") private int getAccount(){
		return account;
	}

	public void setId(int i){
		id = i;
	}
	public void setPrice(int p){
		price = p;
	}
	public void setOffice(Office o){
		office = o;
	}
	private void setAccount(int a){
		account = a;
	}
}
 Value.javaにint accountプロパティを書かない場合、EclipseLinkが例外を投げてきます。しかし、普通に考えて書く必要のある代物には見えないため、JPA 2.0の仕様で要求されているものかは不明です。しかもデプロイ時にテーブルはしっかり生成され、デプロイ自体にも成功するものの、クエリを発行する段階で初めてエラーを出してくるという謎の挙動を見せてくれます。
 いつもながらいい加減ですが、Servlet/EJBは以下の通りです。
// MapKeyJoinAccess.java
package com.yamicha.mapkeyjoin;

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

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

	public void regist(){
		// まず科目を作成
		Account cash = new Account("現金");
		Account checking_account = new Account("当座預金");
		Account accounts_receivable = new Account("売掛金");
		Account notes_receivable = new Account("受取手形");
		Account product = new Account("製品");
		Account equipment = new Account("備品");
		Account goodwill = new Account("のれん");

		// 登録
		em.persist(cash);
		em.persist(checking_account);
		em.persist(accounts_receivable);
		em.persist(notes_receivable);
		em.persist(product);
		em.persist(equipment);
		em.persist(goodwill);

		// 各オフィスに科目ごとの金額を登録
		// 北朝鮮支店
		Office dprk = new Office("北朝鮮支店");
		dprk.getAssets().put(cash , new Value(150000));
		dprk.getAssets().put(checking_account ,
			new Value(1750000));
		dprk.getAssets().put(accounts_receivable ,
			new Value(350000));
		dprk.getAssets().put(notes_receivable ,
			new Value(800000));
		dprk.link();
		em.persist(dprk);

		// ミャンマー支店
		Office myanmar = new Office("ミャンマー支店");
		myanmar.getAssets().put(cash , new Value(640000));
		myanmar.getAssets().put(checking_account ,
			new Value(4000000));
		myanmar.getAssets().put(accounts_receivable ,
			new Value(500000));
		myanmar.getAssets().put(goodwill , new Value(720000));
		myanmar.link();
		em.persist(myanmar);

		// 阿久根支店
		Office akune = new Office("阿久根支店");
		akune.getAssets().put(cash , new Value(75000));
		akune.getAssets().put(checking_account ,
			new Value(1800000));
		akune.getAssets().put(product , new Value(1500000));
		akune.getAssets().put(equipment , new Value(9800000));
		akune.link();
		em.persist(akune);
	}
	public List<Office> getOffices(){
		return (List<Office>)em.createQuery(
			"SELECT o FROM Office o").getResultList();
	}
	public Office getOffice(Object id){
		return em.find(Office.class , id);
	}
}

// MapKeyJoinServlet.java
package com.yamicha.mapkeyjoin;

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="mapkeyjoinservlet" , urlPatterns={"/*"})
  public class MapKeyJoinServlet extends HttpServlet{
  @EJB(beanName="MapKeyJoinAccess") private MapKeyJoinAccess ma;

  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();

    ma.regist();

    List<Office> offices = ma.getOffices();
    for(Office o : offices){
      out.println(o.getName());

      Map<Account , Value> assets = o.getAssets();
      for(Map.Entry<Account , Value> e : assets.entrySet()){
        out.println("t" + e.getKey().getName() + ": " +
          e.getValue().getPrice());
      }
      out.println();
    }

    out.close();
  }
}
 これを実行してみると、次の結果が表示されました。
北朝鮮支店
	受取手形: 800000
	現金: 150000
	売掛金: 350000
	当座預金: 1750000

ミャンマー支店
	のれん: 720000
	現金: 640000
	売掛金: 500000
	当座預金: 4000000

阿久根支店
	備品: 9800000
	製品: 1500000
	現金: 75000
	当座預金: 1800000
 テーブルは以下の通りです。
mapkeyjoin_account
+------+----------+
| id   | name     |
+------+----------+
| 8751 | 現金     |
| 8752 | 当座預金 |
| 8753 | 売掛金   |
| 8754 | 受取手形 |
| 8755 | 製品     |
| 8756 | 備品     |
| 8757 | のれん   |
+------+----------+

mapkeyjoin_value
+------+---------+---------+--------+
| id   | price   | account | office |
+------+---------+---------+--------+
| 8759 |  350000 |    8753 |   8758 |
| 8760 |  150000 |    8751 |   8758 |
| 8761 |  800000 |    8754 |   8758 |
| 8762 | 1750000 |    8752 |   8758 |
| 8764 |  500000 |    8753 |   8763 |
| 8765 |  640000 |    8751 |   8763 |
| 8766 | 4000000 |    8752 |   8763 |
| 8767 |  720000 |    8757 |   8763 |
| 8769 | 9800000 |    8756 |   8768 |
| 8770 |   75000 |    8751 |   8768 |
| 8771 | 1800000 |    8752 |   8768 |
| 8772 | 1500000 |    8755 |   8768 |
+------+---------+---------+--------+

mapkeyjoin_office
+------+----------------+
| id   | name           |
+------+----------------+
| 8758 | 北朝鮮支店     |
| 8763 | ミャンマー支店 |
| 8768 | 阿久根支店     |
+------+----------------+
カテゴリ [開発魔法][社会問題] [トラックバック 0][コメント 0]
<- 前の記事を参照 次の記事を参照 ->

- Blog by yamicha.com -