メイン

プログラム アーカイブ

2007年01月04日

相変わらず、意味不明

こんなエラー出ても、わからんっちゅーの。
XMLTest.obj : error LNK2019: unresolved external symbol "void __cdecl _com_issue_error(long)" (?_com_issue_error@@YAXJ@Z) referenced in function "public: __cdecl _variant_t::_variant_t(unsigned short const *)" (??0_variant_t@@QAA@PBG@Z)

これのことかなぁ
http://support.microsoft.com/kb/892073/ja

上記の、情報に従って、ちょっと追加してみる。
stdafx.h
void _com_issue_error(HRESULT hr);
void _com_issue_errorex(HRESULT hr, IUnknown* pUnkn, REFIID riid);

stdafx.cpp
void _com_issue_error(HRESULT hr)
{
//Insert a custom implementation, such as the following.
//TRACE( _T("Caught unhandled COM exception!\n") );
}

void _com_issue_errorex(HRESULT hr, IUnknown* pUnkn, REFIID riid)
{
//Insert a custom implementation, such as the following.
//TRACE( _T("Caught unhandled COM exception!\n") );
}

エラーが消えた・・・。
#import ステートメントなんて、使ってないのになぁ。
まあ、ビルドできたから、とりあえずは、いいけど。

2008年04月15日

Model-Glueのイベントとメッセージ

ColdFusionに、フレームワークが必要なのかどうかわからないけど、とりあえず、読んでみよう。
Model-Glue、ColdSpring、Transferの組み合わせで、何が便利なのか、確認。
Reactorではなく、Transferなのは、APIドキュメントに、“Transaction”があって、「トランザクションの記述が簡単なのかな?」と思っただけのこと。
実際には、その辺りについては、あんまり変わらないみたいな気がしてきている。
Transferの方が、いろいろと、ごてごて機能満載な感じがしている。

さて、フレームワークというものは、ちょっと動くものを作ってみようということが、なかなか難しい。
いろいろと、やらなきゃいけないことが多くて、「フォームでポストリクエストを受け取って、画面に表示」ということだけでも、めんどくさいだけにしか感じない。
こういったことは、ColdFusionの手軽で、軽快な作業性とは、大きく反している。
フレームワークの利点ってのは、巨大なプロジェクトで、大人数が作業する際に、真価が発揮されると思っているんだけど、そういったあたりも、確認できればいいな。

Model-Glueの設定ファイル“ModelGlue.xml”を見ただけでも、ちょっと引いてしまったのは、内緒。
ここで重要なのは、イベントと、メッセージだろうか。
イベントとは、文字通り、リクエストなどのイベント。URLの後ろに“event=<イベント名>”と付けたりする。
そうでなくても、構造上は、イベントは、“ModelGlue.xml”で任意に発生させることができる。
で、メッセージは、コントローラーへ処理を渡す際に発生させるという感じだろうか。
イベントは、そのメッセージを発生させたり、画面遷移させたり、追加でイベントを発生させたりできる。
メッセージは、単に、“function”を実行させるだけという認識でいいのではないだろうか。

もちろん、この2つ以外にも、Model-Glueには、色々な概念があるけど、一つ一つ、確認していかないと、混乱してしまうから、まずは、ここまで。

2008年04月16日

イベントとメッセージ その2

では、Model-Glue において、イベントやメッセージが発生した場合に何が引き起こされるのだろうか。

メッセージは、コントローラーが引き受けるもので、その挙動は、ModeGlue.xml の
 modelglue
  controllers
   controller
    message-listener
に定義されている。
メッセージは、メッセージリスナーが受け取ることになる。
メッセージリスナーがメッセージを受け取ると、messege-listener の messege 属性に一致するメッセージを探して、
その function 属性に設定されている関数が実行される。
関数は、modelglue => controllers => controller の type 属性に指定してあるコントローラー内に定義されている。

イベントが発生した場合の振る舞いは、ModelGlue.xml の
 modelglue
  event-handlers
   event-handler
に定義されている。

イベントが発生すると、event-handler の name 属性の中から一致しているものを探す。
そこで定義されている、broadcasts、results、views が処理される。
broadcasts は、message 子要素を持ち、メッセージを発生させる。
results は、result 子要素を持ち、追加的にイベントを発生させる。
result 要素は、name 属性を設定することができるが、設定されていない場合は、常に、do 属性のイベントが発生し、
設定されている場合は、コントローラー内で addResult() 関数によって登録された name が存在する場合に、イベントが発生する。
views は、include 子要素を持ち、文字通り、ユーザーが受け取る画面を構成する情報を指定する。
include は、画面のどこ(name 属性)に、どのファイル(template 属性)による情報を表示するかを指定する。
また、include は、value 子要素を持ち、value 要素は、画面を構成する際に必要となる引数を設定する。

これらの振る舞いがどのような順番で処理されるかははっきりわからないが、ロジックを処理するために
コントローラーへメッセージを渡し(broadcasts)、画面のベースとなるテンプレート(html、head、bodyタグで構成される)を
書き起こし(results)、各画面ごとに異なる情報や、ロジックになどにより処理された情報などを表示(views)するという
流れで、サンプルが作られているようだ。

2008年04月17日

イベントの続きと、viewstate

イベントは、どうやって発生させるのだろうか。
方法は、二通りあるようだ。
一つめは、以前にも書いたように、event-handler の results => result 要素で発生させる。
二つめは、さらに、以前に書いたように、「URLの後ろに“event=<イベント名>”」として、リクエストによって、発生させる。
このイベント名がそのまま、発生するイベントとなっている。

この“event=<イベント名>”を省略した場合は、どうなるのか。
http://~~~/~~~/index.cfm とした場合である。
どうやら、ColdSpring.xml で定義されている、

 <beans>
  <bean id="modelGlueConfiguration" class="ModelGlue.unity.framework.ModelGlueConfiguration">
   <property name="defaultEvent"><value>page.index</value></property>
  </bean>
 </beans>

page.index が発生するらしい。
確かに、“イベント指定なし”と“event=page.index”では、同じ挙動になる。

他にも、exception
とあるように、エラーが発生すると、exception というイベントが発生するようだ。

この部分を見つけるまで、ColdSpring.xml の modelGlueConfiguration は、あまり注意してみていなかったけど、どうやら、
結構重要らしい。

サンプルなどを見ると、このイベントをリンクなどのURLに指定する際に、画面表示プログラム埋め込み文字列ではなく、
views => include => value で引数として画面表示プログラムへ渡している。
果たして、これにどれほどの意味があるのかわからないけど、引数の渡し方は、ここから、わかる。

この“xe.cartinsertitem”が引数の変数名で、“CartInsert”がその値となる。
“xe”という単語が気になるが、“eXit Event”を示しているらしい。
ただし、この“xe”という単語が機能上特別な意味を持っているのかは、わからなかった。

では、画面側で、それらの値を受け取る場合は、どうなるのか。
viewstate.getValue("xe.cartinsertitem")
とすることで、値を受け取れる。
viewstate というのは、コントローラーなど、ロジック上から、値を渡す場合などにも、この空間?に設定されるものである。

また、myself や、self という予約後もあり、viewstate.getValue("myself") とすると、
リクエストページが index.cfm の場合「index.cfm?event=」という値を得ることができる。

2008年04月18日

viewstate と viewcollection

前回、viewstate というものの読み解いた。似たような単語で、viewcollection というものがある。
前者が view の state 状態ということであれば、後者は、view の集合となるのだろうか。余計わかりにくいか。

画面表示プログラム上で、viewcollection.getView("body") としてやることで、画面表示を埋め込むことができる。
event-handler => views の要素、include で画面に埋め込むプログラムを設定する。
<include name="body" template="dspCart.cfm" />

viewcollection.getView("body") に、dspCart.cfm が埋め込まれるわけである。

viewcollection.getView("body")この記述は、event-handler の results => result 要素で生成した画面上でしか、
機能しなかったが、実際のところは、どうなのだろうか。
動いてくれると、便利なんだが。

コントローラーから画面に値を渡す場合は、どうなるのか。
viewstate で受け取れるようにする方法である。
<cfset arguments.event.setValue("cartData", cartData) />
こうすることで、cartDate という変数の cartDate という値を渡すことができる。
arguments.event というのは、重要な概念で、HTTP でいうところのイベントを意味している。
これは、リクエストも、レスポンスも含んでいるようである。

つまり、レスポンスで画面に値を渡すわけであるから、レスポンスというイベントに値を設定(setValue)するということである。

わかりにくいかもしれないが、ポストリクエストのポストデータを受け取るときも、このイベントを利用する。
<cfset var itemId = arguments.event.getValue("itemid") />
こうすることで、フォームの itemid という値を取得することができる。

このイベントは、コントローラー上でのみ、扱える空間のようだ。
もちろん、引数などで渡してやれば、どこでだって使えるのであるが、コントローラー上では、イベントを受け取ることを
書いてしまえば、受け取ることができる。
他にも、コントローラ上でのみ扱える ModelGule API とか、コントローラーは、いろいろ便利に使えるようである。

2008年04月21日

とりあえず、動くもの

サンプルアプリケーション
これまでの情報から、ものすごくシンプルなアプリケーションを作ってみた。
商品リストから商品を選んで、カートに入れるというよくあるカートアプリケーション。

