2005-11-22
目次
「WebObjects Dev Report」 第30回 田畑 英和
WebObjects5.3.1がリリースされましたので今回はまずこちらのご紹介から始めます。Ver 5.3からXcodeにWebObjectsの開発環境が含まれるようになりましたが、つい最近リリースされました最新版のXcode2.2にはWebObjects 5.3.1が含まれています。これまでのWebObjectsはProject Builder/Xcodeとは独立してリリースされていましたが、Xcodeに統合されたことによりXcodeのアップデートに合わせて、WebObjectsもアップデートされるようになったようです。0.0.1のアップデートではありますが、今後はXcodeの進化と共にWebObjectsもアップデートされていくのではないでしょうか。
5.3.1での変更点についてはすでにドキュメントが出ていますので、詳細についてはこちらのほうを参照してください。開発ツールについての改良がいくつかおこなわれています。Deployment版の5.3.1については直接ダウンロードすることも可能です。
・WebObjects 5.3.1 Updateについて
http://docs.info.apple.com/article.html?artnum=302797
・WebObjects 5.3.1 for Mac OS X Server 10.4
http://www.apple.com/jp/ftp-info/reference/webobjects531formacosxserver104.html
あと新しいドキュメントも公開されています。5.3からWebObjects Builderが新しくなりましたが、新バージョンに対応した「User Guide」が公開されました。また、Mac OS X Server 10.4からはデーモンの起動方法が新たに導入されたlaunchdによって管理されるようになりましたが、こちらについての記述もドキュメント「WebObjects Deployment Guide」に反映されています。具体的にはwotaskdやMonitorの起動に関する記述が追加されています。
・WebObjects Builder User Guide
http://developer.apple.com/documentation/WebObjects/Conceptual/WO53_WOBuilderGuide/index.html
・WebObjects Deployment Guide(Starting WebObjects Service)
http://developer.apple.com/documentation/WebObjects/Deployment/Deploying_Applications/DeploymentElements/chapter_5_section_5.html
前回はセッションを用いない処理DirectActionの使用方法を解説しましたが、この処理についてもう少し詳しくみていきたいと思います。プロジェクトの新規作成時に自動的に作成されるDirectActionクラスのDirectAction.javaにはあらかじめMainコンポーネントを表示するメソッドdefaultAction()が実装されています。
このメソッドはWOActionResults型の値を返すようになっていますが、この型はInterfaceとして定義されており、WOComponentやWOResponseによって実装されています。WODirectActionクラスでもWOComponentクラスと同様にページを生成するpageWithName()が使用できますので、コンポーネント名を引数で指定してページを生成し、生成したページをreturnすることで任意のコンポーネントに遷移することができます。
・defaultAction()の実装
public WOActionResults defaultAction() {
return pageWithName(“Main”);
}
最低限このpageWithName()を用いてページを返すようにすればDirectActionでページを遷移することができますが、このとき返すページの実装に注意する必要があります。DirectActionを用いる1つの理由はセッションを使用しないことですが、DirectActionが返すページの実装によっては自動的にセッションが生成されてしまう場合があります。
生成したページ内で状態を保持する必要がある場合には、自動的にセッションが生成されますので、DirectActionを用いたからといって必ずセッションが生成されないというわけではありません。例えばページ内でForm関連のDynamic Elementを使用したり、WOHyperLinkでaction属性にバインドをおこなった場合などではページが生成されると自動的にセッションも生成されてしまいます。つまりセッションを使用したくない場合にはDirectActionを使用するだけでなく、生成するページの作り方にも注意を払う必要があるということです。
実際にセッションが生成されたかどうかを調べる方法ですが、セッションが生成されるということはSessionオブジェクトが生成されるということですので、Session.javaのコンストラクタに次のようなコードを実装しておけばログ上でセッションの生成を確認することができます。
public Session() {
super();
/* ** Put your per-session initialization code here ** */
NSLog.debug.appendln(“New Session!! : ” + sessionID());
}
セッションが生成されるときにフレームワークにより自動的にセッションごとにユニークなセッションIDが割り当てられますが、このセッションIDを取得するにはWOSessionクラスのsessionID()メソッドを用います。
ビジネスマッチングシステムでは、データを閲覧する場合にはセッションを用いずに処理をおこない、データを登録する場合にはセッションを用いるような使い分けをおこなっています。
小池邦人のCarbon API 徒然草(2005/11/18)
今回は、Mac OS X 10.3から導入された新機能を使うことで、前回紹介した3つのルーチンの処理内容がどの様に変化するのかを、順序を追って解説します。
今回の処理内容がMac OS X 10.3に対応していると言うことは、サンプルアプリケーションをMac OS X 10.4で起動しても問題はありません。しかし、当然ですが、Mac OS X 10.2では動作しませんので(クラッシュする)、サンプルのソースコードを今回の処理内容に切り替えたら、アプリケーション起動時にMac OS Xのバージョンをチェックして、対象外であればエラーを表示する必要があります。
処理内容のキーポイントは、Mac OS X 10.3から導入されたSetWindowResizeLimits()とHIViewSetLayoutInfo()の2つのAPIを利用することです。画像表示用ウィンドウに実装しているCarbon Event Handlerの処理がかなり複雑なのは、ウィンドウをリサイズした時の幅と高さを、画像の矩形枠内に制限する処理を行っているためです。ウィンドウの最大幅と高さを、SetControlMinimum()とSetControlMaximum()によりScrollView自身に記憶しておき(本来の目的とは異なる使い方ですが…)その値を、Event Handler側で読み込んで制限する処理に利用しています。
ウィンドウサイズの制限は、setupViwerWindowEvent()ルーチンでインストールされているEventTypeSpecの以下の2つのイベントを受け取る時に処理されています。
{ kEventClassWindow,kEventWindowGetMinimumSize },
{ kEventClassWindow,kEventWindowGetMaximumSize },
setupViwerWindow()ルーチンの最初に、SetWindowResizeLimits()を加えることで、これらのイベントに対する処理を省くことが可能となります。SetWindowResizeLimits()には、予想されるウィンドウの最大幅と高さをHISize構造体として渡します。
同様に、ウィンドウサイズを変更した時に、それに合わせてScrollViewのサイズを制限する処理もEvent Handlerを肥大化させている原因です。そちらは、以下の2つのベントを受け取る時に処理されています。この処理の方は、HIViewSetLayoutInfo()を使うことで省略することが可能です。
{ kEventClassWindow,kEventWindowBoundsChanging },
{ kEventClassWindow,kEventWindowBoundsChanged },
Mac OS X 10.3から、あるViewが、それが埋め込まれているViewに対して、どのような位置関係を保つのかを自動制御できるようになりました。今回のScrollViewはウィンドウのContentViewに埋め込まれていますので、その相対位置関係(レイアウト)を固定してしまいます。一度固定されたレイアウトは、ウィンドウがリサイズなどされてもシステム側で自動調整され保持されます。これをHIViewの自動レイアウト機能と呼びますが、そのレイアウト情報を指定するのがHIViewSetLayoutInfo()です。自動レイアウトを実現するのには、以下のHILayoutInfo構造体に適切な情報を記載してHIViewSetLayoutInfo()に渡します。
HILayoutInfo s_layout=
{
kHILayoutInfoVersionZero, // 構造体バージョン(現在はゼロ)
{
{ NULL,kHILayoutBindTop }, // HIBinding構造体
{ NULL,kHILayoutBindLeft },
{ NULL,kHILayoutBindBottom },
{ NULL,kHILayoutBindRight }
},
{
{ NULL,kHILayoutScaleAbsolute,0.0 }, // HIScaling構造体
{ NULL,kHILayoutScaleAbsolute,0.0 }
},
{
{ NULL,kHILayoutPositionTop,0 }, // HIPositioning構造体
{ NULL,kHILayoutPositionLeft,0 }
}
};
HILayoutInfo構造体はHIView.hに記載されています。この構造体のパラメータの意味やレイアウト情報の利用目的については、次回に詳しく解説したいと思います。以下に、SetWindowResizeLimits()とHIViewSetLayoutInfo()を加えた、Mac OS X 10.3用の新しいsetupViwerWindow()を紹介しておきます。
short setupViwerWindow( WindowRef window,CGImageRef image )
{
HIViewRef iview,sview,cview;
short ww,hh,ret=1;
HISize hmax; // ウィンドウサイズの制限を代入するのに用いる
ControlID cid;
Rect drt;
HIRect vrt;
ww=CGImageGetWidth( image ); // 表示画像の幅(Pixel)を得る
hh=CGImageGetHeight( image ); // 表示画像の高さ(Pixel)を得る
hmax.width=ww+15; // ウィンドウの最大幅を代入
hmax.height=hh+15; // ウィンドウの最大高さを代入
SetWindowResizeLimits( window,NULL,&hmax ); // リサイズの限界を設定する
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のフレームサイズを設定
SetControlMinimum( sview,ww+15 ); // 画像の幅+ScrollBar幅を記憶する
SetControlMaximum( sview,hh+15 ); // 画像の高さ+ScrollBar幅を記憶する
// 上記2つの値の保持はズーム処理用
HIViewSetLayoutInfo( sview,&s_layout ); // 自動レイアウト情報を設定する
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 );
}
新APIの機能を使えるようになったおかげで、setupViwerWindowEvent()で用意しなければいけないEventTypeSpecは、7種類から3種類にまで減りました。また、画像ウィンドウ用のCarbon Event HandlerであるmyViwerWindowEventHandler()も、Mac OS X 10.3対応により大きく簡素化されました。
void setupViwerWindowEvent( WindowRef window )
{
EventTypeSpec list[]={
{ kEventClassCommand,kEventCommandUpdateStatus },
// メニューのアップデートを確認
{ kEventClassWindow,kEventWindowZoom },
// ウィンドウのズームボタンに対応
{ kEventClassWindow, kEventWindowClose }
// ウィンドウのクローズボタン(閉じる)に対応
};
InstallWindowEventHandler( window,myViwerWindowEventHandler,
GetEventTypeCount(list),list,window,NULL );
// 3種類のCarbon Eventに対応するCarbon Event Handlerを実装する
}
pascal OSStatus myViwerWindowEventHandler( EventHandlerCallRef myHandler,
EventRef event,void *userData )
{
short ret=eventNotHandledErr;
WindowRef wptr=NULL;
unsigned long ekind;
HIViewRef sview;
short part;
long cls;
HICommand cmd;
ControlID cid;
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 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 );
}
しかし、せっかくSetWindowResizeLimits()でウィンドウサイズの制限をシステム側に教えているのに、何故だかStandard Handlerのズーム処理(kEventWindowZoom)ではその制限が利いていません(どこまでも大きくなる)。Mac OS X 10.3の仕様なのかバグなのかは判断できませんが、とにかく納得いかない現象です。そのため、Mac OS X 10.3の段階では、ウィンドウの最大幅と高さをSetControlMinimum()とSetControlMaximum()で記憶する処理を、setupViwerWindow()ルーチンから外すことができませんでした。しかし、嬉しいことに、Mac OS X 10.4では、SetWindowResizeLimits()で設定したサイズ限界がズーム処理にも適応されるようになっています。
次回は「画像ファイルをウィンドウに表示する」の最終回です。HIViewSetLayoutInfo()に渡すHILayoutInfo構造体について詳しく解説し、Mac OS X 10.4で上記の3つのルーチンの処理内容がどう変化するのかを紹介します。
つづく
SqueakではじめるSmalltalk入門 第51回 鷲見正人
本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。前回に引き続き、チェンジセットの扱いを取りあげます。
▼チェンジセットへの登録のタイミング
デフォルトの記録先として指定されているチェンジセット(チェンジソーターで選択した時「Changes go to …」と表示されるチェンジセット。以下、デフォルトのチェンジセット)には、システムに加えられた改変が自動的に登録されてゆきます。これはその都度「登録」されたもので、けっして過去のある時点の状態と今の状態の差分をその都度いちいちチェックしているわけではないことに注意してください。
登録のタイミングは再コンパイル(もしくは新規コンパイル)です。したがって、何も改変を加えなくても再コンパイルすればデフォルトのチェンジセットに登録されてしまいます。たとえば、Integer >> #factorialをブラウズして、これを内容を変更せずに再コンパイルしてデフォルトのチェンジセットがどうなるか確認してみましょう。Integer >> #factorialの定義は、どこか適当な場所(たとえばワークスペースなど)で「factorial」とタイプしてからbrowse it(cmd+B)すると簡単に呼び出すことができます。
[fig.A]Integer >> #factorialの定義
http://squab.no-ip.com:8080/mosaren/uploads/51a.png
#factorialの定義を呼び出すことができたら、これを再コンパイル、つまりaccept(cmd+S)すればよいのですが、Macで開いたばかりの文書ファイルの保存ができないのと同様に、Smalltalkシステムでも何らかの変更を加えないとエディタの内容はacceptできないようになっています。試しにaccept(cmd+S、あるいは黄ボタンメニューから「了解」を選択)してみても、コードペインがフラッシュ(瞬間的に白黒反転)して軽い注意を促されるはずです。
どこか適当な場所に改行やスペース(文字でも構いません)を挿入してから直ちにdeleteキーで削除するか、select all(cmd+A)してカット&ペースト(cmd+X後、cmd+V)するなどしてみましょう。コードペインに赤い枠が表示されれば、それがacceptが可能になった合図です。ここで改めてaccept(cmd+S、あるいは黄ボタンメニューから「了解」を選択)します。赤い枠が消えれば再コンパイルは完了です。
[fig.B]Integer >> #factorialを内容を変えずに再コンパイルする
http://squab.no-ip.com:8080/mosaren/uploads/51b.png
さて、この状態でデフォルトのチェンジセットはどうなっているでしょうか? アクティブウインドウをブラウザからチェンジソーターに切り換えて確認してみます。右手上のペインにIntegerが追加されているので、それをクリックして選択すると、たった今、再コンパイルしたばかりの#factorialが登録されているはずです。このようなチェンジセット機構の挙動を便利に感じるか不便に思うかは場合によりますが、とりあえず今のところは、再コンパイルをきっかけにしてデフォルトチェンジセットへの登録が行なわれることを覚えておいてください。
[fig.C]内容不変にも関わらず登録された#factorial
http://squab.no-ip.com:8080/mosaren/uploads/51c.png
▼冗長な登録を回避する
改変が加えられたメソッドは、バージョン管理機能を利用して、その定義を元に戻すことが可能です。この機構を用いれば、デフォルトのチェンジセットへの冗長な登録は避けられるのでないか…と思い付いた方もおられるかもしれませんね。でも残念ながら答はノーです。それは、今のデフォルトチェンジセットにFile >> #readContentsBrief:が登録されていることからもご推察いただけるものと思います。このメソッドは、確認のためいったん加筆しましたが、用が済んだ後、元に戻したはずです。しかし、こうしてしっかり登録されてしまっています。
じつはこれ、バージョン復帰の機構や、先のデフォルトチェンジセットへの登録のタイミングについて知っていれば、納得できる挙動なのです。バージョン復帰は、単に、元の定義をチェンジファイル(あるいはソースファイル)から引っ張ってきて再コンパイルしているだけなので、再コンパイルが行なわれたかどうかしか関知しないチェンジセット機構にとっては、内容が元にもどったかどうかなどは知ったことではない…というわけです。
でも、バージョンブラウザの機能を使って、いちいちチェンジソーターを開いて確認せずとも、デフォルトのチェンジセットへの冗長な登録を排除(削除)することは可能です。Integer >> #factorialを使って、実際に試してみましょう。まず、Integer >> #factorialのバージョンブラウザを開いてください。バージョンブラウザを開くには、ブラウザのversionsボタンをクリックします。他にも、メソッド名リストペインの黄ボタンメニューからversionsを選んでも、同ペインにフォーカス(マウスポインタを移動)してからcmd-Vとタイプしても同様です。
[fig.D]Integer >> #factorialのバージョンブラウザ
http://squab.no-ip.com:8080/mosaren/uploads/51d.png
上のペインから元のバージョンを選んで中央のrevertボタンをクリックすることで、選択した元のバージョンに戻すことできます。そして、この操作を行なってもデフォルトのチェンジセットには相変わらずInteger >> #factorialは登録されたままであることについても、すでに述べたとおりなので、もはや確認の必要はないでしょう。
ここで注目すべきは、revertの隣にあるremove from changesボタンです。このボタンをクリックすることで、このバージョンブラウザを開いた(つまり注目している)メソッドをデフォルトのチェンジセットから削除することができます。ためしに同ボタンをクリックして、チェンジソーターに切り換えてその効果を確認してみてください。
余談ですが、このInteger >> #factorialバージョン履歴を見ると分かるように、内容をまったく変えていなくともacceptで強制的に再コンパイルにより、そのメソッドのオーサー(書き手)は変更されてしまっています。したがって、現状復帰を心がけるなら、必要があってメソッドの定義をいったん改変し元に戻す場合、それがささいな改変でも再編集してacceptするのではなく、バージョンブラウザのrevert機構を用いたほうがよさそうです。
▼チェンジソーターでの登録の削除
もちろん、チェンジソーターを使って不要な登録を削除することもできます。削除したいメソッド(たとえば、FileList >> #readContentsBrief:)を選んで、黄ボタンメニューからdelete method from changeSetを選択します。
[fig.E]FileList >> #readContentsBrief:の登録抹消
http://squab.no-ip.com:8080/mosaren/uploads/51e.png
似ていてまぎらわしいのですが、次のremove method from systemを選んではいけません。このメニュー項目は、システムブラウザでのremove methodと同じで、メソッドそれ自体の削除になってしまいます。注意してください。
クラスごとチェンジセットから登録を抹消する場合は、右上のクラス名のリストペインからdelete class from change setを選択します。
バックナンバー:
http://squab.no-ip.com:8080/mosaren/
ニュース・解説
今週の解説担当:木下 誠
———————————————————————-
J2SE 5.0 Release 3登場
———————————————————————-
J2SE 5.0 Release 3が登場しました。ソフトウェアアップデートによる更新で、全ユーザが対象となります。
J2SE 5.0は、JavaのバージョンとしてはJava 1.5ということになります。Java 1.4ではJ2SE 1.4と表記されていましたが、今回からはJ2SE 5.0という表記を使うようです。ユーザが混乱しそうですね。
また、このリリースでは、J2SE 5.0をインストールしても、J2SE 1.4がデフォルトとして残ります。J2SE 5.0を利用するには、ユーティリティにあるJ2SE 5.0/Java Preferencesを使って、スイッチする必要があります。
J2SE 5.0 Release 3 Release Notes
http://developer.apple.com/releasenotes/Java/Java50Release3RN/index.html
———————————————————————-
Windows用のサンプルが多数公開
———————————————————————-
Windows用のサンプルが多数公開されています。ADCで、C#やVBといった文字をこれほど目にすることなるとは、思いもしませんでした。
QuickTimeのCOMを利用した、C#とVBのサンプルになっています。確かに、WindowsでのQuickTime COMは機能が充実しており、かなり高度な操作が行えます。また、WindowsのiTunesもCOMが提供されていて、Mac OS XでAppleScriptによる操作と、同程度のことが行えます。
というわけで、Windows上でのAppleソフトのプログラミング環境は、意外に整備されています。
CreateMovie – C#
http://developer.apple.com/samplecode/CreateMovieCSharp/CreateMovieCSharp.html
CreateMovie – VB6
http://developer.apple.com/samplecode/CreateMovieVB6/CreateMovieVB6.html
MoviePlayer – C#
http://developer.apple.com/samplecode/MoviePlayerCSharp/MoviePlayerCSharp.html
———————————————————————-
他サンプル2点
———————————————————————-
通常のサンプルも公開されています。認証のためのプラグインを作る、NullAuthPlugin。そして、キーボードやマウスからのイベントを受け取る、EventMonitorTestです。
NullAuthPlugin
http://developer.apple.com/samplecode/NullAuthPlugin/NullAuthPlugin.html
EventMonitorTest
http://developer.apple.com/samplecode/EventMonitorTest/EventMonitorTest.html
———————————————————————-
CoreAudio SDKアップデート
———————————————————————-
CoreAudio SDKがアップデートしました。バージョン番号は1.4.3となります。これはTiger専用となるようです。
CoreAudioに興味のある方は、前回公開されました「The Sound of Opportunity Knocking: The Audio Units Community Takes Off」も併せて読まれるといいと思います。
CoreAudio SDK
http://developer.apple.com/sdk/
MOSAからのお知らせと編集後記は割愛します