count - みる会図書館


検索対象: UNIX MAGAZINE 2002年5月号
7件見つかりました。

1. UNIX MAGAZINE 2002年5月号

連載 /JavaServer Pages— public class Counter2 { import Java. iO. * ; package counter ; 図 5 ファイルを不したアクセスカウンタのソースコード (Counter2. java) saveCounter (count) ; count 十十 ; return count ; if ( (count=readCounter() ) く 0 ) { int count ; public int getVa1ue ( ) counterFi1e public void setFi1e(String f) public Counter2() private String counterFi1e = nu11; int readCounter ( ) try { int pr ivat e count tokenizer . TT NUMBER) { if (tokenizer . nextT0ken() StreamTokenizer tokenizer = new StreamTokenizer (reader) ; InputStreamReader reader = new InputStreamReader (istream) ; FiIeInputStream istream new Fi1eInputStream(counterFiIe) ; count } else { C ount (int)tokenizer. nva1 ・ reader. close() ; try { private VOid saveCounter(int c) return count ; } catch (IOException e) { } catch (UnsupportedEncodingException e) { } catch (SecurityException e) { } catch (Fi1eNotFoundException e) { OutputStreamWriter writer = new OutputStreamWriter (ostream) ; FiIeOutputStream ostream = new Fi1eOutputStream(counterFiIe) ; } catch ( 工 OException e) { catch (UnsupportedEncodingException e) { catch (SecurityException e) { catch (Fi1eNotFoundException e) { writer. close() ; writer. write(lnteger. t0String(c) + " \ Ⅱ " ) ; 122 UNIX MAGAZINE 2002.5

2. UNIX MAGAZINE 2002年5月号

連載 JavaServer Pages—O 図 7 同時アクセスがするとアクセス数の里を誤る ① 1 人目のアクセスカウンタ値 readCounter() count 十十 saveCou nter() カウンタ値 ② 2 人目のアクセス -1- CV 1 -1 ・ワ」 CV readCounter() count 十十 ー saveCounter() 2 2 図 8 排他里を追加した Counter2 クラスの getValue() public int getVa1ue ( ) int count このとき、 2 人目のアクセスによる処理が readC 。 unt ー er() を実行し終えたとします。 1 人目のアクセスによるカ ウンタ値はまだアクセスカウンタのファイルに保存されて いないので、 2 人目がアクセスしたときも readCounter() カ芍区す値は、、 1 " です。したがって、、、 count 十十 " を実行 したあとの 2 人目のカウンタ値も 2 です。 このように、 getVaIue() か 1 司時に実行されると、タイ ミングによっては複数の人に同じアクセスカウンタ値を表 示してしまいます。 さらに、 1 人目がアクセス数をファイルに保存するとき には正しく、、 2 " 呆存されますが、 2 人目はもともと正し いアクセス数を取得できていないので、ファイルにも誤っ は、 synchronized のプロックに入るときに、 object が た値である、、 2 " を保存します。 ロックされていないかどうかを卩十ヾ、 このように、図 5 のコードでは、同時アクセスが発生し ・ロックされていなければ、ロックして、、排他的に実行 たときにアクセス数をカウントしそこねる可能生がありま されるコード " を実行 す ( 図 7 ) 。 ・ロックされていればロックカ埆早除されるまで待つ synchronized というように重川します。 この不具合を解決するためには、 1 人目のアクセスカワ これを利用して、 getVaIue() メソッドを書き換えてみ ァイルからアクセス数を読み出してふたたびファイルに保 ましよう。図 8 は、アクセス数を読み込む readCount- 存するまで、 2 人目のアクセスがファイルからアクセス数 er() から、保存する saveCounter() の呼出しまでを排他 を読み出さないようにする必要があります。 的に処理するように書き換えたコードです。 ーー級にこのような処理 ( 里と呼ばさまざまな synchronized でロックするオプジェクトは、 1 人目の 手法があります。 Java ではオプジェクトをロックして排 アクセスでも 2 人目のアクセスでも、同一のものが参照さ 他処理を寒見する方法を言言」として提供しています。 れるオプジェクトであればなんでもかまいません。ここで は、、、 this " オプジェクト、すなわち jsp:useBean で生成 synchronized ( 0 り ec の { した ac オプジェクトを使いました。 排他的に実行されるコード ただし、 ac オプジェクトが page スコープなどの叩ー synchronized (this) { if ( (count=readCounter() ) くの { count 十十 ; saveCounter (count) ; return count ; 125 UNIX MAGAZINE 2002.5

3. UNIX MAGAZINE 2002年5月号

連載 /JavaServer Pages— tiate(this. getC1ass() . getC1assLoader() , r. Counter1") ; は、 Beans クラスの instantiate() メソッドを使って、 counter ℃ ounterl クラスのオプジェクトを生成していま す。このコードは、クラスか存在しないなどの理由でオプ ジェクトの生成に失敗したときに、コンパイルエラーでは なく例外か発生することを除けは次のコードと同じです。 ac = new counter. Counterl() ; アクセスカウンタ・オプジェクトの生成に成功すると、 16 行目に制御が移り、生成したオプジェクトを page- 'counte ・ setAttribute() ・ getAttribute() です。ただし、 定した場合でも、変換後の Java の実装は基本的には同し jsp:useBean タグで application 以タトのスコ プジェクトは次回以降のアクセスで参照されます。 Context に保存します。すでに説明したとおり、 ープを指 このオ 今回はファイルの入出力処理を含むため、 Counter1. java 保存する Java のソースコード、、 Counter2. java" です。 図 5 は、ファイルを利用してアクセスカウンタの値を アクセスカウンタ JavaBean ( その 2 ) スカウンタを作り、 JSP ファイルから呼び出してみまし るために、アクセス数をファイルに保存するようなアクセ 保存していたアクセス数を忘れてしまいます。これを避け ト述のアクセスカウンタは、 Web サーバーを止めると ファイルを利用したアクセスカウンタ スコープになります。 に渡すスコーフ窈旨定が、 jsp:useBean タグて指定された UNIX MAG AZINE 2002.5 ・ value プロバティの値を取得するメソッド (getVal- ・用 e プロバティの値を設定するメソッド ・引数をもたないコンストラクタ Counter2 クラスは、 よりはすこし複雑です。 (setFile()) をもつ JavaBean です。 setFile() は、アクセス数尉寺するファイルのパスを 設定するメソッドです。引数として渡されたファイルのパ スは counterFiIe 変数に保存さアクセス数の取得など の目的でファイルにアクセスするときに参照されます。 getValue() はファイルに保存されていたアクセス数 ではなく、現在 ( 更新後 ) のアクセス数を返します。 get- Value() の内部では次の処理をおこないます。 1. readCounter() を呼び出し、ファイルに保存されてい たアクセス数を count 変数に設定する。 2. readCounter() はエラーの発生時には負の値を返すの で、その場合はそのままメソッドを抜ける。 3. count 変数の値を 1 増やし、今回のアクセスぶんをア クセス数に反映させる。 4. saveCounter() を呼び出し、更新後の ( 新しい ) アクセ ス数をファイルに保存する。 5. メソッドの戻り値として更新後のアクセス数を返す。 アクセス数をファイルから読み込んだり、ファイルに 保存する処理は、 readCounter() と saveCounter() で おこなっています。 readCounter() のコードを追ってみましよう。 read- Counter() では counterFile をオープンし、読み込んだ 値か数字列であればその値を返します。 counterFile の読 込みに失敗したり、数字 : 列以外の値が保存されている場合 には、言ムみに失敗したことを意味する負の値 ( ー 1 ) を返 します。 saveCounter() のコードでは、 counterFile を書込み 用にオープンし、引数として受け取ったアクセス数を書き 込んでいます。 こまでで、アクセスカウンタ JavaBean の処理は理 解できたでしようか。続いて、この JavaBean を呼び出 す JSP ファイルについてみていきます。 jsp:useBean タクの本体 図 6 は、アクセスカウンタとして Counter2 クラス を使う JSP ファイル、、 counter2. jsp" です。これまでみ てきた jsp:useBean タグとの大きな違いは、タグに本体 ( b 。 dy ) があることでしよう。 jsp:useBean タグは、 121

4. UNIX MAGAZINE 2002年5月号

連載 /JavaServer Pages— public void init ( 引数 1 , 引数 2 , public Abc() 引数 1 , 引数 2 , ・・・に関する処理 Abc クラスを呼び出す JSP ページの書き方の違いもみ てみましよう。 もとの引数付きのコンストラクタの場合、 jsp:useBean タグは利用できないので、オプジェクトを作るときにはス Abc d = new Abc( 引数 1, 引数 2 , く % クリプトレットを使います。 プジェクトを作る JSP のスクリプトレットのコードは次 作り替えた JavaBean 版の Abc クラスを使うと、オ d. init ( 引数 1 , 引数 2 , Abc d = new Abc(); く % のようになります。 124 •-s jsp:useBean の本体をスクリフ counter2. jsp のように スするメソッドとして書き換えられるのなら、図 6 の もし、 init() メソッドの部分をプロバティにアクセ く /jsp:useBean> d. init( 引数 1, 引数 2 , く % く Jsp:useBean id="d" c1ass="Abc" scope= Bean タグを使って書き換えると、次のようになります。 そこで、上記のスクリプトレットのコードを jsp:use- か、あるいはこれらの組合であってもかまいません。 ・文字列 ・ HTML のタグ ・式タグ ・スクリプトレット 体に言当する内容は、 体に jsp:setProperty タグを使っていますが、タグの本 図 6 の counter2. jsp の例では jsp:useBean タグの本 トレットではなく、 jsp:setProperty などのプロバティを 操作するタグに置き換えることもできます。 また、 く Jsp:useBean id="d" cIass="Abc" scope="session" > く b > セッション開始 ! く /b> く br> d. init( 引数 1, 引数 2 , く % 排イ也処理 ザに表示します。 セスしたときだけ、 く /jsp:useBean> セッション開始 ! " の文字列をプラウ のような JSP コードは、同一のセッションて初めてアク readCounter() で読み込んだ値が、、 1 " だったとします。 たとえは、 1 人目のユーサーがアクセスしたときに return count ; saveCounter (count) ; C ount 十十 ; return count ; if ( (count=readCounter ( ) ) くの { int count ; public int getVa1ue ( ) コードを見てみましよう。 ここでもう一度、 Counter2 の getValue() メソッドの クラスの処理か 1 司時に実行されます。 のページに複数の人が同時にアクセスすると、 Counter2 セス要求を並列に処理します。したがって、 counter2 ・ jsp 通常、 Web サーバーは受け取った Web ページへのアク きるのか JSP ページに同時にアクセスしたとき何が起 ります。 も Web のプログラミングにありがちな大きな不具合があ ここて紹介した 2 不鶤頁のアクセスカウンタには、いずれ によって 1 人目のカウンタ値は、、 2 " になります。 count 十十・ すると、 UNIX MAGAZINE 2002.5

5. UNIX MAGAZINE 2002年5月号

連載 /JavaServer Pages—O 図 9 sleep() を追加した不具合のあるコード public int getVa1ue ( ) int count return count 十十 ; try { Thread . sleep ( 5000 ) ; count ; if ( (count=readCounter()) return count ; saveCounter (count) ; } catch (Exception e) { くの { 図 10 counter3. jsp の表祚果 上日 n 版カウンタにの 3 ) ー Netscape 6 ードの E'•をな 1 ′第を ロロコ讐 1 めト : 発 7 ( 5 物前 アクセス数 : 60 排他処理を行っていないカウンタ ホム検索ロプめマーり、を“ 0 籌新着、お勧め、メンバーズ 0 - ファイル ( E ) 編集 ( 日表示検索ジャンプ 0 ブックマーク ( 印タスク (I) ヘルプ ( 印 ーホーム検素うカクマゆ、いを” 0 新着・、おを籌メントオ ~ ファイルの編集 ( 印表示検索ジャンプ 0 プめマーり ( 印タスクヘルフ凹 ロ。ー : ~ ュメント : 発了 ( 5 物 アクセス数 : 60 排他処理を行っていないカウンタ 第同 plication 以外のスコープをもつ場合は、 1 人目のアクセ スと 2 人目のアクセスで、、 this " の実体が違うかもしれな いので、ロックするオプジェクトには別のものを選ぶ必要 排他里の確認 があります。 126 サから 5 秒以内に連続して counter3. jsp にアクセスする を使った、、 counter3. jsp" の表示結果です。 2 つのプラウ 図 10 は、図 9 のコードを組み込んだアクセスカウンタ 示されるはすです。 る不具合が発生し、 1 回目と 2 回目で同じアクセス数カ俵 あいだに別のアクセスが発生すると、アクセス数を間違え この細工によって、アクセス数を処理している 5 秒の 日判勺に停止 ) するようにしました。 Counter() メソッド ) の直前で、 5 秒澗 sleep ( 処理を一 ッドです。ファイルにカウンタ値を保存する処理 (save- 図 9 は、排他処理をおこなっていない getVaIue() メソ まずは、不具合が発生するほうのコードに細工しましょ することです。 し細工し、現象カ起きやすいようにしたうえて動作を石忍 このようなケースでの常套手段は、ソースコードにすこ のか容易には石忍できません。 は、ソースコードの不具合を修正しても正しく動いている うかがタイミングに依存し、現象を再現しにくいケースで アクセスカウンタの例のように、不具合が起きるかど ましよう。 排他処理か期待どおりに動いているかどうか確かめてみ と、図のようにアクセス数か 1 司しになります。 図 11 は、排他処理をおこなったうえで 5 秒間 sleep するようにした getValue() メソッドです。このアクセ スカウンタのコードでも、 1 回目のアクセスから 5 秒以 内に 2 回目のアクセスがあると、同し時刻 ( 時間帯 ) に getValue() の実行か重複します。しかしこのケースでは、 あとからコードを実行しようとしたアクセスが synchr 。ー nized のプロックの直前て待たされます。 その結果、 1 回目のアクセスがファイルにアクセス数を 書き込んだあとでないと、 2 回目のアクセスはファイルか らアクセス数を読みにいかないので、アクセス数は正しく カウントされます。結果として、 2 つの Web プラウサ上 にはそれぞれがアクセスした時点のアクセスカウンタの値 が正しく表示されます ( 図 12 ) 。 Jsp:useBean のお也里 排他処理は、 jsp:useBean を変換した Java プログラ ムのなかでもおこなわれています。 図 13 は、図 4 と同じく jsp:useBean タグを変換した Java のソースコードの一部です。 synchronized プロックは、 ・ pageContext に保存したオプジェクトを取得する ・ pageContext にオプジェクトを保存する という処理が同一アプリケーションにおいて排他的に実行 されることをイ正します。 もし、この部分の処理が排他的に実行されなかった場 合に何カ起きるのカ甘隹測してみましよう。たとえは、 JSP ページへの初めてのアクセスが同時に発生したとします。 UNIX MAGAZINE 2002.5

6. UNIX MAGAZINE 2002年5月号

連載 /JavaServer Pages—@ 図 11 sleep() を追加した不具合を修正しているコード public int getVa1ue ( ) int c ount synchronized (this) { if ( (count=readCounter() ) return count ; count 十十 ; try { Thread. sleep ( 5000 ) ; } catch (Exception e) { saveCounter (count) ; return C ount ; 図 13 jsp:useBean タグの非他タ里 くの { 図 12 正しく表示されたアクセスカウンタ ムファイル ( E ) 編集 ( 印表示検常 ) ジャンプ 0 ブッりマり ( 印タスりヘルプ旧 ) 物匪仮カウンタ ( その 4 ) ー Netscape 5 ロロ雪コュメ : 完了 00 け ) リアクセス数 : 64 排他虹理を行っているカウンタ 、働ホーム、検常ロカりマーり、 t 師物 536 ”、新着、お都助、メントズ 方イル住編果 ( 印表示検索ジャンプ 0 ブッりマーり ( 印タスクへルプ ( 印 アクセス数 : 63 排他処理を行っているカウンタ 」木ーム検索朝ブッりマーり第物引聞ー鷭。、新著籌お都助、メントズ ロ X ロ X / / begin [file="/counterl . jSP";fr0m=(11,0);t0=(11,66)] counter . Counter1 ac Ⅱ u11 ; -jspx-specialac true ; ← true なら jsp:useBean の本体の処理を実行する if ( ac = Ⅱ u11 ) { pageContext . getAttribute ( "ac" ,PageContext. APPLICATION—SCOPE) ; ac= (counter . Counterl) synchronized (application) { false; boolea 取 -Jspx—specialac (counter. CounterI) java. beans . Beans . instantiate(this . getCIass() . getCIassLoader() , "counter . Counter1") ; pageContext . setAttribute ( ac , すると、別々のアクセスによって実行される 2 系統の処 理の両方が、 getAttribute() で null を受け取ります。次 の if 文のなかのコードも重複して実行さ新しく生成さ れた 2 つのオプジェクトが、 pageContext 内に同し名前 て保存されます。 その結果、 ・アクセス回数を 1 回数えそこなう ・ jsp:useBean の本体の処理が 2 回実行されてしまう ・生成した 2 つのオプジェクトの一方しか保存されない ( 最初に保存されたオプジェクトは 2 番目に保存された オプジェクトに上書きされて失われる ) といったさまざまな問題カ吽します。 UNIX MAGAZINE 2002.5 PageContext . APPLICATION_SCOPE) ; このように、 Web のアプリケーションでは処理か並列 に実行されることを ; 頁におき、共通のデータを読み書き するときは必要に応して排他処理を組み込まなくてはなり ません。 ☆ 今回は、 JavaBean を生成する jsp:useBean タグのす こし詳しい説明から発展して、 JavaBean オプジェクト のスコーフ。や jsp:useBean の実装を解説しました。また、 Web アプリケーションの典型的な不具合として、 JSP ペ ージに対して同時に複数のアクセスが発生した場合の動作 をとりあげ、正しく処理をおこなうための排他処理とその 具ー勺なガ去を紹介しました。 ( あらい・みちこ ASTEC) 127

7. UNIX MAGAZINE 2002年5月号

黄着ープログラミ / グ 6 SC 北 好評発売中 ! Java プログラミング・ノート 国際化と 日本語処理 ava は残るものの、現在のところ悪用によるトラブルは起きて し ) なし、。 Web ページの内容を誰でも書き換えられる Wiki Wiki webll がとくに問題を起こさすに運営されているのと同 様、誰でも手軽にメーリングリストを作れる QuickML の運営も平和裡におこなっていきたいと願っている。し かし、利用者が大蝠に増えたときにはセキュリティに関す る方針を改める必要があるかもしれない。 i モードと相性かい QuickML は屯にメールを送るだけでメーリングリス トを作れるので、とくに携帯電話から利用するとイ甦リであ る。ところが、国内でもっとも普及している i モードの端 末は Cc: による送信に対応していないため、 QuickML と の相生がたいへん悪い。メンバーの追加がおこなえないの ・風間一洋著 ・ A5 判、 312 ページ である。 ・ ISBN 4-7561-3481-5 i モード用にメンバー追加をおこなう Web インター ・本体 3 , 000 円十税 フェイスを作って対応しようかとも考えたが、私自身が i モードを利用していないこともあって、まだ実現してい Java による日本語処理、さらには国際化 ない。 プログラミングに必須の知識を数多くの また、 i モードの端末ではヘッダの Reply-To: 行が無視 サンプル・プログラムを示しながら平易に されるため、普通に返信すると送信者にメールがされ 解説する。真の意味での "Write Once, てしまうという問題もある。 QuickML では、メールの末 Run Anywhere" を目指すプログラマー 尾に、 に最適の 1 冊。 目次から ML : enkai@quickml. com 1 章 Java はどんな言語か 使い方 : http : //QuickML. com/ 2 章 国際化と地域化 3 章 Unicode というフッタを挿入するので、 ML: の右側のアドレスを 4 章 ロケー丿レ カーソルで選択すれは、メーリングリストに返信できる。 5 章 工ンコーティング 6 章 タイムソーン au や H ”の端末では、 Cc: も Reply-To: も間題なく扱え リソースパンドル 7 章 8 章 フォーマット出力と解析 るようである。 9 章 文字列の比較 テキストの境界解析 メールの振分け問題 10 章 インブットメソッド 1 1 章 QuickML では、メールのヘッダにメーリングリストで 12 章 文字の表示 Unicode プロック / ロケール一覧 / 付録 あることを示す次のようなフィールドを付加する。 工ンコーディング名一覧 / タイムゾーン D 一覧 / ユーロ通貨記号への対応 X-Mai1—Count : 123 X—ML—Address : enkai@quickml.com 株式会社アスキー X-ML—Name : enkai X-QuickML : true CAFE BABE u N ー X プログラミング・ノート 国際化と日本語処理 ・フ 〒 1 51 ー 8024 東京都渋谷区代々木 4 ー 33 ー 1 0 出版営業部 電話 ( 03 ) 535 ト 81 94 はかにもさまざまな実装 11 http://c2.com/cgi/wiki/o Wiki には、 がある。 115 UNIX MAGAZINE 2002.5