作成したイベントは3つ。

 CartInsert
 CartDeleteItem
 CartDeleteAll

メッセージは、4つ。

 ItemList
 CartInsertAction
 CartDeleteItemAction
 CartDeleteAllAction

これらは、ModelGule.xml から見つけることができる。
Controller.cfc に、メッセージに対応する関数を一つずつで、4つの関数。
ロジックとして、CartProcess.cfc に、ロジックの関数として3つ。
データベースを使わなかったために、商品リストを保持する Common.cfc を作成。

やはり、これぐらいの規模の仕組みでは、フレームワークのメリットを感じることはできなかったが、Model-Glueの基本的な作り方は、把握できた。

dspIndex.cfm で商品リストを表示する際に、Controller.cfc の getItemList 関数で、変数 itemMasterArray に、
arguments.event.setValue("itemMasterArray", ★商品の一覧データ★)で、レスポンスデータに保存。
dspIndex.cfm の viewstate.getValue("itemMasterArray") で商品の一覧データを取得する。

商品を選択すると、イベント CartInsert で、商品IDをポストリクエスト送信すると、メッセージ CartInsertAction が発生する。
Controller.cfc の関数 cartInsertItem によって、ロジックのモデル CartProcess.cfc のインスタンスを生成し、
arguments.event.getValue("itemid") でポストデータ itemid を取得して、関数 insertItem に渡す。関数 insertItem からは、
カートのデータが戻ってくるので、arguments.event.setValue("cartData", ★カートのデータ★) で、画面に変数 cartData で渡す。

他のイベントの場合も、似たような感じになっている。
いわゆる、MVCが構築されているわけになるが、当然、理想は、理想で、実際にシステムを作っていく上では、
こんなにきれいに分かれないだろう。
ここでポイントになるのは、VとCの流れの調整を ModelGlue.xml だけで行うということだろうか。
ModelGlue.xml では、Mのモデル(ロジック)部分のことは、制御外になっている。コントローラーの先は、作り手次第になっている。

2008年04月22日

ColdSpring

ColdSpring を活用してみよう。
すでに ColdSpring の機能である、“DI”というものについての記述は、たくさんあるので、どのように使うかを見ていく。
よい題材が思いつかなかったので、Common.cfc で生成していた商品リストを「強引に」ColdSpring でやってみよう。
ColdSpring.xml に下記のように記述する。

 <bean id="itemArrayBean" class="shopping.model.ItemArrayBean">
  <property name="itemArray">
   <list>
    <map>
     <entry key="name"><value>光学式マウス</value></entry>
     <entry key="price"><value>2600</value></entry>
    </map>
    <map>
     <entry key="name"><value>ボール式マウス</value></entry>
     <entry key="price"><value>1100</value></entry>
    </map>
    <map>
     <entry key="name"><value>レーザー式マウス</value></entry>
     <entry key="price"><value>4800</value></entry>
    </map>
   </list>
  </property>
 </bean>

ここで注意しなければならないのは、Model-Gule は、ColdSpring.xml などのファイルを、OSのデフォルトエンコーディングを前提に
読み込んでいるらしく、Windows で動作させる場合は、Shift_JIS で保存しなければ、文字化けしてしまった。

 <?xml version="1.0" encoding="UTF-8"?>

としても、だめだった。他のOSでは試していないので、あくまで、推測である。
自動で判別してくれるとか、先頭行をチェックしてから読み込むということは、してくれないようである。

shopping.model.ItemArrayBean は、商品リストデータを保持するコンポーネント。
Java でいうところの、Bean ということになる。ColdSpring でも、この Bean という単語を採用している。
デフォルトでは、リクエストごとに、インスタンスが生成されているようだ。
固定値を保持するような Bean は、アプリケーションで1インスタンスでいいのだから、何かしら、やり方があるのだろうか。
singleton とかの記述もマニュアルにあるし、できそうな雰囲気もあるが、試していない。

では、実際に、これを利用するためには、どうすればよいのか。
コントローラーでは、非常に簡単に利用できる。
getModelGlue().getBean("itemArrayBean") これだけで、取得できてしまうのである。
Controller.cfc にある、onRequestStart 関数に
<cfset variables.itemArrayBean = getModelGlue().getBean("itemArrayBean") /> とすれば、Controller.cfc 上では、いつでも、利用可能になる。

また、あたかも、AutoWire のように、

 <cffunction name="setItemArrayBean" access="public" returnType="void" output="false">
  <cfargument name="itemArrayBean" type="any">
  <cfset variables.itemArrayBean = arguments.itemArrayBean />
 </cffunction>

としてやるだけでも、取得できてしまう。
「あたかも、AutoWire のように」としたのは、ColdSpring.xml の bean タグに、AutoWire の設定することなく、
setter 関数が処理されたためにこのような表現をした。コントローラーは、本当に特別なもののようだ。
AutoWire については、また、後日、読み解いてみたい。

2008年04月23日

ColdSpring で Bean へデータを渡す

では、コントローラーではないコンポーネントに ColdSpring の Bean を渡すには、どうすればよいのか。
ロジックの、CartProcess.cfc に itemArrayBean を渡す方法を考えてみよう。

bean タグは、子要素に、constructor-arg と、property を持つことができる。
constructor-arg は、コンストラクタの引数として渡すためのタグ。
property は、setter 関数で渡すためのタグとなっている。


 <bean id="shopping" class="shopping.model.CartProcess">
  <constructor-arg name="itemAB">
   <ref bean="itemArrayBean" />
  </constructor-arg>
 </bean>

と ColdSpring.xml に記述してやることによって、CartProcess.cfc の初期化の際に、引数で自動的に渡してくれるのである。
初期化の関数は、デフォルトで、init になっているようで、


 <cffunction name="init" returntype="any" access="public" output="false">
  <cfargument name="itemAB" required="true">
  <cfset variables.itemArray = arguments.itemAB.getItemArray() />
  <cfreturn this />
 </cffunction>

という記述を、CartProcess.cfc にしてやると、CartProcess.cfc 上で、いつでも商品リストデータが利用可能になる。

一方、

  <constructor-arg name="itemAB">
   <ref bean="itemArrayBean" />
  </constructor-arg>

を、

  <property name="itemAB">
   <ref bean="itemArrayBean" />
  </property>

とすると、自動的に、CartProcess.cfc にある、setItemAB という関数を探して itemArrayBean を渡してくれるのである。

再び、サンプルアプリケーションを作ってみた。
できることは同じであるが、ColdSpring を利用して、コントローラーへ、自動的に、データを渡している。

サンプルColdSpring

2008年04月24日

ColdFusion 版 Ruby on Rails その名も ColdFusion on Wheels

やはり、あるんだな。
ColdFusion on Wheels
どんなんだろうか。
あ、ColdFusion8 限定。しかも、DBが、SQLServer と、MySQL5 だけだ・・・。

AutoWire

さて、たびたび出てきた AutoWire とは、何か。
ColdSpring のドキュメントによると、

The term "autowire" refers to the ability of the ColdSpring beanFactory to automatically wire dependent objects together without necessarily having to define those dependencies in the xml bean definitions.

とある。
簡単に言うと・・・、説明は止めておこう。実際に、どのように動くのかを見た方がわかりやすい。
検索すれば、AutoWire も、いっぱい出てくる。もちろん、ColdSpring での情報は少ないが。

前回、

 <bean id="shopping" class="shopping.model.CartProcess">
  <property name="itemAB">
   <ref bean="itemArrayBean" />
  </property>
 </bean>

このような記述をした。
ColdSpring.xml の Bean は、基本的にリクエストごとに、初期化される。
shopping.model.CartProcess を初期化する際に、setItemAB 関数を探して、引数として、itemAB という名前で、itemArrayBean を
渡して処理しなさいということであった。

AutoWire を使えば、この記述が以下のように簡単になる。

 <bean id="shopping" class="shopping.model.CartProcess" autowire="byName" />

autowire="byName" をautowire="byType" とすることもできる。
要するに、Bean を受け取りたい側(この場合は、CartProcess.cfc)で、setter 関数を記述さえすれば、取得できるわけである。

byName と、byType は、どう違うのか。名前と型なわけで、全く違うわけだが、byName であれは、setItemAB と名前で探すのに対し、

<bean id="shopping" class="shopping.model.CartProcess" autowire="byType" />


<cfargument name="itemArrayBean" type="shopping.model.ItemArrayBean" />

byType の場合は、setter 関数の名前は set で始まっていればよく、引数の受取の型指定が一致しているものを探すわけである。

同じ型で複数の Bean を作りたい場合には、byName にすることになるだろう。
byTypeの方は、すでに setter 関数があって、名前が重複してしまった場合などに利用することになるだろう。

基本的には、好みで決めればいいのだろう。byType の方が、好みだ。

2008年04月28日

ColdFusion on Wheels

ColdFusion on Wheels をちょっとやってみた。

http://ドメイン/アプリケーションディレクトリ/index.cfm/●●●●/▲▲▲▲?reload=development

?以下(URL引数)は、なしでもよい。

index.cfm で終わる場合、
/cfwheels/config/routes.cfm の最初の addRoute の Route が処理される。
デフォルト状態では、

のみなので、コントローラー main.cfc の welcomeToWheels という関数が処理され、
/cfwheels/view/main/welcomeToWheels.cfm という画面が表示される。

