MOSA Multi-OS Software Artists

MOSAはソフトウェア開発者を支援します

  • iPhone/iPod touch アプリ紹介
  • MOSA掲示板
  • 活動履歴
  • About MOSA(English)

MOSA Developer News[MOSADeN=モサ伝]第152号

2005-03-15

目次

  • SqueakではじめるSmalltalk入門  第34回  鷲見 正人
  • 小池邦人の「Carbon API 徒然草」
  • 「Behind the WebObjects」    第39回  田畑 英和
  • ニュース・解説               木下 誠

SqueakではじめるSmalltalk入門   第34回  鷲見 正人

 本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。

 前回に引き続き、コレクションの抽象クラス「Collection」のプロトコルを覗きながら、コレクションがどんなメッセージを受け付けるオブジェクトなのか、その“正体”を探ってゆきましょう。

 addingに続くarithmeticプロトコルには、前回後回しにしたadaptingに分類されるメソッド群と連携して、とてもおもしろい仕組みにより実現されたメソッドが用意されています。しかしその前に、Smalltalkのコレクションの性質の基本とも言うべきenumerating(列挙)プロトコルを先に見ておくことにします。

 さて、すでにブロックを用いた制御構造のところで触れたように、Smalltalkではいわゆるfor-nextループを次のように「メッセージ送信」のかたちで表現し、動きをシミュレートします。

World findATranscript: nil.    "トランスクリプトをアクティベート"
1 to: 5 do: [:i | Transcript cr; show: i]  "そこに1から5まで出力"

 このスクリプトは、次のように書いても同じ結果になります。字面では括弧が追加されただけですが、しかし、その意味するところは大きく違ってきます。

World findATranscript: nil.
(1 to: 5) do: [:each | Transcript cr; show: each]

 レシーバが誰で、それにどんなメッセージを送っているのか、をそれぞれについて整理すると両者の違いが明確になると思います。前者は、1に対してto: 5 do: [...] というメッセージを送っているだけ、つまり、Smalltalkにおける“式”の要件であるメッセージ送信の体裁こそ満たしていますが、そうして送られるメッセージにはそれ以上(つまり式の要件を満たす以外の)“意味”を見いだすことはできません。

 他方で後者は、(1 to: 5)というコレクション(an Interval)に対して、do: [...] というメッセージを送っています。ブロック変数を「i」から「each」に書き換えたことからも察していただけるように、#do:メソッドは、それを起動したコレクションの各要素を“列挙”し、それぞれについて引数のブロックを評価します。前者より、ずっとメッセージの内容とその意味が近いところにありそうですね。また、do: [...]ならばto: n do: [...] と違って、レシーバを別のオブジェクトに置き換えることもできます。

World findATranscript: nil.
(1 to: 5) do: [:each | Transcript cr; show: each].
#(1 2 3 4 5) do: [:each | Transcript cr; show: each].
'string' do: [:each | Transcript cr; show: each]

 enumeratingプロトコルには、レシーバの各要素について繰り返しブロックを評価する#do:の他に、注目するメソッドとして、ブロックの評価値を集めてコレクションにして返す#collect:、条件に合致したものだけ集める#select:があります。なお、evenは、整数に送ってそれが偶数かを判断し、結果をtrueあるいはfalseで返させるメッセージです。

#(1 2 3 4) collect: [:each | each * 2]  " => #(2 4 6 8) "
#(1 2 3 4) select: [:each | each even]  " => #(2 4) "

 collect: [...]とselect: [...]というメッセージはたいへんよく似た、つまり、引数としてブロックをひとつ添えた形態をとっていますが、引数であるブロックの役割りはかなり違うので使用に際しては注意が必要です。前者がブロックを、新たに生じさせるコレクションの要素の“発生器”として用いるのに対し、後者ではブロックを、各要素について、新しいコレクションの要素としてよいか、それとも排除するかについての判断のために用います。したがって、collect: [...]の引数のブロックには制約はありませんが、select:[...]の引数のブロックは必ず真偽値を返さなければならないという条件を満たさなければなりません。このことは、上段右端のペインで「collect:」あるいは「select:」を選択してそれぞれの定義を読むとよりよく理解できると思います。

 select: [...]の逆の役割りを果たすreject: [...]というメッセージも使えます。もちろんこれは、引数のブロック内の式の真偽を反転させたselect:[...]と同じ結果になります(定義も、ほぼ、そうなっています)。なお、oddは整数に送ってそれが奇数かを判断し、結果を真偽(trueかfalse)で返させるメッセージです。notは、真偽に送ることでその反転を促します。

