2005-11-08
目次
「WebObjects Dev Report」 第28回 田畑 英和
前回、前々回は少し話題を変えてサーバ構築について説明してきましたが、
今回はまたプロジェクトの解説に戻りたいと思います。今回のテーマは、セッション管理です。
Webアプリケーションの基盤となるHTTPにはもともとセッション管理の仕組みがありません。つまり、Webサーバに複数回アクセスしたとしても、各アクセスは個別のリクエストとして処理され、リクエスト間の関連性は保持されません。
こうなると困るのが、例えばオンラインショッピングサイトのショッピングカートのようなものを実現するときです。連続してリクエストをおこなったとき、つまりページを移動していったときにもショッピングカートの中身は保持される必要があります。ですので、もともとセッションの仕組みがないHTTPでもなんとかセッション管理をおこなう必要が出てくるのです。
セッションを実現する方法はいくつか考えられますが、WebObjectsはフレームワークが自動的にセッションの管理をおこなってくれます。ですので、なにも準備をしなくても最初からセッションを利用することができるのです。
実際どのようにセッション管理がおこなわれるかですが、あるクライアントから最初のリクエストがあったとき、WebObjectsのフレームワークはそのクライアント用に新しいセッションを割り当てます。まずサーバ上でセッションオブジェクトとセッションを識別するためのセッションIDが生成されます。そして、動的に生成されたWebページにはセッションIDを含んだハイパーリンクが埋め込まれます。URLおよびURLに含まれるセッションIDは次のようになります。
・URL
/cgi-bin/WebObjects/MOSAJobMatch.woa/wo/5smyn1cV1XzALuFPFVCMUw/2.0.4.3
・セッションID
5smyn1cV1XzALuFPFVCMUw
このように22桁の英数字によるセッションIDが、セッションに割り当てられて、URLに埋め込まれます。1度セッションが割り当てられたクライアントから2度目以降のリクエストがあった場合、すでに最初に表示したWebページのハイパーリンクにはセッションIDを含んだURLが埋め込まれていますので、サーバ側ではURLに含まれるセッションIDから、リクエストのあったクライアントがサーバ上のどのセッションオブジェクトに関連付けられているのかを識別して、セッションの管理をおこないます。
別のクライアントからアクセスがあった場合、つまりまだセッションが割り当てられていないクライアントからアクセスがあると、再びセッションの生成がおこなわれ、そのセッション固有のセッションIDによって管理がおこなわれます。
セッションIDがURLに含まれるということはWebブラウザ上で簡単にセッションIDを見ることができますが、これがセキュリティ上問題があるという場合は、セッションIDをURLからははずし、クッキーの中に格納することもできます。この場合、もちろんWebブラウザ側ではクッキ−が利用できるようになっている必要があります。
public Session() {
super();
// セッションIDをURLからはずし、クッキーに格納
setStoresIDsInURLs(false);
setStoresIDsInCookies(true);
}
クッキーにセッションIDを格納して、セッションIDを表面上は隠すことができますが、セッションは永久に存在するわけではありません。最後にリクエストがあってから一定時間が経過するとサーバ上のセッションオブジェクトはタイムアウトして自動的に消滅してしまいます。つまり一定時間しかセッションオブジェクトは存在しません。デフォルトでは、タイムアウトまでの時間は60分に設定されていますが、セッションのタイムアウト時間は自由にカスタマイズすることができます。
まず一番お手軽な方法は、プロジェクトに含まれるPropertiesファイルに次のような設定を追加します。このときタイムアウト時間は秒単位で指定します。この設定はあらかじめコメントアウトされたものがPropertiesファイルに書き込まれています。
・Propertiesファイルによるセッションタイムアウト時間の設定(30分)
WOSessionTimeOut=1800
また、これ以外にも直接コーディングによりタイムアウト時間を指定することもでき、アプリケーション全体で指定する方法と、セッションごとに指定する方法があります。
・アプリケーション(WOApplicationクラス)
public void setSessionTimeOut(Number timeOut)
・セッション(WOSessionクラス)
public void setTimeOut(double aTimeInterval)
今回はWebObjectsがどのようにしてセッションを管理するのかを解説してきましたが、セッションが不要な場合はセッションを用いない処理をおこなうこともできます。次回は、セッションを用いない処理と、ビジネスマッチングシステムで実際にどのようなセッションの制御をおこなっているかを紹介したいと思います。
小池邦人のCarbon API 徒然草(2005/11/4)
今回は、setupViwerWindow()ルーチンとsetupViwerWindowEvent()ルーチン、そして画像表示用ウィンドウに実装するCarbon Event HandlerのmyViwerWindowEventHandler()を紹介します。実は、この3つのルーチンに記述する処理内容は、ターゲットとなるMac OS Xのバージョンによって大きく変化します。
まず最初に、Mac OS X 10.2でも問題なく動作する処理方法を取り上げます。Mac OS X 10.2で問題なく動作すると言うことは、当然、Mac OS X 10.3や10.4での動作も問題ありません。つまり、アプリケーションユーザのターゲットが、Mac OS X 10.2から10.4である場合には、今回紹介するソースコードを用いる必要があります。ただし、本サンプルアプリケーションが画像表示のために多用しているHIView APIは、Mac OS X 10.2からしか利用できませんので、Mac OS X 10.0や10.1をターゲットとする場合には、今回の処理内容を大幅に変更する必要があります。今回は、そうした「古いタイプ」の処理方法については言及いたしません。
以下が、画像表示用のウィンドウに各種Viewを配置しているsetupViwerWindow()ルーチンです。
#define VIEW_ID 300 // ScrollViewのControl ID
#define MY_SIG 'MosA' // ScrollViewのSignature
short setupViwerWindow( WindowRef window,CGImageRef image )
{
HIViewRef iview,sview,cview;
short ww,hh,ret=1;
ControlID cid;
Rect drt;
HIRect vrt;
if( ! HIScrollViewCreate( kHIScrollViewOptionsVertScroll|
kHIScrollViewOptionsHorizScroll,&sview ) )
// 縦横スクロールバーを持つScrollViewを作る
{
HIViewSetVisible( sview,1 ); // ScrollViewを表示可に切り替える
HIViewFindByID( HIViewGetRoot(window),kHIViewWindowContentID,&cview );
// 画像ウィンドウのContentViewを得る
HIViewAddSubview( cview,sview ); // ScrollViewをContentViewに埋め込む
GetWindowPortBounds( window,&drt ); // ウィンドウの矩形枠を得る
vrt.origin.x=vrt.origin.y=0.0;
vrt.size.width=drt.right-drt.left;
vrt.size.height=drt.bottom-drt.top;
HIViewSetFrame( sview,&vrt ); // ScrollViewのフレームサイズを設定
ww=CGImageGetWidth( image ); // 表示画像の幅(Pixel)を得る
hh=CGImageGetHeight( image ); // 表示画像の高さ(Pixel)を得る
SetControlMinimum( sview,ww+15 ); // 画像の幅+ScrollBar幅を記憶する
SetControlMaximum( sview,hh+15 ); // 画像の高さ+ScrollBar幅を記憶する
HIImageViewCreate( image,&iview ); // ImageViewを作成する
HIViewSetVisible( iview,1 ); // ImageViewを表示可に切り替える
HIViewAddSubview( sview,iview ); // ImageViewをScrollViewに埋め込む
cid.id=VIEW_ID; // Control ID=300
cid.signature=MY_SIG; // Signature='MosA'
SetControlID( sview,&cid ); // ScrollViewにControlIDを設定する
ret=0;
}
return( ret );
}
画像ウィンドウにCarbon Event Handlerを実装しているのは、setupViwerWindowEvent()ルーチンです。ここでは、7種類のCarbon Eventを受理できるようにEventTypeSpecを設定しています。
void setupViwerWindowEvent( WindowRef window )
{
EventTypeSpec list[]={
{ kEventClassCommand,kEventCommandUpdateStatus },
// メニューのアップデートを確認
{ kEventClassWindow,kEventWindowZoom },
// ウィンドウのズームボタンに対応
{ kEventClassWindow,kEventWindowGetMinimumSize },
// ウィンドウの矩形枠最大サイズを制限
{ kEventClassWindow,kEventWindowGetMaximumSize },
// ウィンドウの矩形枠最小サイズを制限
{ kEventClassWindow,kEventWindowBoundsChanging },
// ウィンドウの拡大縮小に対応(グローボックス)
{ kEventClassWindow,kEventWindowBoundsChanged },
// ウィンドウの拡大縮小に対応(グローボックス)
{ kEventClassWindow, kEventWindowClose }
// ウィンドウのクローズボタン(閉じる)に対応
};
InstallWindowEventHandler( window,myViwerWindowEventHandler,
GetEventTypeCount(list),list,window,NULL );
// 7種類のCarbon Eventに対応するCarbon Event Handlerを実装する
}
最後に紹介するのは、Carbon Event HandlerであるmyViwerWindowEventHandler()ルーチンです。このルーチンは、setupViwerWindowEvent()のInstallWindowEventHandler()により画像表示用ウィンドウに実装されます。
pascal OSStatus myViwerWindowEventHandler( EventHandlerCallRef myHandler,
EventRef event,void *userData )
{
short ret=eventNotHandledErr;
WindowRef wptr=NULL;
unsigned long ekind;
unsigned long ctype;
HIViewRef sview;
short part;
long cls;
HICommand cmd;
ControlID cid;
HIRect vrt;
Rect brt;
Point pt;
cls=GetEventClass( event ); // イベントクラスを得る
ekind=GetEventKind(event); // イベントの種類を得る
if( cls==kEventClassCommand ) // イベントクラスがkEventClassCommandの場合
{
switch( ekind )
{
case kEventCommandUpdateStatus: // メニューのアップデートを確認
GetEventParameter( event,kEventParamDirectObject,typeHICommand,
NULL,sizeof(HICommand),NULL,&cmd );
// 選択されたメニューの情報を得る
ret=mainteViewerWindowMenu( wptr,cmd.menu.menuRef );
// メニューメンテナンス自作ルーチン
break;
}
}
else if( cls==kEventClassWindow ) // イベントクラスがkEventClassWindowの場合
{
GetEventParameter( event,kEventParamDirectObject,typeWindowRef,NULL,
sizeof(WindowRef),NULL,&wptr );
// 対象となるウィンドウのWindowRefを得る
cid.id=VIEW_ID; // Control ID=300
cid.signature=MY_SIG; // Signature='MosA'
HIViewFindByID( HIViewGetRoot(wptr),cid,&sview ); // ScrollViewを得る
switch( ekind )
{
case kEventWindowGetMinimumSize: // ウィンドウ矩形枠最小サイズを制限
pt.v=pt.h=80;
SetEventParameter( event,kEventParamDimensions,typeQDPoint,
sizeof(Point),&pt );
// 幅と高さが80ピクセルより小さくならないよう制限する
ret=noErr;
break;
case kEventWindowGetMaximumSize: // ウィンドウ矩形枠最大サイズを制限
pt.h=GetControlMinimum( sview ); // ウィンドウの最大幅を得る
pt.v=GetControlMaximum( sview ); // ウィンドウの最大高さを得る
SetEventParameter( event,kEventParamDimensions,typeQDPoint,
sizeof(Point),&pt );
// 幅と高さが得られた最大値を超えないように制限する
ret=noErr;
break;
case kEventWindowBoundsChanging: // ウィンドウの拡大縮小に対応
case kEventWindowBoundsChanged:
GetEventParameter( event,kEventParamAttributes,typeUInt32,NULL,
sizeof(unsigned long),NULL,&ctype );
// ウィンドウ矩形枠がどのように変化したのか調べる
if( (ctype&kWindowBoundsChangeSizeChanged) ) // サイズが変わった
{
GetWindowPortBounds( wptr,&brt ); // ウィンドウ矩形枠を得る
vrt.origin.y=vrt.origin.x=0.0;
vrt.size.width=(brt.right-brt.left);
vrt.size.height=(brt.bottom-brt.top);
HIViewSetFrame( sview,&vrt ); // ScrollViewのサイズも変更
}
ret=noErr;
break;
case kEventWindowZoom: // ウィンドウのズームボタンに対応
pt.h=GetControlMinimum( sview ); // ウィンドウの最大幅を得る
pt.v=GetControlMaximum( sview ); // ウィンドウの最大高さを得る
if( IsWindowInStandardState(wptr,&pt,NULL ) ) // 現状のチェック
part=inZoomIn; // ズームインを行う
else
part=inZoomOut; // ズームアウトを行う
ZoomWindowIdeal( wptr,part,&pt ); // ウィンドウのズーム処理実行
ret=noErr;
break;
case kEventWindowClose: // ウィンドウのクローズボタンに対応
disposeMyWindow( wptr ); // ウィンドウを破棄する自作ルーチン
ret=noErr;
break;
}
}
return( ret );
}
次回は、今回紹介した3つのルーチンの処理内容について、さらに詳しく解説します。そして、こうして用意したMac OS X 10.2用の処理が、Mac OS X 10.3や10.4でどの様に変化するのかを、順序を追って紹介して行きたいと思います。
つづく
SqueakではじめるSmalltalk入門 第50回 鷲見正人
本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。今回から数回にわたって、システムに対して散発的に施された改変を管理するための機構「チェンジセット」を取りあげます。
▼チェンジセットとは
我々はすでに、システムブラウザを使うことで、クラス単位やクラスカテゴリ単位、メソッド単位やメソッドカテゴリ(プロトコル)単位で、そのソースコードをファイルアウトし、他の仮想イメージにそれを読み込ませる(ファイルインする)ことが可能であることを知っています。しかしシステムブラウザには、クラスをまたいで複数のメソッドを追加したり改変を加えるような作業を行なった場合に、それらを一括してファイルアウトする仕組みは用意されていません。
こんなとき役に立つのが「チェンジセット」という機構です。チェンジセットは、その名の示すとおり、システムに加えられた主に複数の“改変”箇所を、あとで確認できるよう“ひとまとめ”に扱うために提供された機構です。あるいは、そうして改変箇所が登録されたデータベース(もちろんオブジェクト)の呼称としても用いられます。
じつは、Smalltalkシステムは、あらかじめ指定されたチェンジセット(変更箇所のデータベース)に、システムのどの部分、つまり、“どのクラスのどのメソッド”が変更されたのかという情報を自動的に記録し蓄積する仕組みを持ちます。チェンジセットに蓄積された変更箇所については、あとで該当するクラスやメソッドのソースを一括してファイルアウトすることが可能です。なお、チェンジセットは複数持つことができて、それぞれに名前を付けて適宜、切り換えて使うことができます。
▼チェンジファイルへのログ機構との違い
前回、取りあげた「チェンジファイル」へのログ機能と、今回の「チェンジセット」への変更箇所の登録機構は、名前も作業の内容も似ているように感じられますが、両者はまったく別物です。混同しないように注意してください。
すでにご紹介したとおり、チェンジファイルへのログ機能は、改変の“内容”を記録してゆくものです。これに対しチェンジセット機構は、改変された“箇所”だけを情報として記録します。
また、改変内容の記録先であるチェンジファイルは、Smalltalkシステムの“外界”にある単一のテキストファイル(ログ用のワークファイル)なのに対し、チェンジセットはSmalltalkシステムの中に複数存在するオブジェクトで、それぞれが小規模なデータベースのような振る舞いをする…という違いもあります。
▼チェンジソーター
システムに加えられた改変の登録先として指定されているチェンジセットと、その他のチェンジセット群やその内容を閲覧するためのツールが「チェンジソーター」です。デスクトップメニューの「開く…」(英語メニューでは「open…」)→「シンプル・チェンジ・ソーター」(同、simple change sorter)で起動できます。
[fig.A]チェンジソーター
http://squab.no-ip.com:8080/mosaren/uploads/50a.png
まず、ウインドウタイトルにある「Changes go to “名無し1″」(英語では「Changes go to “New Changes”」)に注目してください。このタイトルには、二つのことが示されています。
ひとつは、このシステムに登録されているチェンジセット群の中で、ブラウズ中(選択されている)のは「名無し1」(あるいは「New Changes」)と名付けられたチェンジセットであること。そして、もうひとつは、このチェンジセットが改変箇所の記録先として指定されていること、です。
後者については「Changes go to」という部分に表わされています。ためしに左上のリストペインで別のチェンジセットをクリックして選択しなおしてみてください。「名無し1」チェンジセット以外では、タイトルは「ChangeSet:<<チェンジセット名>>」のように変化するのを確認できるしょう。
右手最上段のリストペインでは、選択したチェンジセットに登録された改変箇所をクラス名で一覧できます。このペインでクラスを選択すると、さらにそのクラス内で改変されたメソッドが(あれば)中央のリストペインに列挙されます(クラス情報の改変のみなら、中央のリストペインは空欄のまま最下段のペインにそのむねだけが表示されます)。
「名無し1」チェンジセットには、ちょうど第47回に終えたばかりの、日本語ファイルの扱いに関するファイルリスト不都合を修正するために加えた改変が登録されているはずです。
[fig.B]チェンジセットに登録された改変を確認する
http://squab.no-ip.com:8080/mosaren/uploads/50b.png
チェンジセットが実際に保持している情報はこれ(改変されたクラスとメソッド群の名前)までです。しかし、クラスとメソッド名まで分かっていれば、そのソースコードを見たくなるのは人情ですし、メソッドもオブジェクトであるSmalltalkシステムにおいては、そのソースを“たぐる”ことは実にたやすいことです。したがって、チェンジソーターがシステムブラウザのような機能を持っていたとしても、何ら不思議なことではないでしょう。
実際、そのようになっていて、中段リストペインに列挙されたメソッド名をクリックして選択すれば、そのメソッドのソースを閲覧できます。もちろん、必要ならばこの場で編集(再コンパイル)も可能です。
[fig.C]システムブラウザ同様、ソースの閲覧や編集も可能
http://squab.no-ip.com:8080/mosaren/uploads/50c.png
バックナンバー:
http://squab.no-ip.com:8080/mosaren/
ニュース・解説
今週の解説担当:木下 誠
———————————————————————-
CodeWarrior 10登場!
———————————————————————-
ついにCodeWarrior 10が登場しました。Mac版としては、最後になるであろう、と言われているCWです。
2つのバージョンが用意されています。1つは、学生やホビースト向けの、無料のLearning Edition。ライセンスに制限があり、テクニカルサポートはありません。もう1つは、$99で販売されるProfessional版。どちらも、ダウンロードのみです。
細かい変更点に付いては、おそらく来週小池さんが書いてくださるでしょう。一つ、注目しておきたいポイントは、PowerPlant、PowerPlant X、Constructorが将来オープンソース化されることが明記されました。これで、オープンソースコミュニティによる、PowerPlantのサポートが現実味を帯びます。
CodeWarrior Development Studio for Mac 10
http://www.metrowerks.com/MW/Develop/Desktop/mac10
———————————————————————-
Core Audioの紹介記事
———————————————————————-
「The Sound of Opportunity Knocking: The Audio Units Community Takes Off」と、題する記事が公開されました。Core Audioを用いたアプリケーションや、デベロッパが紹介されています。
また、Developer CDに付属するAU Labの簡単な使い方や、Audio Unitプラグインの開発の流れも併せて紹介されています。Core Audioの簡単なオーバービューを知りたい方は、目を通してみるといいと思います。
The Sound of Opportunity Knocking: The Audio Units Community Takes Off
http://developer.apple.com/audio/audiocommunity.html
———————————————————————-
DVDPlaybackフレームワークを利用したサンプルと、
Tabコントロールを利用したサンプル
———————————————————————-
CocoaでDVDを再生するサンプル、CocoaDVDPlayerが公開されました。これは、Mac OS X 10.3から搭載されている、DVDPlayback.frameworkを使ったサンプルです。標準アプリケーションの、DVDプレイヤーと同等のことを行えるアプリケーションを作成できます。
CocoaDVDPlayer
http://developer.apple.com/samplecode/CocoaDVDPlayer/CocoaDVDPlayer.html
タブコントロールを利用するサンプルも公開されています。こちらは、Carbon用です。
TabsShowcase
http://developer.apple.com/samplecode/TabsShowcase/TabsShowcase.html
———————————————————————-
Kernel Debug Kitアップデート
———————————————————————-
Kernel Debug Kitがアップデートされて、Kernel Debug Kit 10.4.3となりました。Mac OS Xのアップデートに合わせた公開です。
Developer – Development Kits
http://developer.apple.com/sdk/
MOSAからのお知らせと編集後記は割愛します