上記URLの場合、コントローラー ●●●●.cfc の ▲▲▲▲ という関数が処理され、
/cfwheels/view/●●●●/▲▲▲▲.cfm という画面が表示される。
このとき、routes.cfm の記述は要らないようだ。

最後にある ?reload=development のURL引数は、実際にはこのように使うのかわからないが、
こうすることで、application.settings.environment に値を設定できる。
もちろん、この記述をしないのが普通。
この値により、/cfwheels/config/environments/ の中の、それぞれ対応するファイルを読み込むようにできる。
現状、design とか、development、production などだ。

/cfwheels/config/environment.cfm の中で、この値を設定しているいるが、この値を変えても、
初回起動時(アプリケーションのスタート時)にしか変わってくれないので、強制的に変えたいときに使うのかもしれない。

コントローラーの関数内で設定した変数

は、view の画面ファイル内で、
#testValue#
など、そのまま使えるようにしてくれるようだ。
これは、簡単で便利なんだけど、逆に、想定できないようなバグを発生させる危険性もあるだろう。

バージョンが 0.7 ということで、まだまだ、これからのようだ。
ファイルの一覧を眺めても、基本的なことしかできないのかなぁと感じる。
これからに期待ってことで。

cfcUnit

テスティングフレームワークというものも、大規模開発向けなんだろうと思いつつ、流してきた。
折角、Model-Glue でCFコンポーネントにロジックをまとめることを調査しているので、
この機に、ちょっと調べてみよう。
cfcUnit と、CFUnit というものがあるらしいけど、最初に見つけた cfcUnit を調査。

http://sourceforge.net/project/showfiles.php?group_id=100854&package_id=126568

から、ファイルを拾ってくる。現在、1.2.0 beta1 らしい。
cfcUnit ディレクトリと、org ディレクトリを WEB のルートに入れる。
この2つに分かれているディレクトリにどういう意味があるのかは、わからない。

余談だが、cfcUnit は、Mac で開発してるようだ。

http://localhost/cfcunit/index.cfm でテスト実行用画面が表示される。
cfcunit.tests.AllTests というあらかじめ用意されているテストプログラムをテストしてみる。
「Run Test」ボタンを押すと、程なく、テスト完了。

では実際に、テストプログラムを作ってみよう。
今まで使ってきた shopping.model.CartProcess というCFコンポーネントのテストプログラムを作成する。

org.cfcunit.framework.TestCase を継承(extend)して、test で始まる関数を作ればいいようだ。
ここで問題が。この CartProcess コンポーネントは、ColdSpring によるDIを使っているので、そのままでは利用できない。

ColdSpring の機能を Model-Glue 経由で利用しているため、純粋に ColdSpring を利用する方法で初期化することになる。

 <cfset variables.cartProcess = "">
 <cffunction name="setUp" returntype="void" access="private">
  <cfset testBeanFactory = createObject("component","coldspring.beans.DefaultXmlBeanFactory").init()/>
  <cfset testBeanFactory.loadBeansFromXmlFile("/shopping/config/ColdSpring.xml",true)/>
  <cfset variables.cartProcess = testBeanFactory.getBean("cartProcess")>
 </cffunction>

この記述を使って CartProcess インスタンスを取得すればよい。setUp という初期化関数が使えるようだ。

そして、いろんなテストを作成する。
実際にテストを作成してみると、いろんなことを考えないといけないことがよくわかる。
予想はしていたけど、このテストプログラムを作るのは、仕様についても、プログラム言語のことも、
よく理解した上で作らないといけない。
このテストプログラムを作るのにもそれなりの工数がかかると思うのだが、実際の開発では、どれぐらい生産性が上がるものなのだろうか。

こうして作成した CartProcessTest.cfc を CartProces.cfc を同じディレクトリに入れる。
どのようなテストが入っているかは、http://localhost/shopping/model/CartProcessTest.cfc で一覧できる。
テスト実行用画面で、shopping.model.CartProcessTest をテストしてみる。

実際にテストしてみると、一つテストが失敗する。
カートに一つしか商品がない場合に削除ボタンを押しても、カートから削除できないという不具合がある。
CartProces での手抜きがばれてしまうわけだが、ちゃんと作り込んでやれば、全てのテストをクリアできる。

複数のテストプログラムをまとめるために、suite という概念があるようだ。
複数のコンポーネントをテストする場合に、便利なのだろう。

また、cfcUnit には、FLEX で作られたテスト実行用画面もある。
http://localhost/cfcunit/flex/index.html
でその画面が見られるだろう。FLEX だからどうなんだ。と言われても、困るというものだ。

2008年04月30日

ColdSpring によるAOP(Aspect Oriented Programming)

ColdSpring のDIコンテナとセットで、AOPというものが解説されることがある。
これも、たくさん記述があるので、それを読んでみても、何がどう便利でどう簡単なのかが、ピンと来ない。
というわけで、実践。

ColdSpring AOP Tutorial - Part Oneとか、ColdSpring ドキュメントや、ColdSpring のサンプルからちょっとコードを拝借。

ログを書き出す機能を、これまでのアプリケーションに、AOP手法で実装してみる。

とりあえず、どれぐらい簡単なのかを確認するために、ログ機能を利用するための諸設定などは、すでに行われているものとすれば、実に、簡単である。

やろうとしていることは、shopping.model.CartProcess コンポーネントの関数を実行するたびに、ログを書き出すようにしたい。
ということで、それには、ColdSpring.xml の中の、

 <bean id="shopping" class="shopping.model.CartProcess" autowire="byType" />

これを


 <bean id="cartProcessTarget" class="shopping.model.CartProcess" autowire="byType" />
 
 <bean id="shopping" class="coldspring.aop.framework.ProxyFactoryBean">
  <property name="target">
   <ref bean="cartProcessTarget" />
  </property>
  <property name="interceptorNames">
   <list>
    <value>loggingAdvisor</value>
   </list>
  </property>
 </bean>

とするだけである。
が、実際、簡単なんだと思えるまで、結構時間がかかった。

2段階でコンポーネントのインスタンスを取得していることになる。
こうして得られる shopping インスタンスは、coldspring.aop.framework.ProxyFactoryBean ではなく、
あたかも shopping.model.CartProcess そのもののように、扱うことができる。

そして、shopping 上の関数を利用すると、ログ書き出しが機能してしまうのである。
既存の shopping.model.CartProcess のコードを書き換えることなく、機能追加を実装できてしまった。

いやいや、ログを取る場合は、もっと細かいレベルで、見たいのではないかと。
例えば、shopping.model.CartProcess の関数は、「カートに商品を入れる」というものであり、
このログ機能が処理されるタイミングは、shopping.model.CartProcess の関数が実行される前、後、その両方、
そして、エラーが発生した場合で設定できる。
既存の関数にログをはき出す機能を付けても、それでは、たいした効果は期待できない。

AOPとは、再利用可能でシンプルな見やすいプログラムを作ることが目的の一つになっている。
例えば、データベースに対して、引数で与えたSQL文を発行するだけというような、再利用できる低レベルでの関数であれば、
その関数の前後などで、ログを書き出すことは、意味を持ってくるのだろう。

また、ログに限らず、AOPは、トランザクション処理や、キャッシュ処理、権限チェック処理などが利用例としてあげられており、どのようなものを実装するかで、意義は変わってくるのだろう。

2008年05月01日

AOPの実装

では、どのようにAOPを実装するのかを見ていく。

前回のログを書き出すコードとして拝借したファイルは、LogginAroundAdvice.cfc と LoggingService.cfc の2つ。
LoggingService.cfc は、ログを書き出すだけのコンポーネント。
LogginAroundAdvice.cfc は、ログの機能を追加しようとしている関数に対して、どういうタイミングでログを書き出すかを
指定(Advice)するためのコンポーネント。

Advice という用語が出てきた。これが実にわかりにくい。
今でも、はっきりわかっていない。おぼろげな認識では、
“どういう機能(ログ書き出し)をどのタイミング(前、後、前後、エラー時)で提供”するかということだろうか。
そして、Advisor というものもある。その Advice を“どういうものに付け加えるかを指定”するとでも言うのだろうか。
ドキュメントの英文を読んでも、ピンと来ないし、困ったものだ。


 <bean id="loggingService" class="shopping.model.aop.component.LoggingService" />
 
 <bean id="loggingAdvice" class="shopping.model.aop.aspects.LoggingAroundAdvice">
  <property name="loggingService">
   <ref bean="loggingService">
  </property>
 </bean>
 
 <bean id="loggingAdvisor" class="coldspring.aop.support.NamedMethodPointcutAdvisor">
  <property name="advice">
   <ref bean="loggingAdvice" />
  </property>
  <property name="mappedNames">
   <value>*</value>
  </property>
 </bean>

ColdSpring.xml で、このように設定する。
loggingService という Bean を設定し、その機能を AroundAdvice する loggingAdvice を設定。
任意の関数名で処理を織り込む(Weave)loggingAdvisor を設定。

これにより、ログ機能(shopping.model.aop.component.LoggingService)をAOPで利用するための準備が整う。

前回の

 <bean id="shopping" class="coldspring.aop.framework.ProxyFactoryBean">
  <property name="target">
   <ref bean="cartProcessTarget" />
  </property>
  <property name="interceptorNames">
   <list>
    <value>loggingAdvisor</value>
   </list>
  </property>
 </bean>