#(1 2 3 4) reject: [:each | each even]      " => #(1 3) "
#(1 2 3 4) select: [:each | each odd]       " => #(1 3) "
#(1 2 3 4) select: [:each | each even not]  " => #(1 3) "

 #collect:、#select:のように“基本”ではありませんが、覚えていて要所で使うとちょっとカッコイイのが#inject:into:です。たとえば、こんなスクリプトの場合、

| sum |
sum _ 0.
#(1 2 3 4) do: [:each | sum _ sum + each].
^ sum

…と、いうように、一時変数のsumの宣言とその初期化、また、do: [...]はレシーバを返すのでsumを改めて参照するために、合計を出すメインの式の他に、ひとつの宣言文と余計な二つの式を必要とします。#inject:into:はこうしたありがちな手続きを一時変数の力を借りずに、かつ、ひとつの式のみで済ませたいときに使います。

#(1 2 3 4) inject: 0 into: [:result :each | result + each]

 どうして、たったこれだけで合計を算出できるのか不思議に思われるかも知れませんが、そのカラクリはCollection >> #inject:into:の定義を見れば一目瞭然です。

Collection >> inject: thisValue into: binaryBlock
   | nextValue |
   nextValue _ thisValue.
   self do: [:each | nextValue _ binaryBlock value: nextValue value: each].
   ^ nextValue


バックナンバー:
http://squab.no-ip.com:8080/mosaren/

小池邦人の「Carbon API 徒然草」(2005/03/11)

Navigation Service APIの活用(その6)

今回は、最後の自作ルーチンnavCheckImportExtention()を紹介し、それをNavGetFile()のフィルタルーチンから使うケースを解説します。また、ファイルタイプも拡張子も付いていない画像ファイルに遭遇した場合、それがオープンできるかどうかを判断するために用いる便利なルーチンも紹介します。

前回、「拡張子のみ」でその種類を判断しなければいけないファイルのために、NULL(ゼロ)を含めたいくつかの特殊ファイルタイプもNavTypeList構造体へ追加しておく必要があると説明しました。ここでは「未定義」のファイルタイプとして、NULLの他に、’????’ 、’****’、’ ‘(スペース4つ)の3つを追加しましたが、これは筆者の経験から加えた物であり(笑)Apple社がそう定義しているわけではないのでご了承ください。また、UNIX環境からMac OS 9起動マシン経由で入ってくる画像ファイルの中には、そのタイプが’TEXT’だったりする物もありますので状況によってはさらに注意が必要です。

以下が、navCheckImportExtention()ルーチンです。非常に原始的な方法(文字列比較)で拡張子をチェックし、ファイルタイプは「未定義」だが拡張子が目的の内容であれば、*typeに対象タイプを代入し1を返します。また、ファイルタイプが設定済みで未定義タイプでなければゼロを、未定義タイプで内容が目的の拡張子でない場合には-1を返します。今回のソースコードは誌面の関係上、チェック対象をJPEGファイルのみに限定しています。本来ならば、必要とされる画像種類の数だけ文字列比較の箇所を増やす必要があります。また、厳密に比較するならば、大文字と小文字が混在した拡張子や、4文字「.jpeg」などの、ある程度予想されるイレギュラルな拡張子にも対応する必要があるでしょう。はっきり言って、やり出したらきりがない「どこで妥協するのだ?」作業となります。