で、bean id="shopping" に引数 interceptorNames で渡している loggingAdvisor が上記の設定でできるのである。

サンプルアプリケーション

2008年05月02日

Transfer

いよいよ、Transfer だ。
ちょうど、Transfer 1.0 RC がリリースされたようだ。
気になったのは、この2点。

 ・Composite Key Support
 ・Transaction Support

Composite Key ってなんぞや?
今まで、データベースの主キーとして、カラム一つしか指定できなかったっぽいのが、複数のカラムが指定できるようになったということなのだろうか?
どうやら、複数のカラムが指定できるようになったらしい。が、項目として指定できるのは、1つのみで、あとは、外部参照の項目を指定することのようだ。
基本的に正規化してテーブル設計すれば、問題はなさそうだけど、大丈夫なんだろうか。
古いシステムのテーブル設計によく見られる、4つとか、5つとかの項目からなる主キー設定で、なおかつ、
正規化してある訳じゃないテーブルには、使えないということか。

いよいよ、Transfer を読み解いていくことになるわけだが、まずは、データベースを作らなければいけない。
データベースは、環境に非常に影響を受けるので、著しく汎用性が落ちてしまうのが困りものだけど、仕方ない。

とりあえず、慣れている PostgreSQL で作成する。
バージョンは、8.1 だ。

table_01.gif

各テーブルの意味は、そのまんまだから、わかるだろう。
ちなみに、SERIAL 型というのは、データ挿入でオートインクリメントしてくれる INT 型。

データベース作成

createdb -E UNICODE SHOPPING

テーブル作成

CREATE TABLE public.CATEGORYMST (
categoryid INT NOT NULL
, categoryname TEXT NOT NULL
, PRIMARY KEY (categoryid)
);

CREATE TABLE public.ITEMMST (
itemid SERIAL NOT NULL
, lnkcategoryid INT NOT NULL
, itemname TEXT NOT NULL
, price INT NOT NULL
, PRIMARY KEY (itemid)
);

CREATE TABLE public.CARTDATA (
sessionid CHAR(32) NOT NULL
, lnkitemid INT NOT NULL
, categoryname TEXT NOT NULL
, itemname TEXT NOT NULL
, price INT NOT NULL
, PRIMARY KEY (sessionid, itemid)
);

データ登録

INSERT INTO CATEGORYMST (categoryid, categoryname) VALUES (1, 'マウス');
INSERT INTO CATEGORYMST (categoryid, categoryname) VALUES (2, 'キーボード');

INSERT INTO ITEMMST (itemid, lnkcategoryid, itemname, price) VALUES (1, 1, '光学式マウス', 2600);
INSERT INTO ITEMMST (itemid, lnkcategoryid, itemname, price) VALUES (2, 1, 'ボールマウス', 1100);
INSERT INTO ITEMMST (itemid, lnkcategoryid, itemname, price) VALUES (3, 1, 'レーザー式マウス', 4800);
INSERT INTO ITEMMST (itemid, categoryid, itemname, price) VALUES (4, 2, 'テンキー付きUSBキーボード', 1800);
INSERT INTO ITEMMST (itemid, lnkcategoryid, itemname, price) VALUES (5, 2, 'テンキーなしUSBキーボード', 1200);
INSERT INTO ITEMMST (itemid, lnkcategoryid, itemname, price) VALUES (6, 2, 'テンキー付きPS/2キーボード', 1100);
INSERT INTO ITEMMST (itemid, lnkcategoryid, itemname, price) VALUES (7, 2, 'テンキーなしPS/2キーボード', 900);
SELECT SETVAL('ITEMMST_itemid_seq', MAX(itemid)) FROM ITEMMST;

これで、データベースの準備はできた。次は、Transfer の設定だ。

2008年05月07日

Transfer の設定

例のごとく、今までのサンプルアプリケーションを変更していく。

まずは、config/transfer/Datasource.xml から。

<datasource>
 <name>shopping</name>
 <username></username>
 <password></password>
</datasource>

ColdFusion の管理画面で、データソースを設定して、その名前を入れるだけ。

次に、config/ColdSpring.xml 。今までコメントアウトしてきたところだ。

<alias alias="ormAdapter" name="ormAdapter.Transfer" />
<alias alias="ormService" name="ormService.Transfer" />
<bean id="transferConfiguration" class="transfer.com.config.Configuration">
 <constructor-arg name="datasourcePath"><value>/shopping/config/transfer/Datasource.xml</value></constructor-arg>
 <constructor-arg name="configPath"><value>/shopping/config/transfer/Transfer.xml</value></constructor-arg>
 <constructor-arg name="definitionPath"><value>/shopping/model/data/transfer</value></constructor-arg>
</bean>

この状態でアプリケーションが動くかどうか確認してみよう。
Model-Glue デバッグの2行目に、Using ORM Adapter: com.adobe.hs.common.orm.TransferAdapter とか表示されるだろうか。
なにかエラーのようなものがなければ、OKだ。

いよいよ、Transfer の肝、config/transfer/Transfer.xml 。

<objectDefinitions>
 <package name="master">
  <!-- Category -->
  <object name="Category" table="CATEGORYMST">
   <id name="PKeyCategoryId" type="numeric" column="categoryid" />
   <property name="CategoryName" type="string" column="categoryname" />
   <onetomany name="CategoryItemLink" lazy="true">
    <link to="master.Item" column="lnkcategoryid" />
    <collection type="struct">
     <key property="ItemId" />
    </collection>
   </onetomany>
  </object>
  <!-- Item -->
  <object name="Item" table="ITEMMST" sequence="ITEMMST_itemid_seq">
   <id name="PKeyItemId" type="numeric" column="itemid" generate="false" />
   <property name="ItemName" type="string" column="itemname" />
   <property name="Price" type="numeric" column="price" />
   <manytoone name="ItemCategoryLink" lazy="true">
    <link to="master.Category" column="lnkcategoryid" />
   </manytoone>
  </object>
 </package>
</objectDefinitions>

たぶん、いきなり見ても、わからないだろう。
package は、Transfer 上での意味しかなく、テーブルをグループ化するためのもの。
object は、テーブル。id は、主キーカラム。property は、カラム。
onetomany 、manytoone 、は、他のテーブルとのリレーション設定。
これだけ把握した上で、ざっと眺めれば、なんとかわかってくるだろうか。

Model-Glue3 Gesture

ちょくちょく参考にさせてもらってるなんちゃってCF-OOP!で、Model-Glue の次期バージョンの話が出てた。Model-Glue3(Gesture)αリリース!
なにやら、いろいろと機能が追加されるようだけど、個人的には、Model-Glue3.0の新機能1:イベント自動生成が気になる。
Model-Glue などのフレームワークで一番の(個人的な)不都合は、設定ファイルをXMLで書かなきゃいけないことだと思っている。
そんな不満をある程度解消してくれそうな機能なのではないのだろうか。

例えば、だいぶ前に WebSphere で IBM謹製 Studio を使ったときに、設定ファイルは、入力ボックスに各種設定の文字を入れていくようなウィンドウが表示されて、XMLタグを見ることなく設定できた。
XMLファイルというのは、慣れていればいいのかもしれないが、経験の少ない開発者にとって敷居が高いものだと勝手に断定している。

一番いいのは、部品をドラッグアンドドロップとかで配置して、グラフィカルにMVCの流れが見えることだと思うけど、そんなのはかなり厳しい話で、WebSphere のようなものが妥当な線なんだと思う。

Model-Glue のイベント自動生成機能は、イベント名を起こすだけで、ある程度の設定をしてくれるということだから、ゼロから設定ファイルを書くのではなく、都度変更すればよいわけだ。
ゼロからと、変更するだけでは、大きな違いがあると思うし、かなり敷居が低くなるんじゃないかと思う。

今までのようにXMLを直接編集するしかないとか、(あくまで個人的に)作業効率が悪いままでは、結局フレームワークというものが、万人向けではなく、特定層向けツールで終わってしまっているというのが現状ではないだろうか。
なにしろ、ColdFusion の最大の特徴である、「未経験開発者の一定レベル到達時間が短い」を打ち消しかねない。
ちょっと言い過ぎた気もするけど、一向に ColdFusion のフレームワークの情報が世の中に増えてこないのは、その辺にあるのじゃないだろうか。
Model-Glue の新機能に期待である。

2008年05月08日

Transfer の利用

では、Transfer を利用するように書き換えてみる。

ColdSpring.xml で設定していた、販売商品のマスタデータをデータベースから取得するようにするため、下記のように書き換え。

<bean id="itemArrayBean" class="shopping.model.ItemArrayBean">
 <property name="itemArray">
  <list>
   <map>
    <entry key="name"><value>光学式マウス</value></entry>
    <entry key="price"><value>2600</value></entry>
   </map>
   <map>
    <entry key="name"><value>ボール式マウス</value></entry>
    <entry key="price"><value>1100</value></entry>
   </map>
   <map>
    <entry key="name"><value>レーザー式マウス</value></entry>
    <entry key="price"><value>4800</value></entry>
   </map>
  </list>
 </property>
</bean>

 ↓

<bean id="itemArrayBean" class="shopping.model.ItemArrayBean" autowire="byType" />

マスタデータを設定する必要が無くなるため、ばっさり、削除。
その代わり、AutoWire で Bean を注入。

何を注入するのか。shopping.model.CartProcess に以下のコードを追加する。

<cffunction name="setOrmService" access="public" returntype="void" output="false">
 <cfargument name="ormService" type="transfer.TransferFactory" required="true">
 <cfset variables.transfer = arguments.ormService.getTransfer() />
</cffunction>

前回設定した ormService を渡して取得する Transfer オブジェクトを利用してデータベースからデータを取得するようにするのである。
この ormService は、type を見ればわかるように、transfer.TransferFactory である。

一方、ormAdapter の正体は、ModelGlue.unity.orm.transfer.TransferAdapter で、どうやら、Model-Glue が用意してくれたもののようだ。
いっそのこと、抽象クラスかインターフェースかなんかにキャストして、O-R マッピングで汎用的に使えるようになっていれば、おもしろそうだけど、俺が何か間違っているのだろうか。

shopping.model.ItemArrayBean で Transfer オブジェクトを受け取り、データを取得して、既存の戻り値と同じものを返せば、商品一覧をデータベースから取得して表示するだけなら、書き換えるプログラムは、この ItemArrayBean だけとなる。

2008年05月09日

Transfer がうまく動かない

Transfer の迷宮をさまよい中。
とりあえず、以前書いた

<objectDefinitions>
 <package name="master">
  <!-- Category -->
  <object name="Category" table="CATEGORYMST">
   <id name="CategoryId" type="numeric" column="categoryid" />
   <property name="CategoryName" type="string" column="categoryname" />
   <onetomany name="CategoryItemLink" lazy="true">
    <link to="master.Item" column="CategoryId" />
    <collection type="struct">
      <key property="ItemId" />
    </collection>
   </onetomany>
  </object>
  <!-- Item -->
  <object name="Item" table="ITEMMST" sequence="ITEMMST_itemid_seq">
   <id name="ItemId" type="numeric" column="itemid" generate="false" />
   <property name="ItemName" type="string" column="itemname" />
   <property name="Price" type="numeric" column="price" />
   <manytoone name="ItemCategoryLink" lazy="true">
    <link to="master.Category" column="categoryid" />
   </manytoone>
  </object>
 </package>
</objectDefinitions>

は、だめのようだ。

<objectDefinitions>
 <package name="master">
  <!-- Category -->
  <object name="Category" table="CATEGORYMST">
   <id name="CategoryId" type="numeric" column="categoryid" />
   <property name="CategoryName" type="string" column="categoryname" />
   <onetomany name="CategoryItemLink" lazy="true">
    <link to="master.Item" column="CategoryId" />
    <collection type="struct">
      <key property="ItemId" />
    </collection>
   </onetomany>
  </object>
  <!-- Item -->
  <object name="Item" table="ITEMMST" sequence="ITEMMST_itemid_seq">
   <id name="ItemId" type="numeric" column="itemid" generate="false" />
   <property name="ItemName" type="string" column="itemname" />
   <property name="Price" type="numeric" column="price" />
  </object>
 </package>
</objectDefinitions>

外部参照なわけで、相互に参照するような設定にしてはいけない。
相互に参照しないと、双方から参照できないと思っていたら、そんなことはないようだ。

カートのデータをデータベースに登録するプログラムに変更しようとして、面倒な問題に直面。
カートのデータを全消去というコードがなんとも、面倒だ。

もちろん、従来のO-R マッピングを利用しない書き方に比べて面倒ということではなく、折角の Transfer が意味のないコードになってしまうということだ。
やっぱり、Transfer を意識したテーブル設計をしなければならない。

テーブル CARTDATA をヘッダと明細に分けよう。
さて、引き続き、さまようか。

2008年05月12日

なんとか

なんとか、Transfer の迷宮を抜け出せつつある。もちろん、Transfer のほとんどの機能を把握したという意味ではない。

テーブルを下図のように変更。
table_02.gif

CREATE TABLE public.CARTHEADER (
sessionid VARCHAR(32) NOT NULL
, createdate TIMESTAMP NOT NULL
, updatedate TIMESTAMP NOT NULL
, PRIMARY KEY (sessionid)
);

CREATE TABLE public.CARTDATA (
lnksessionid VARCHAR(32) NOT NULL
, lnkitemid INT NOT NULL
, categoryname TEXT NOT NULL
, itemname TEXT NOT NULL
, price INT NOT NULL
, quantity INT NOT NULL
, PRIMARY KEY (lnksessionid, lnkitemid)
);

ついでに、カートデータとして、各商品の個数を登録できるようにした。

主キーに、固定長の文字列を設定して、バイト長が足りない文字列を入れることは、御法度らしい。
他にも、実際にやってみるとわかる Transfer のクセというか作法もちょこっとずつわかってきた。

サンプルアプリケーション

ColdFusion-Style フォーラムで話題があがっていたけど、アプリケーションフレームワークは色々あるが、DIコンポーネントは ColdSpring 、O-Rマッパーは、Transfer を選択する人が多いのだろうか。
アプリケーションフレームワークは ColdBox が流行なのかな。なにやら、Eclipse のプラグインがあるみたいだし、ちょっと読んでみる必要があるのかな。

目下の悩み事は、CFタグのコードと、cfscriptのコードが入り交じっていることだ。
全部CFタグにしたほうが、統一感があっていいのだけど、各種ドキュメントのサンプルコードが cfscript で書いてあったり、ちょっとだけコーディング量が少なかったりと、cfscript で書いちゃう場所もある。
どちらかに全て統一となると、cfscript に統一ということはできないようだから、やっぱり、CFタグの方がいいのかなぁ。

2008年05月13日

Transfer のトランザクション処理

サンプルアプリケーションは、データベースのトランザクション処理ができていない。
こんなアプリケーションが許されるわけはないので、トランザクションを実装しなければならない。
トランザクションはどのように実装するのか。

やり方としては、コンポーネント内の指定した関数を丸ごとトランザクション処理するというイメージになる。
shopping.model.CartProcess の transfer.TransferFactory を AutoWire したタイミングで、transfer.TransferFactory から transfer.com.sql.transaction.Transaction を取得する。

<cffunction name="setOrmService" access="public" returntype="void" output="false">
 <cfargument name="ormService" type="transfer.TransferFactory" required="true">
 <cfset variables.transfer = arguments.ormService.getTransfer() />
 <cfset variables.transaction = arguments.ormService.getTransaction() />
</cffunction>

その Transaction を利用して、

 <cfset transaction.execute(component, methodName, [arguments]) />

と、直接的に関数をトランザクション指定で起動することもできる。
直接指定の場合は、その関数を利用するときに、上記の記述で利用することになる。

また、AOPのように記述して、関数を指定することで、指定した関数が丸ごとトランザクション処理されるようだ。
この記述の場合は、事前に行っておくことで、その関数を通常のように利用した場合でも、トランザクション処理されることになる。

<cffunction name="setOrmService" access="public" returntype="void" output="false">
 <cfargument name="ormService" type="transfer.TransferFactory" required="true">
 <cfset variables.transfer = arguments.ormService.getTransfer() />
 <cfset variables.transaction = arguments.ormService.getTransaction() />
 <cfset variables.transaction.advise(this, insertItem) />
</cffunction>

さらに、

 <cfset arguments.transaction.advise(this, "^save") />

と、正規表現で一括してトランザクション処理指定もできる。
トランザクションで処理したい関数を save で始まる関数名にしておけば、簡単に一括指定できる。

2008年05月14日

ColdBox やってみた

ColdBox を動かしてみよう。

もう、こんなの

や、こんなの

が表示されるだけで、「おぉ」と思ってしまうのは、よくない傾向だ。
我ながら、つくづく、見た目に騙されやすい。と思う。実際に役に立つ情報が表示されているのかどうかは、謎。

ColdBox 公式から、ダウンロードしてきて、解凍したファイルを WEBROOT に配置。
その中の ApplicationTemplate をコピーして、このディレクトリの名前を適当に変える。

とりあえず、これだけで、先ほどのような画面が表示されるようになる。

ここにあった Eclipse のプラグインのインストールができなかった。
バージョンが europa ではだめなのか、はたまた、Eclipse に色々つっこみすぎているのがいけないのか。

なんだか、ドキュメントの項目だけを見ても、機能がいっぱいあるように見える。
個人的には、Model-Glue のようにシンプル設計がいいと思うのだけど、実際のところは、どうなのか。

Model-Glue で作っていたサンプルアプリケーションを移植してみようとしたら、文字化けした・・・。
character_error.gif

2008年05月15日

Ant に注意

前回の文字化けは、ColdBox 上の問題ではなく、Ant 上の問題だった。
やはり、慣れないものを使うときは、慎重にしないといけないということか。

ColdBox のパッケージに含まれる ApplicationTemplate に入っている build.xml を使うときは、

<filterchain>
 <concatfilter prepend="header.txt"/>
</filterchain>

を削除するなり、コメントアウトするなりしよう。

Ant のコピーコマンドは、通常そのままファイルをコピーするのだけど、filter 設定があると、ファイルを開くわけで、その際に、デフォルトではOSデフォルトエンコーディングでファイルを開く。
ファイルが異なるエンコーディングで保存してある場合、問題があるわけで、その結果、ファイルを保存することになると、文字化けする。copy コマンドに encoding 属性を付けるという手もある。