short navCheckImportExtention( Str255 str,OSType *type )
{
    short    len;

    if( *type==NULL || *type=='????' || *type=='****' || *type=='    ' )
    {                         // ファイルタイプが未定の場合(通常はNULL)
        len=*str;
        if( str[len-3]=='.' ) // 拡張子の位置をチェック
        {
            if( str[len]=='g' && str[len-1]=='p' && str[len-2]=='j' )
            {
                *type='JPEG'; // JPEGファイルと判断
                return( 1 );
            }
            if( str[len]=='G' && str[len-1]=='P' && str[len-2]=='J' )
            {
                *type='JPEG'; // JPEGファイルと判断
                return( 1 );
            }
        }
        return( -1 );
    }
    return( 0 );
}


上記ルーチンをNavGetFile()のフィルタルーチンで利用すれば、そのファイルのタイプが未定義でも、ファイル名選択ダイアログのブラウザで通常表示(グレー表示ではない)することが可能です。以下のnavFilterProc()が、navCheckImportExtention()を用いたフィルタルーチンです。

pascal Boolean navFilterProc( AEDesc *item, void* info,
                                    NavCallBackUserData ud,NavFilterModes mod )
{
    NavFileOrFolderInfo   *finfo;
    OSType                type;
    FSSpec                fsc;
    short                 chk;

    if( item->descriptorType==typeFSS ) // ファイルのFSSpec構造体を得られるか?
    {
        finfo=(NavFileOrFolderInfo*)info; // ファイルやフォルダ情報を得る
        if( ! finfo->isFolder )           // 対象はファイルのみ
        {
            AEGetDescData( item,(Ptr)&fsc,sizeof( FSSpec ) ); // FSSpecを得る
            type=finfo->fileAndFolder.fileInfo.finderInfo.fdType;// Typeを得る
            chk=navCheckImportExtention( fsc.name,&type );  // 総合チェック
            if( chk==1 )           // Typeは未定義だが対象となる拡張子である
                return( 1 );       // ブラウザに表示する
            else if( chk==-1 )     // 対象外の拡張子である
                return( 0 );       // ファイル名をグレー表示にする
        }
    }
    return( 1 ); // Typeはちゃんと定義されているのでブラウザに表示する
}


利用するための登録は簡単です。NavGetFile()を実行する時に、以下のようにフィルタルーチンとして引数で渡してやります。NavFileOrFolderInfo構造体の詳しい内容についてはNavigation.hを参照してください。また、フィルタルーチンで表示判別の対象となるファイルは、先んじてNavTypeListHandle(NavTypeList構造体)で設定したファイルタイプを持つ物のみとなりますので、くれぐれも注意してください。

NavGetFile( NULL,&reply,&opt,NULL,NULL,navFilterProc,list,NULL );

ファイルタイプが未定義でも、ちゃんと拡張子があれば種類の判断は可能なのですが(嘘の拡張子が付いていたらダメ)、中には両方とも存在しないファイルがあります。こうなると、「ファイルの中身」をサーチし、その種類を判断するという「最終手段」を取らざるをえなくなります。具体的に言えば、画像ファイルのヘッダ情報を読み込み、そこに正しい情報が記載されているかどうかをチェックするわけです。しかし、すべての画像ファイルについて「いちいちそこまでやってられない!」と言うのが開発者の本音なわけです(笑)。そこで最後に、QuickTime GraphicsImporterコンポーネントの能力を使い、ファイルのMIME(Multipurpose Internet Mail Extensions)情報を得ることで、そこからファイル種類を判別するnaviCheckMIMEList()ルーチンを紹介しておきます。