また、上記の Ant 設定は、全てのファイルの先頭に、header.txt の内容を挿入するという内容らしい。
その header.txt も、Ant が都度書き出していて、内容は、CFML のコメントになっている。
CFML のファイルだけなら、いいのだが、外部スタイルシートファイルや、JavaScript ファイルにも入れてしまって、結果、エラーが発生する。

こんなことで、半日以上費やしてしまった・・・。

2008年05月16日

Model-Glue から ColdBox への移植

なんとか、Model-Glue 版ショッピングカートを ColdBox 版ショッピングカートに移植完了。
でも、View 周りがなんとなく、汚い気がする。

基本的には、両者とも、MVCフレームワークなわけで、「とりあえず作ってみました」的なレベルでは、大して差はなかった。

Controller に当たる handler で、設定することなく(Model-Glue は、設定することなく、setter 関数を入れるだけ) AutoWire はしてくれなかったので、handler 上の init 関数などで以下のように、取得する必要がある。

<cffunction name="init" access="public" returntype="any" output="false">
 <cfargument name="controller" type="any">
 <cfset super.init(arguments.controller)>
 <cfset variables.shopping = getPlugin("ioc").getIoCFactory().getBean("shopping") />
 <cfset variables.itemArrayBean = getPlugin("ioc").getIoCFactory().getBean("itemArrayBean") />
 <cfreturn this>
</cffunction>

こうしておけば、handler が初めてよびだされるときに、ColdSpring で設定された Bean を呼び出してくれるのであろう。

また、Model-Glue では、XMLファイルで処理のフローを設定していたものが、ColdBox では、上記の handler 内でほとんど行うようだ。
ApplicationRoot
 ┗handlers
  ┗gengeral.cfc
gengeral.cfc という handler があって、その中に書かれている関数がイベント名になる。
例えば、gengeral.cfc に、CartView という関数があるとすると、gengeral.CartView というイベントを駆動させると、その CartVew 関数が処理される。

あとは、TransferFactory など、AutoWire 関連の記述を書き換えるぐらいでモデルなどのコードは、ほとんど変更しなかった。この辺りは、さすがである。
当然、画面表示周りの部分は、それなりに書き換える必要がある。イベント名の作法が変わるわけだし、画面表示自体の作法が変わる。

個人的な問題として気になることがあった。
開発する際、WEBサーバー(Windows マシンで、IIS)のドキュメントルートにプログラムを置くのではなく、リポジトリとして決めてある場所にプログラムを保存して、実行は、IIS 上で仮想ディレクトリを設定してある。
プログラムを変更した場合、保存後、すぐに、ブラウザのF5リフレッシュで変更結果を確認している。

ColdBox でそのように作成しようとしたら、なぜか、エラーが発生してしまった。設定があるのかもしれないが、わからなかったので、結局、Ant を使って、WEBサーバーのドキュメントルートに配置していたわけで、結果、前回のようなエラーにも遭遇した。
ColdBox のイメージがちょっぴり悪くなってしまった。もちろん、ColdBox は悪くないのだろう。あくまで、個人的な問題だ。

2008年05月19日

ColdBox の CFEclipse 用便利小物

折角なので、もうちょっと ColdBox をやってみる。

ColdBox は、Eclipse(CFEclipse)で開発することを意識しているようで、いろいろと便利小物を用意してくれている。

以前、インストールに失敗したプラグインが、改めてインストールしたら、あっさり完了した。
これは、ヘルプファイルのようで、
help.gif
Eclipse 上でヘルプを参照できる。

また、WEBのルートにインストールした coldbox ディレクトリにある install ディレクトリ内に cfeclipse_dictionary と cfeclipse_snippets がある。
dictionary の方が、コード補完用のファイルで、snippets の用が、スニペット用のファイルとなっている。
コード補完は、あるのとないのでは、全然違ってくるので、ありがたい。
Eclipse のインストールディレクトリにある Plugins / org.cfeclipse.cfml_1.3.1.6 / dictionary に
dictionaryinstall.gif
とコピーして、その場所にある dictionaryconfig.xml を
dictionaryssetting.gif
と変更する。そうすれば、
autosuggest.gif
のようにコード補完してくれる。しかし、cfscript 内の場合は、してくれなかった。
autosuggest2.gif
なにか、間違っているか、設定があるのか、「そんなのは、自分で加工しろよ!」なのか。
snippets については、ちょっとした発見(自分が知らなかっただけだけど)があって長くなりそうなので、また、後日。

2008年05月20日

ColdBox の CFEclipse 用便利小物2

CFEclipse にある、snippets という機能。
昔々の ColdFusion Studio という開発環境からあった機能だ。Dreamweaver にもあったかなぁ。

さて、ColdBox 用 snippets のインストール。
Eclipse のワークスペースにある .metadata / .plugins / org.cfeclipse.cfml / snippets に cfeclipse_snippets の coldbox ディレクトリを入れる。
snippetsinstall.gif
いままで入れたことがなければ、keyCombos.properties というファイルがあるだけだろうか。
ちょっと自前 snippets を入れてあるので、いろいろ入っているけど、こんな感じ。
再起動して、ちゃんと Eclipse が認識すれば、こうなる。
snippets.gif

次に、cfeclipse_snippets にある、keyCombos.properties で、既存の keyCombos.properties を上書きするのではなく、内容をコピーする。
このファイルの存在というか機能を、今回初めて知ったぐらいなので、空だったから、上書きしても問題なさそうだった。
さて、この keyCombos.properties とは、なんだろうか。
実は、なかなかの優れものだった。今回初めて知ってかなり驚いた。
keycombos1.gif
例えば、switch と入力した状態で、Ctrl + J とキーをたたくと、
このようなダイアログが表示される。
keycombos2.gif
ここで入力して OK ボタンを押すと、
keycombos3.gif
こんな風になるのだ。思わず「おぉ」と声が出てしまった。
snippets とは、本来こういうものだったことを知らなかった。
しかし、この機能が使えない単語で Ctrl + J を押すと、
keycombos_error.gif
こういうダイアログが出てしまうのは、どうしたものか。

で、Snippets で ColdBox に関するコードが出てくるというわけで、なかなか便利そうである。
ほしいものがなければ、自分で作れということでもある。
これは、ColdBox ネタというより、CFEclipse ネタか。

2008年05月21日

Model-Glue のコード補完

Model-Glue の Eclipse 用のコード補完設定ファイルを作ってみた。
modelglue.xml
インストールの仕方は、以前のエントリを参照。

また、関数へのマウスオーバーでポップアップするヘルプを公式ドキュメントから抜き出して日本語訳してみたが、間違いもあるだろう。
仕様として、同じ関数名があると後に定義されたヘルプが出てしまうようなので、同じ関数名は、属するオブジェクトを連ねて表示し、両対応の当たり障りのない(中途半端な)ヘルプ文章にした。

以下、ちょっと用語解説。

続きを読む "Model-Glue のコード補完" »

2008年05月22日

Scaffold

まず、前回の modelglue.xml をちょっと更新した。
ファイル modelglue-02.xml 。念のためファイル名は変えておいた。コード補完部分は変わっていない。

では、今回の本題。Scaffold という機能もなかなか便利。
サンプルアプリケーションでいうと、Transfer.xml に記述してあるオブジェクトを指定して Scaffold を設定すると、そのオブジェクトのデータ管理ができる機能が自動で生成される。
以下のように ModelGlue.xml に一行付け加えるだけで、その機能ができてしまうのである。

<event-handlers>
 ……
 <scaffold object="master.Item" />
</event-handlers>

で、http://localhost/shopping/index.cfm?event=master.Item.list にアクセスすると、そのテーブル内のデータが表示できる。

続きを読む "Scaffold" »

2008年05月23日

Scaffold のカスタマイズ

Scaffold には、用意されたデザインではなく、自由にデザインを変更できる機能がある。
これを使えば、もしかすると、本番システムにおいても利用できる機能なのかもしれない。

続きを読む "Scaffold のカスタマイズ" »

2008年05月26日

Model-Glue の初期設定

ここらで、基本的なところに戻って、ColdSpring.xml の先頭にある、
<bean id="modelGlueConfiguration" class="ModelGlue.unity.framework.ModelGlueConfiguration">
を見ていこう。

ここでは、Model-Glue の各種設定項目を、DIコンテナである ColdSprng で設定しているということになる。
設定できる項目は、以下の通り。

続きを読む "Model-Glue の初期設定" »

2008年05月27日

XMLの設定ファイルの豆知識

ところでいくつかあるXMLの設定ファイルで、どうするのかなぁと感じていたことがある。
特定のディレクトリを絶対パスで指定したい場合に、配置するサーバーの状態によっては、ディレクトリ名を変えないといけないこともあるだろう。そうしたときに、XML内の該当箇所を全て置き換えていかないといけないのかなぁ。とちょっと不便に思っていた。

ところが、ここのソースを見て解決した。
要は、ColdFusion レベルの手法ではなく、XMLレベルの手法で解決すればいいのだ。

続きを読む "XMLの設定ファイルの豆知識" »

2008年05月28日

TransferDecorator

Transfer の機能にある、decorator とはなんだろうか。
どこかで聞いたような気がしたんだけど、オブジェクト指向に出てくるデコレータパターンかな。
オブジェクトの振る舞いを自由に変更できるということか。

例のごとく、ドキュメントを読んでも、さっぱりわからない。
悪戦苦闘の結果に導き出した答えが、「Transfer のオブジェクトの振る舞いを変更するための仕組み」。
Transfer のオブジェクトは、Transfer.xml の object タグの情報を元に、自動で生成される。Transfer.xml で設定できること以外は、そのオブジェクトに対しては、ブラックボックス状態だ。
そこで、この transfer.com.TransferDecorator の出番となる。

続きを読む "TransferDecorator" »

2008年05月29日

Transfer の clone 機能

Transfer は、clone 関数が用意されている。文字通り、オブジェクトの複製ができる。
get で取得した Transfer のオブジェクトを clone するだけだ。

 user = getTransfer().get("user.User", 1);
 cloneUser = user.clone();

どんなときに使うのだろうか。

続きを読む "Transfer の clone 機能" »

2008年06月02日

Transfer Event Model

Transfer Event Model とは、なんだろうか。
データベースのテーブルをマッピングした Transfer オブジェクト経由でデータベース上のデータに対してなんらかの変更が加えられた(もしくは、変更が加えられる)ことを監視して、処理を発生させることができるということのようだ。

続きを読む "Transfer Event Model" »

2008年06月03日

Observer を Inject する

Google Groups に参考になるスレッドが上がってた。
addXXXObserver(component), where to call? is singleton required?
そこからのリンクMy Take on Transfer ORM Event Model - BeforeCreate Example
Observer の登録の仕方だ。これを参考にすると、すっきりした。

続きを読む "Observer を Inject する" »

2008年06月04日

ちょっと楽になるかな?ツール

もともと、無精なものだから、どうにも Transfer の Generated Methods の入力が煩わしい。
多少でも楽になればと思い、ちょっとツールを作ってみた。
これを使えば、
developing_04.gif
こういう風に、一覧で利用できる関数を表示してくれる。

続きを読む "ちょっと楽になるかな?ツール" »

2008年06月05日

ManyToMany

Transfer のリレーション設定の一つである manytomany って、なんとなく見過ごしてきたけど、実際のところ、これって何よ?というわけで、調べてみた。
多対多ということなんだろうけど、浅学なのか、こういうリレーションてのは、あまり考えたことがなかった。

例えば、ユーザーというデータがあって、そのユーザーが購入した商品は、複数ある。
逆に、ある商品を購入したユーザーは、複数人いるというのが、多対多ということらしいけど、どうやって設定するのやら。
以前、Transfer のサンプルの tBlog の Transfer.xml で manytomany を見かけたけことを思い出して、参考にしてみた。
インターネット上の情報から考えても、どうやら、リレーション用のテーブルを設けるらしい。

続きを読む "ManyToMany" »

2008年06月06日

ColdSpring の Remote Facades

ColdSpring のドキュメントに Remote Facades という項目がある。
これも確か、デザインパターンで見たような気がする。
便利なサイトがあったので、参考にさせてもらった。ありがたい。
なるほどなるほど。
実際の実装にはここを参考にさせてもらった。

で、とりあえず、http://localhost/shopping/model/ItemArrayBean.cfc?method=getItemArray にアクセス。

コンポーネント [[リポジトリ]]\shopping\www\model\ItemArrayBean.cfc のメソッド 'getItemArray' はリモートでアクセスできません。

cffunction の access 属性が public なのだから当然。

続きを読む "ColdSpring の Remote Facades" »

2008年06月09日

Transfer のドキュメント生成ツール

以前のエントリで、Generated Method を一覧してくれるツールをアップしたけど、やっぱり、公式なツールとしてすでに存在していたようだ。

こんな感じで関数を一覧してくれるので、紙のドキュメントにすることも可能だ。

続きを読む "Transfer のドキュメント生成ツール" »

2008年06月10日

ColdFusion とフレームワーク

さて、そろそろネタも尽きてきた。
ここらで、ColdFusion のフレームワーク利用について、考えてみる。

結果から言うと、使ってもいいし、使わなくてもいいというところだろうか。
やはり、フレームワークとなると、複数人で作業して、かつ、それぞれの技術能力にバラツキがある場合とかじゃないと、かえってマイナスの要因が目立ってしまう。
しかし、読んでみた率直な感想としては、自分一人で開発する場合でも、使ってみてもいいかなと感じる。

続きを読む "ColdFusion とフレームワーク" »

2008年06月11日

Railo で撃沈

CFMLが動く環境は、ColdFusion だけでなく、フォーラムにもあがっているように、Railo と、Open BlueDragon というものがある。
どうやら、両者とも、非商用は無料らしい。ということは、商用は有料となる。
Adobe 製 ColdFusion ではなく、Railo や、Open BlueDragon を選択する理由とは、なんだろうか。
Servlet を動かせるようだから、Java とのさらなる親和性かなぁ・・・。よくわからない。

さて、とにかく、Railo を動かしてみた。
結果的に、これまで作ってきた Model-Glue や ColdBox のアプリケーションは、見事、撃沈。
動いてくれなかった。フレームワーク上で発生している問題っぽい。
深くは調査しなかったので、何か方法があるのかもしれないけど、あっさりあきらめました。ごめんなさい。
残念な結果に終わってしまった。

2008年06月12日

ColdFusion を利用できるレンタルサーバー

数年前に調べたときは、国内のレンタルサーバーはあまりなかったけど、最近は、どうだろうか。
調べると言っても、Google で検索するしか方法を思いつかない。
条件としては、個人利用できる程度の値段設定ということかな。

やっぱり、国内で利用できるものということになると、ほとんど状況は変わっていない。
heteml (ヘテムル)
Futurism Works
(ランニングコストの安い順に並べました)
以前と一緒だ。値段も、一月あたり、1,500円とか、2,000円。
この2つは、以前調べたときもあった。これからも続けてほしいものだ。
ただ、両者とも、データベースが MySQL +αだけで、PostgreSQL が使えないのが、個人的には、かなり減点。しかも、MySQL のバージョンが、heteml の方が、4.0.25 だし、Futurism Works に至っては、バージョン4系としか書いてない。どうにもやる気を感じることができない。あくまで、個人的に。
「4.1 系と、5系を利用できる」とかだと、かなり印象は変わったはず。
開始当初からの状態で、変えられないという事情もあるんだろうけどね。
Futurism Works は、ColdFusion8 を準備中と書いてあるけど、どうなんだろうか。

他にも ColdFusion を利用できそうなレンタルサーバー屋があったけど、いささか、お値段が・・・。という感じ。

そんな中、とてもあやしい(個人的な印象だけ)けど、日本法人のあるお値打ちなレンタルサーバー屋がもう一つあった。

続きを読む "ColdFusion を利用できるレンタルサーバー" »

2008年06月13日

Active Directory 認証って言うのかな?これ

「ColdFusion でActive Directory」という話題があって、興味はあったので、調べてみたんだけど、結局のところ、ColdFusion では、Active Directory 認証はできないと思った方がいいような結果しか導けなかった。
そもそも、ColdFusion の LDAP 用のタグ <cfldap> には、認証というオプションがないので、「LDAP 情報を参照できるかどうか」ということしかわからない。これが LDAP では、当たり前のことなのかわからないけど、とにかく、参照、変更、削除という情報操作しかできないのだ。

続きを読む "Active Directory 認証って言うのかな?これ" »

2008年06月30日

ドキュメント全文検索機能 verity

ColdFusion には Verity という機能があって、今まで、試したことがなかったけど、ちょっと、やってみた。
要は、いろんなファイルを一括で検索できるようにしてしまおうというもの。
namazu みたいなものだと認識している。

続きを読む "ドキュメント全文検索機能 verity" »

2008年07月04日

cfgridcolumn での動的な色設定

ColdFusion のバージョン6のドキュメントには、

textColor 属性と bgColor 属性における式の使用方法

という項目があるけど、7以降のドキュメントには、見あたらない。

(CX operator string ? true_condition :false_condition)

と書けば、セルの値により色を動的に変更できたみたいだけど、バージョン8では、使えないと思った方がいいのかな。

続きを読む "cfgridcolumn での動的な色設定" »

2008年07月08日

やっぱり、cfgrid で色を動的に変えたい

妥協点を模索中。
.x-grid-cell-#lineNo#-0 { background-color: ##FFCCDD; }
.x-grid-cell-#lineNo#-1 { background-color: ##FFCCDD; }
.x-grid-cell-#lineNo#-2 { background-color: ##FFCCDD; }
こんな感じで、行の色を変えられるものの、折角の bind 機能と連携して色を変えることができない。

続きを読む "やっぱり、cfgrid で色を動的に変えたい" »

2008年07月10日

Subversive のインストール

Eclipse に Subversive を入れようと思ったら、なにやら、2箇所からインストールしないと行けないようだ。
ここにあるように、

http://download.eclipse.org/technology/subversive/0.7/update-site/ * Subversive plug-in update site
http://www.polarion.org/projects/subversive/download/eclipse/2.0/update-site/ * Subversive SVN Connectors update site

から、それぞれ、Subversive プラグインと、SVNクライアントプラグインをインストールするらしい。面倒だね。