short naviCheckMIMEList( FSSpec *fsc,OSType *type )
{
    QTAtom                    atom=NULL;
    OSType                    type1=0;
    long                      size=0;
    short                     ret=1;
    QTAtomContainer           cont;
    Str255                    str;
    Ptr                       pp;
    GraphicsImportComponent   gi;

    *str=0;
    if( ! GetGraphicsImporterForFile( fsc,&gi ) ) // FSSpec経由でImporterを得る
    {
        GraphicsImportGetMIMETypeList( gi,&cont ); // QTAtomContainerを得る
        if( atom=QTFindChildByID( cont,NULL,'mime',1,NULL ) ) // QTAtomを抽出
        {
            if( ! QTGetAtomDataPtr( cont,atom,&size,(Ptr *)&pp ) ) // MIME抽出
            {
                *str=size;
                BlockMove( pp,str+1,size );                   // 文字列に変換
                if( cmpString( str,"¥pimage/x-photoshop" ) )  // 文字列の比較
                    type1='8BPS';
                if( cmpString( str,"¥pimage/x-mac" ) )  // これは自作ルーチン
                    type1='PNTG';
                if( cmpString( str,"¥pimage/x-bmp" ) )
                    type1='BMPf';
                if( cmpString( str,"¥pimage/pict" ) )
                    type1='PICT';
                if( cmpString( str,"¥pimage/jpeg" ) )
                    type1='JPEG';
                if( cmpString( str,"¥pimage/tiff" ) )
                    type1='TIFF';
                if( cmpString( str,"¥pimage/gif" ) )
                    type1='GIFf';
                if( cmpString( str,"¥pimage/png" ) )
                    type1='PNGf';
                if( cmpString( str,"¥papplication/pdf" ) )
                    type1='PDF ';
                if( type1 )
                {
                    *type=type1;  // 得られたファイルタイプを代入
                    ret=noErr;    // Typeを得られればnoErr(ゼロ)が返る
                }
            }
        }
        CloseComponent( gi ); // GraphicsImporterコンポーネントを解放
    }
    return( ret ); // Typeが得られれなければ1が返る
}


このルーチンは、「正体不明」のファイルの正体を突き止める最終手段としてそこそこ役に立ちます。今回は、MIME情報も得たいケースを考え、QTAtomから抽出したMIMEタイプを一度パスカル文字列に変換してから比較していますが、もちろんこの手間を省き直接バイナリ比較してもかまいません。前回も言及しましたが、現在のNavigation Serviceは「拡張子」の扱が非常に貧弱なのが最大の弱点です。それだけ、以前からMacintoshが採用している(今でもしているが…)ファイルタイプと言う仕組みが理解しやすく取り扱いが楽だった証拠にもなります。しかし、こうなってしまった現状としては、この「鬼っ子」をもう少しうまく手なずけるための有用なAPIが、早急にNavigation Serviceに実装されることを切望したいと思います。

次回は「Navigation Service APIの活用」の最終回となります。FSSpecの代わりにFSRefを得るために有用なシートウィンドウ版の「フォルダ選択ダイアログ」と「ファイル名選択ダイアログ」を紹介したいと思います。

「Behind the WebObjects」  第39回  田畑 英和

 前回に引き続き運用についての解説です。前回はアプリケーションのインストール方法を説明しましたが今回は運用環境のセットアップについてみていきたいと思います。

運用環境のセットアップ

 WebObjectsの運用プラットフォームとしてはWindowsやSolarisもサポートされていますが、ここではMac OS X Serverでのセットアップ方法について解説します。Mac OS X ServerにはあらかじめWOの運用ライセンスが付属しており、さらにv10.3からはOSの一部として最初から運用環境が組み込まれているため別途運用環境をインストールする必要がなく、短時間で環境をセットアップすることができます。
 ただしMac OS X Server v10.3をインストールしただけですと、運用環境の中核となるwotaskd(WebObjects task deamon)はまだ停止状態になっています。通常はOS起動時にwotaskdを起動させて常駐させておく必要がありますので、まずはその設定が必要になります。
 Mac OS X Server v10.3にはあらかじめwotaskdの起動スクリプトが用意されていますが、wotaskdの実行命令がコメントアウトされた状態になっていますのでコメントを外さなければなりません。コメントを外しておけばOS起動時にスクリプトが自動的に実行されてwotaskdが起動します。

・wotaskd起動スクリプト
/System/Library/StartupItems/WebObjects/WebObjects
・実行命令
“${WOSERVICE}” -appPath “${WOTASKD}” >/var/log/webobjects.log 2>&1 &