2008年09月11日

Transfer でのエラー発生時の愚痴

Transfer を使っていると、何か問題があったときに、どこがいけないのか、本当にわかりにくい。
たいていの場合は、Transfer.xml の書き方が間違っている場合が多いのだけど、実際にどんなクエリを発行しようとしてエラーになったのか、どんなクエリを発行したのか。

続きを読む "Transfer でのエラー発生時の愚痴" »

2008年09月22日

Railo 浮上

以前のエントリーで、Railo に見事撃沈された我がサンプルアプリケーション。
その Railo が正式リリースされたと聞いたので、もう一度、動作確認してみた。

続きを読む "Railo 浮上" »

2008年09月24日

Railo のインストール

Railo には、3つのエディションがあって、ColdFusion とよく似ているので、推測しやすい。
Develop、Community、Enterprise 。で、無料で本番環境利用できるのが、Community である。

Develop はいいとして、Community と、Enterprise の違いは、具体的には、なんだろうか。


Community 版
restricted server administrator
no multimedia functionality
no admin synchronization
no cluster scope
no redistribution without the permission of Railo Technologies GmbH

Enterprise 版
Context synchronization
Cluster scope
Use of the tag CFVIDEO
CFTHREAD type task
Full server administrator

となっているが、よくわからないので、Community 版をインストールしてみた。

続きを読む "Railo のインストール" »

2008年09月25日

Railo + Resin + Apache on Windows

午前中に書いて保存してなかったようだ・・・。

さて、Apache と連携させてみよう。

Railo のフォルダ内に、setup.exe というツールがある。起動すると、こんな感じ。
railo-setupexe.gif

続きを読む "Railo + Resin + Apache on Windows" »

2008年09月26日

Railo + Tomcat on Linux

というわけで、今度は、Linux 上の Tomcat と連携させてみた。
Tomcat と Apache の連携はしていない。
Linux は、VMware にインストールしてあった CentOS 4.2 。
Tomcat は、5.5 系列の最新だった 5.5.27 。

Tomcat のインストールが終わったところから書こう。

続きを読む "Railo + Tomcat on Linux" »

2008年09月29日

Railo のメリットは?

まず、先日、Railo の Web サービスに関すること記述があやまっていたので、訂正しよう。
Railo で Web サービスを公開することは、ColdFusion と同じように可能である。
例えば、http://domain/echo.cfc?wsdl としてやることで、WSDL を公開出来る。
ここは、ColdFusion と同じだ。
要は、ColdFusion と違って、管理画面上で、Web サービスの登録が出来ない。
ws = CreateObject("webservice", "wsTemp");
こんな感じに、WSDL ファイルの URL を記述しなくてもいいような書き方が出来ないだけのようだ。

Railo の管理画面には、Remote というのがあって、この中に、wsdl という単語がある。
この設定は、なんなのだろうか。Remote Client とか書いてあるし、他のサーバーの URL を書く欄がある。
うーん・・・。

さて、本題。

続きを読む "Railo のメリットは?" »

2008年10月08日

Comet 雑感

ちょっと前というか、結構前に Comet というサーバープッシュ型の手法が話題になったけど、最近はどうなのだろうか。
Air だとか、RIA による手法に押されているのだろうか。
すっかり世の中の情勢に疎くなっているので、よくわからない。

ここはひとつ、物は試しということで、昔、目を通しただけで試していなかった Tomcat + Comet のチャットを動かしてみた。

続きを読む "Comet 雑感" »

2008年10月20日

MXUnit

今時は、MXUnit なのだろうか。
サイト見ると、「テストユニットを簡単に使えるようにしたいんだっ!」と書いてあるように読めたので、ちょっと試してみよう。

純正の Eclipse プラグインとか Snippet テンプレとかあるので、意気込みは本当かもしれない。

続きを読む "MXUnit" »

2008年10月29日

CFCDoc Revamped

この CFCDoc Revamped てのは、オリジナルのこのから、いくつか手直しを受けて、CPL で再公開されたものらしい。
確か、以前どこかで見かけて、「ふーん、おもしろそうだなぁ」と思ったきり、忘れていたものじゃないかと思う。
先日、この CFCDoc Revamped を見かけて、ちょっと試してみた。

続きを読む "CFCDoc Revamped" »

2008年11月05日

CF Frameworks Explorer ってなんぞ?

CFEclipse を導入する際に、ずっと気になっていたけど、

cfframeworks01.gif

こんな風だし、

cfframeworks02.gif

右クリックで、“構成”を選択すると、

cfframeworks03.gif

こんな警告出るし、

こんなウィンドウが表示されるだけで、なんなんだよ、これ。って感じで、放置していた CF Frameworks Explorer 。

でも、ここ の「08 CF Frameworks Explorer Introduction」を見て、一気に解決。

続きを読む "CF Frameworks Explorer ってなんぞ?" »

2008年11月10日

Transfer で発行されるクエリ

Transfer では、データベースクエリを発行する場所は、transfer.com.sql.QueryExecution の executeQuery() に集約されているので、どんなクエリが発行されているのかを把握することが簡単である。

実際に、80行目に以下のコードを入れてみた。

続きを読む "Transfer で発行されるクエリ" »

2009年01月26日

Grails ということで

ちと、Grails を使っていくことになりそうな感じになってきた。
そんなわけで、触ってみている。

うまく更新をリロードしてくれないときがあるんだよなぁ。

2009年03月05日

ColdFusion で自前 log4j ログをはき出す

cfscript でコードを書いていると、ログ出したいなぁという時があるけど、cflog タグは当然使えない。
まあ、ログじゃなくても、いろんな方法があるわけだけど、ささっと変数状態を見たいときがある。
というわけで、やってみた。

続きを読む "ColdFusion で自前 log4j ログをはき出す" »

2009年08月19日

groovyで簡単ファイルコピー

JAVAでファイルコピーをしようとすると、NewIO で簡単になったみたいだけど、ColdFusion にどっぷりつかっていた身としては、それにしたって、めんどくさい。
ましてや、Stream でゴリゴリなんて、もってのほか。
ところが Groovy だと、楽ちん簡単。

続きを読む "groovyで簡単ファイルコピー" »

2009年08月21日

今時のAppleScript

昔AppleScriptを触っていたときは、日本語でプログラムを書けた。
そんな時代から、月日は流れ、今は、MAC OSXの時代。
今時のAppleScriptは、いろんな処理をShellにやらせるのだそうだ。

続きを読む "今時のAppleScript" »

2009年08月25日

プラグインのviewを参照するときの面倒な話

Grail でプラグインを利用する際に、application.propertiesに書く方法と、開発中などで、ローカルにあるプラグインディレクトリを参照するように、BuildConfig.groovyに書く方法の二通りある。
application.properties の場合は、


plugins.data-import=0.8

としてやる。BuildConfig.groovy の場合は、

grails.plugin.location."dataimport"="../DataImport"

などとしてやる。

続きを読む "プラグインのviewを参照するときの面倒な話" »

2009年08月26日

Grailsのトランザクション

Grailsを扱っていると、データベースのトランザクション処理は、目に見えないところに隠蔽されている。
これって、本当にロールバックされるの?と疑問に思ったりする。
BackgroundThread プラグインを扱って、さらに、その疑問がひっかかったので、ちょっと、調べてみた。
Grailsでは、Service で、


boolean transactional = true

としてやると、データベースへの更新が一つでも失敗すると、そのトランザクションは、ロールバックするとされている。

このデータベースの更新の失敗というのは、どんなものか。

続きを読む "Grailsのトランザクション" »

2009年09月02日

Mac で WebDAV + mod_proxy = Chunked 問題

今時というか、かなり前から、Mac や、Windows には、WebDAVクライアント機能がついていて、何も考えずに WebDAV を利用できる。
だいぶ、利用実績もあるはずだと思うんだけど、未だに、サーバー設定に関しては、「やってみた」的な情報しか、Google 先生は、教えてくれない。まあ、探し方が悪いのかもしれないが。
Mac で WebDAV の環境を構築していて、つまずいてしまったので、その記録。

続きを読む "Mac で WebDAV + mod_proxy = Chunked 問題" »

2009年09月21日

なんとなくわかってきた

以前のエントリでトランザクションのことを書いたけど、さらに、わかってきたので、再びエントリ。
でも多分に推測。

まず、Grails は、基本的に、AutoCommit モードで動作している。
でも、ちゃんと、ロールバックの動きはしてくれる。
どういう仕組みなのだろうか。

続きを読む "なんとなくわかってきた" »

2009年09月25日

Let's Griffon

Grails をやっているとたまに上る話題の中に、Griffon というものがある。
Grails の考え方をGUIアプリケーション(Swing)に応用したものだ。
バージョン的には、まだ 0.1.2 というとても低いものだけど、訳あって、チャレンジしてみた。
結局のところ、Swing なわけで、Grails で WEB アプリを簡単に作るようにはいかない。
とりあえず、サンプルアプリを起動するまでのまとめ。

続きを読む "Let's Griffon" »

About プログラム

ブログ「気楽に行こう」のカテゴリ「プログラム」に投稿されたすべてのエントリーのアーカイブのページです。過去のものから新しいものへ順番に並んでいます。

前のカテゴリはサーバー管理です。

次のカテゴリは雑記です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。