運用環境の動作確認

 wotaskdはポート1085番で起動するように設定されていますので、Webブラウザからポート1085にアクセスしてレスポンスがあればwotaskdの起動が確認できたことになります。起動スクリプトをみると分かりますが、wotaskdのログがログファイルに保存されていますので、ログファイルを参照して起動を確認することもできます。

・wotaskdの起動確認
http://localhost:1085
・wotaskdのログファイル
/var/log/webobjects.log
・正常に起動した場合のログ
[2005-02-23 16:15:58 JST]

The URL for webserver connect is:
http://192.168.0.1/cgi-bin/WebObjects/wotaskd.woa/-1085
The URL for direct connect is:
http://192.168.0.1:1085/cgi-bin/WebObjects/wotaskd.woa
[2005-02-23 16:15:58 JST]
Waiting for requests…

 Mac OS X Server v10.3の場合は若干注意が必要なところがありまして、以前はroot権限でwotaskdが起動されていたのですが、v10.3からはappserverというユーザでwotaskdが起動されるようになりました。このためパーミッションの設定には注意が必要です。

Monitorの起動

 wotaskdの起動が確認できれば次はMonitorの起動です。MonitorとはWOの運用環境を設定するツールで、Webアプリケーションとして実装されています。MonitorはWebObjectsで開発されており、起動するには起動スクリプトを実行します。

・Monitorの起動スクリプトのパス
/System/Library/WebObjects/JavaApplications/JavaMonitor.woa/JavaMonitor

 開発環境でMonitorを起動した場合は、WebブラウザにMonitorのトップページが自動的に表示されますが、開発環境上では自動的に表示されません。そこで、ターミナル上でMonitorの起動スクリプトを実行しますとwotaskdのログと同様のものが表示されますので、そこに表示されるURL(最後から2行目)からMonitorのトップページにアクセスすることができます。
 MonitorはWebアプリケーションですので、ネットワークを経由して他のマシンから操作することもできます。

Monitorの設定

 Monitorを起動したらまずはパスワードの設定をおこなってください。パスワードの設定は「Preferences」画面でおこないます。パスワードを設定しておきますと、Monitorがパスワードで保護され、Monitorを起動したときにパスワードの入力が求められるようになります。
 Monitorが利用できれば自由にアプリケーションを停止できたりしますので危険ですし、Monitorでパスワードを設定することによりwotaskdがポート1085で公開しているデータを保護することもできます。

 パスワード設定ができましたら、次に「Hosts」画面でホストの登録をおこないます。ここでのホストとはwotaskdが起動しているマシンのことです。WOはWebサーバとアプリケーションサーバ(wotaskdが起動しているサーバ)を分けることもできますし、アプリケーションサーバを複数配置して負荷分散をおこなうこともできますが、まずはすべて1台のマシン上で動作させる単純な構成から始めるのがよいでしょう。

 ホストの設定が完了すればこれでいよいよアプリケーションを運用できる準備がととのったことになりますが、「Site」画面でHTTP Adaptor URLの設定をおこなっておくと便利です。この設定をおこなっておくことで運用中のアプリケーションにMonitor上から直接リンクがはられます。

・HTTP Adaptor URLの設定例
http://192.168.0.1/cgi-bin/WebObjects

 さて今回は以上ですが、次回はアプリケーションの登録や設定方法を解説する予定です。

ニュース・解説

今週の解説担当:木下 誠

———————————————————————-
Core Imageを解説した文書が登場
———————————————————————-

Appleが、Tiger Developer Overview Seriesの最新作「Developing with Core Image」を公開していました。Tigerで導入される、2次元画像処理ライブラリであるCore Imageの概要を説明しています。

Core Imageは、アプリケーションから使える強力な画像ライブラリです。その特徴は、豊富なフィルタにあります。フィルタはImage Unitと呼ばれるモジュールで提供され、その数は100近くに上ります。簡単に言えば、Web Kitがあればブラウザが簡単に作れるように、Core Imageがあれば誰でもPhotoshopが作れると言えるでしょう。

このImage Unitにアクセスするには、Quartz Coreフレームワークを利用します。このフレームワークは、CIImageやCIFilterといったObjective-CのAPIを提供しており、Cocoaアプリケーションからはシームレスに使うことができるようです。CベースのAPIが提供されるかどうかは不明です。

Core Imageのもう一つの特徴は、ハードウェア・アクセラレータのサポートを受けられることにあります。近年、爆発的に性能を上げているGPUの命令セットを直接使えることになるようです。そのために、Image Unitを作成するときはCIKernelという言語を使います。CIKernelはCに似たスタイルで、Open GL Shading Languageのサブセットになっています。これにより、ポータブルでありながら最大のパフォーマンスを得られるようになっています。

また、TigerにはCore Imageをテストするためのツールが2つ付いてくるそうです。1つはCore Image Fun Houseと呼ばれるもので、1枚の画像に複数のImage Unitを適応していくものです。去年のWWDCキーノートで使われたツールがベースになっているものと思われます。もう1つは、Quartz Composerと呼ばれるもので、グラフィカルにImage Unitを接続していくツールです。このツールでは、Image Unitのインプットとアウトップを細かく制御することができるようです。また、アニメーションを作成して、スクリーンセイバーなどで使うことができます。

Developing with Core Image
http://developer.apple.com/macosx/tiger/coreimage.html

———————————————————————-
Eclipseのチュートリアルが公開
———————————————————————-

Appleが、Java開発環境であるEclipseの使い方を解説した「Developing Java Applications on Mac OS X with Eclipse」を公開しています。Eclipseで開発を始めるためのチュートリアルです。

Eclipseは、Javaで書かれたIDE(統合開発環境)で、Java開発ではほぼ標準の地位を占めます。Mac OS XでEclipseを使う利点は、もちろんその高い完成度もありますが、LinuxやWindowsといった複数プラットフォームが混在した開発体制でも、プロジェクトファイルなどを共有できる、ということが挙げられます。

Appleが今回公開した記事では、Eclipseを使い始めるための3つの例を説明しています。1つ目は、いつも通りのHelloWorldの作り方。2つ目は、Swingを用いたプロジェクト。そして3つ目は、SWT(Standard Widget Toolkit)を用いた例です。

Developing Java Applications on Mac OS X with Eclipse
http://developer.apple.com/tools/usingeclipse.html

———————————————————————-
Dashboard Widget Contest受賞作品発表
———————————————————————-

Appleが、Dashboard Widget Contestの受賞作品を発表していました。「Send SMS」と「WikityWidget」の2つが発表されています。

Send SMSは、ウィジェットからSMS(Short Message Service)を送るものです。SMSは、アメリカの携帯電話でいまだに主流の、150文字程度のテキスト送信サービスです。このウィジェットは、XMLHttpRequestを利用したテキストの送信と、Address Bookからのアドレス取得がポイントとなっています。

WikityWidgetは、Wikiを利用したノートパッドです。Wikiを利用して、ノートの読み込み、保存を行っています。特徴は強力な検索機能のようです。また、プラグインを作成してJavaScriptからSQLiteへのアクセスを行っているようです。何に利用しているのかは分かりませんが。

このように見てみると、少し高機能なウィジェットを作ろうとすると、プラグインの助けがすぐ必要になることが分かります。CSS + JavaScriptでできることはかなり限られると思われるので、ウィジェット用単機能プラグインの開発は需要が高いかもしれません。

The Apple Dashboard Widget Contest
http://developer.apple.com/macosx/tiger/dashboard/

MOSAからのお知らせと編集後記は割愛します

MOSA Developer News   略称[MOSADeN=モサ伝]
Apple、Mac OSは米国アップルコンピュータ社の登録商標です。またそのほかの各製品名等はそれぞれ各社の商標ならびに登録商標です。
このメールの再配信、および掲載された記事の無断転載を禁じます。
特定非営利活動法人MOSA  http://www.mosa.gr.jp/
Copyright (C)2005 MOSA. All rights reserved.