アセットのデータ取得方法によるパフォーマンス測定(その2)

前回:アセットのデータ取得方法によるパフォーマンス測定(その1)

前回に引き続き、今回も、アセット(フレックスファミリーアセット)のデータを取得するのに、より速い取得の方法はないか調べてみたいと思います。

今回は、Asset APIがどのくらい速いのか、Asset APIと、assetset:getmultiplevaluesタグで測ってみます。

前回と同様、アセット10コ、50コ、100コで計測してみましょう。
データの取得は、アセットがもつ属性から適当に20コ(すべて単一)を選んでみます。

では、テスト用のテンプレートをそれぞれ作ります。

1)Asset API

List listAttrNames = new ArrayList();
//20コ取得
listAttrNames.add("testA");
listAttrNames.add("testB");
listAttrNames.add("testC");
listAttrNames.add("testD");
listAttrNames.add("testE");
listAttrNames.add("testF");
listAttrNames.add("testG");
listAttrNames.add("testH");
listAttrNames.add("testI");
listAttrNames.add("testJ");
listAttrNames.add("testK");
listAttrNames.add("testL");
listAttrNames.add("testM");
listAttrNames.add("testN");
listAttrNames.add("testO");
listAttrNames.add("testP");
listAttrNames.add("testQ");
listAttrNames.add("testR");
listAttrNames.add("testS");

Session ses = SessionFactory.getSession();
AssetDataManager mgr = (AssetDataManager) ses.getManager(AssetDataManager.class.getName());

%><ics:if condition='<%=ics.GetList("listTests")!=null && ics.GetList("listTests").hasData()%>'><ics:then><%
 %><ics:listloop listname="listTests"><%
 %><ics:listget listname="listTests" fieldname="id" output="o_AssetId"/><%

String baseAssetId = ics.GetVar("o_AssetId");
 AssetId id = new AssetIdImpl( "TestAsset_C", Long.parseLong(baseAssetId));
 Iterable<AssetData> dataItr = mgr.read( Collections.singletonList( id ) );

for( AssetData data : dataItr )
 {
 for(int y=0; y<listAttrNames.size(); y++) {
 AttributeData atrData = data.getAttributeData((String)listAttrNames.get(y));

}
 }

%></ics:listloop><%
%></ics:then></ics:if><%

2)assetset:getmultiplevaluesタグ
前回と同様ですので省略します。前回はこちら

測定開始です。

・・・測定・・・測定・・・測定・・・。

出ました。結果です。

アセット数

取得属性数

AssetAPI

assetset:getmultiplevaluesタグ

10

20

735ms

84ms

50

20

5437ms

353ms

100

20

9085ms

869ms

※動作環境や定義がもつ属性の数によって変動はあります。正確な数値ではありません。
※同じアセットタイプ、同じ定義で、すべて異なるアセットを使っています。
※フレックスアセットの参照はassetset:setassetタグを使っています。
※3回実行し、その平均値になります。

結果に驚きました。桁が違いますね。assetset:getmultiplevaluesタグが速いというより、Asset APIが遅いです。よくわかったことは、アセットデータを取得するのにAsset APIを使っては危険ということです。管理サイトのカスタマイズなど、管理側の機能に限定して使ったほうが良いかもしれません。

ということで、季節は春です。暖かくなってきました。春に向けての準備など、やりたいことがいろいろありますね。会社では新入社員が入ってくるので新人教育の準備、外では桜の花が咲き始めているので花見の準備、家では車の冬用タイヤをノーマルタイヤへの交換、あ、それは私だけですね。
花見ですが、東京では3月末に開花しているので、今週は絶好の美味しいお酒を味わえそうですね。

sakura_L


入力欄をカスタマイズする!属性エディタ

ゆるゆるアニマルコラム担当のエンジニアKです。今回は「属性エディタ」についてです。新米PGのリス田くんはあれから成長したのでしょうか。それとも…?

◆登場人物紹介◆
mega02
メガネ先輩
ベテランSE。数々のWCS案件を経験してきたツワモノ。

risu02
リス田
新米プログラマー。WCSについて学び始めたばかり。
risu08 げへへー
mega02
risu08 うふふー
mega06 ???
mega06 …おい、リス田。何よだれ垂らしながらニヤニヤしてんだ。気持ち悪いぞ…。
てか、課題はちゃんと進んでいるのか?
risu02 ハッ!先輩っ!?課題ですか?
い、今まさに進めていたところですよー!
見て下さい、僕の…、WebCenter Sites牛丼屋メニューサイトを!!

2117_02_img01

mega02 …ほう。メニュー一品一品をアセット化したのか。
管理画面側はどんな感じ?
risu06 こんな感じです!

2117_02_img02

mega06 こ、これは…。
リス田、お前…、この入力画面、何か感じないのか??
risu07 何か…?
あっ!!サイドメニューも必要ですね!僕、健康志向なんでサラダとか付けちゃいますよー!
mega07 ばかもん!!貴様自身の健康活動なんぞどうでもいい!!
入力画面の入力欄を見てみろ!全部一行テキストボックスだろうが!
これじゃ使い勝手良くないわ!
risu04 ヒ、ヒィッ!!す、すいません!
って、入力欄をテキストボックス以外にする方法ってあるんですか?
mega04 お前、開発者ガイドちゃんと読んでないだろう…。
risu04 ウッ!
mega02 開発者ガイド「属性エディタの設計」に、入力欄の形を変える方法がちゃーんと載っているんだ。
属性エディタを使えば、ラジオボタンやチェックボックス、テキストエリア等々、入力欄を別の形に変える事が出来るぞ。
例えば「肉の種類」は牛肉・豚肉・鶏肉しか入力させたくない場合は、選択肢がその3つのラジオボタン項目を作ってしまえばいい。
属性エディタは以下の様なXMLを使って定義するんだ。

<?XML VERSION="1.0"?>
<!DOCTYPE PRESENTATIONOBJECT SYSTEM "presentationobject.dtd">
<PRESENTATIONOBJECT NAME="Radio_MeatType">
<RADIOBUTTONS LAYOUT="VERTICAL">
<QUERYASSETNAME>Query_MeatType</QUERYASSETNAME>
</RADIOBUTTONS>
</PRESENTATIONOBJECT>

mega01 XMLの内容を簡単に説明すると、Query_MeatTypeという問い合わせアセットの結果を用いて、ラジオボタン項目を縦方向(VERTICAL)に並べる、という事だな。
もちろん、問い合わせアセットは、「牛肉」「豚肉」「鶏肉」の3件が結果として返ってくるようにする。
risu02 おぉー。
mega02 「トッピング」なんかも、トッピングできる食材でチェックボックスとかにしてしまえばいい。
何でもかんでもトッピングできる訳じゃないだろう?
チェックボックスの場合の属性エディタはこんな感じかな。ラジオボタンの場合とよく似ているね。

<?XML VERSION="1.0"?>
<!DOCTYPE PRESENTATIONOBJECT SYSTEM "presentationobject.dtd">
<PRESENTATIONOBJECT NAME="CheckBox_Topping">
  <CHECKBOXES LAYOUT="VERTICAL">
    <QUERYASSETNAME>Query_Topping</QUERYASSETNAME>
  </CHECKBOXES>
</PRESENTATIONOBJECT>

risu01 なるほど…。
mega02 実際の案件だと、お客様の要望を聞いて、その要望に合った形・選択肢の入力項目を作成するんだ。
とりあえず、今の入力画面にいろんな属性エディタを適用させて、使い勝手の良い入力画面にしてみろ。
…あ、そうそう、出来るまでは昼飯に行っちゃだめだぞー。
risu04 な、なんですと!!そりゃ全力でやらねば!!

◇◇数時間後◇◇

risu09 先輩、出来ました…。
は、早く飯…昼飯を…。
mega01 ん?ああ遅かったなぁ。ちょっとまって。今チェックするから。
risu09 空腹時に食べ物関係の作業するのって辛いですね…。

2117_02_img03

mega01 ふむ。いい感じだね。
ラジオボタン、チェックボックスや、プルダウンも盛り込まれているな。よしよし。
アセットの設計をするときは、使う時の利便性までちゃんと考えた上で設計するのがポイントね。
risu06 はい!先輩わかりました!はい!先輩昼飯を食いに行きましょう!!
僕の頭の中はもう牛丼でいっぱいです!!牛丼食べに行きましょう!牛丼!!
mega05 えー。俺魚が食べたい気分なんだにゃ。
risu04 ガーン!!

以上、「入力欄をカスタマイズする!属性エディタ」でした!
次回をお楽しみに!


Content-Typeを動的に指定することは可能なのか

今回は、前回のマネージャーKのコラム(ページは見つかったのか。見つかっていないのか。)でちょっとだけ話に挙がった「Content-Type」についてお話します。

Webcenter Sites(以下WCS)では、Content-Typeをテンプレート作成時に指定することができます。

Content-Typeはテンプレートの設定項目の1つである、ページレットパラメータで”cs.contenttype”をキーに指定します。

ページレット

しかし、このページレットパラメータで指定したcs.contenttypeの値は、そのテンプレートで常に固定となるため、動的にContent-Typeの変更ができません。
サーブレットプログラムでは、下記コードのようにContent-Typeを動的に変更できます。

response.setContentType("text/html");

WCSのテンプレートでこのコードを書いてもエラーは発生しませんが、有効にもならないのです。

それでは、動的にContent-Typeを変更したい要件が出たときにはどうするべきでしょうか。

実際に携わった案件では、使われる可能性のあるContent-Typeのテンプレートを全て用意し、アクセスに応じて適切なContent-Typeのテンプレートを呼び出す方法を取りました。

例えば、gifへのアクセスであれば、cs.contenttypeが”image/gif”のテンプレートを呼出し、pdfへのアクセスであれば、”application/pdf”のテンプレートを呼び出すといった感じです。

呼出し方は色々な方法がありますが、Apacheのrewriteを使うのも一つの方法です。

Rewriteを使ったテンプレート呼出しイメージ

rewrite_image

もう一つ、こちらはまだ検証前ではありますが、テンプレートを”XML”タイプで開発することでContent-Typeを動的に変更できる可能性があります。

XMLにはHTTPのヘッダーを設定するタグ(ICS.STREAMHEADER)が用意されていて、このタグを使うことによってContent-Typeの指定が可能だということです。

実際にこのタグが有効かどうかは次の機会に検証したいと思います。

今のところ、JSPでの開発ではContent-Typeを完全な動的化にする方法が見つかっていませんが、上記に挙げた方法が参考になれば幸いです。


ページは見つかったのか。見つかっていないのか。

Webサービスを利用する際に頻繁に目にすることがある、”404 Not Found”という画面があります。

実際にはエラー表示専用の画面をデザインすることが多いため、メッセージの見栄えはサイトによって異なることが多いです。例えば、弊社コーポレートサイトのエラー画面は、以下のようになっています。

ZYYX 404

このページ内容は、Webサイトのコンテンツにアクセスした際に、URLで指定されたコンテンツが物理的に存在しない場合にWebサーバーが返すものです。コンテンツが存在し、正常にレスポンスされる場合には、”200 OK”が返されます。

このエラーが発生した際、Webサーバーのアクセスログには、HTTPステータス404が発生した旨のログが記録され、エラーページのHTMLにGoogle Analytics等のWebビーコン型のタグを入れておけば、そちら側のログにもHTTPステータス404が記録されます。

さて、HTTPステータスに関しての前置きが長くなってしまいましたが、ここから本題です。

WebCenter Sites(以下、WCS)で動的配信を行う場合、表示されるページは、URLアクセス時に指定されたパラメーターや日付等の検索条件によって変化します。

例えば、コーポレートサイトにニュースを掲載する場合を考えてみましょう。データの運用は、標準的には以下のようになると思います。

  1.  掲載したいニュースの原稿や画像素材を準備する。
  2. ニュースの原稿や素材をWCSのアセットに登録し、公開開始日時を指定する。
  3. WCSの未来日プレビュー機能を使用し、指定した日時にニュースが公開されることを確認する。
  4. ニュースのアセットを配信環境へパブリッシュし、公開開始日時を待つ。

その後、パブリッシュしたニュースの公開開始日時を過ぎると、ビジター画面にニュースが表示され、Google等の検索エンジンのクローラーのアクセスがあり、インターネット上の検索サイトで公開したニュースが検索できるようになります。

さて、ニュース公開後、例えばニュースの公開開始日時を間違って早めに設定してしまった場合のことを考えてみます。公開してしまったニュースを取り下げるには、以下のような方法があると思います。

  •  公開開始日時を修正したアセットをパブリッシュしなおす。
  • ニュースのアセットに非表示にするためのフラグがあれば、それを設定してパブリッシュしなおす。
  • ニュースのアセット自体を削除する。

上記いずれの対象方法を行っても、配信環境では「表示対象のニュースが存在しない」とテンプレートのロジックで判断され、該当のニュースは表示されなくなります。

ここに落とし穴があります。

テンプレートの判断でアセットの有無を判断して出力する結果は、サーバー側の処理としては正常なものですので、見た目上「このページは存在しません」と表示したところで、HTTPのレスポンスとしては”200 OK”が戻ってしまうのです。(この動きを、「ソフト404」と呼びます)

ソフト404は、Webサイトを見ているのが人間だけならば問題はないのですが、実際には、以下の弊害を伴っています。

  • 一度検索エンジンのクローラーによって該当ニュースのページがインデックスされた場合、ソフト404で取り下げを行っても存在しないページの内容や、場合によっては、エラーメッセージを表示したページの内容が検索エンジンのインデックスに残ってしまい、検索の対象となってしまいます。検索にはヒットするのに、実際にリンクをクリックすると内容が無い、ということで、サイトにアクセスしてきたビジターの不信感につながってしまいます。
  • ソフト404を発生させた場合、アクセスログ(Webサーバーのログ、Google Analytics等のWebビーコン型のログのどちらにも)に存在しないページヘのアクセスが”200 OK”として記録されてしまうため、ログをベースにしたコンテンツ改善(リンク切れの解消や、ページアクセス解析)がやりにくくります。

表示させるページが存在しない場合に、ソフト404ではなく、「本当の404 Not Found」を発生させるにはどうすればいいのか。ここで、WCSの仕様が壁となって立ちはだかります。

なんと、WCSでは、標準でHTTPステータスの変更方法がないのです。

WCSのテンプレートはJSPベースですが、setStatus等でHTTPステータスを任意に変更することができません。(同じように、動的にContent-Typeの変更もできないのですが、それは別の機会に)

とはいえ、「いやー、WCSの仕様なので仕方ないんですよねー」で通じるような世の中でもありませんので、弊社はどう解決しているかというと、レスポンスを書き換える「サーブレット・フィルタ」を追加開発して、対処を行っています。

サーブレット・フィルタは、サーブレットを呼び出す前後でリクエストとレスポンスの値に対して処理を行うことができるプログラムです。実際の処理の詳細は本稿では割愛させていただきますが、簡単にいうと、テンプレート側でソフト404のレスポンスを返す際に、サーブレット・フィルタ側でHTTPステータスを”200 OK”から、”404 Not Found”に変更してブラウザやクローラーへ返すようにしています。これで、ソフト404にまつわる弊害も、完全に解決です。

蛇足になるかもしれませんが、このソフト404問題、設計・開発時に意外と見落とされがちでもあるので、本稿が何らかのヒントになることを期待しております。


アセットのデータ取得方法によるパフォーマンス測定(その1)

今、世界はクリスマスムードにつつまれています。クリスマスツリー、クリスマスケーキ、クリスマスプレゼント、クリスマスソング、クリスマスパーティ、クリスマスイベント、クリスマスセールなどなどクリスマスがつくものが楽しさあふれでていますね。

そこで今回は、アセット(フレックスファミリーアセット)のデータを取得するのに、より速い取得の方法はないか調べて、皆様にお届けしたいと思います。christomas_1

たくさんのアセットを参照しているページは、キャッシュがきれている状態でページへアクセスすると、少し重く感じられますよね。少しでも早くページが表示されるように、パフォーマンスを考慮した実装が必須になります。今回は、フレックスアセットのデータの取り方に絞って探ってみようと思います。

今回は、WCSで用意されているタグを使って調べてみます。

データの取得にはassetset:getattributevaluesタグと、assetset:getmultiplevaluesタグが用意されています。この2つのタグの処理時間に違いはあるのでしょうか。2つのタグを使って処理時間を計測し、どちらのタグが速い処理を行っているか測ってみます。

アセット1コのデータを取得しただけでは、わからないので、アセット10コ、50コ、100コで計測してみましょう。

データの取得は、アセットがもつ属性から適当に5つ(string型4つ、asset型1つ)を選んでみます。

では、テスト用のテンプレートをそれぞれ作ります。

1)assetset:getattributevaluesタグ


%><assetset:setasset name="asFlexData" type="TestAsset_C" id='<%= ics.GetVar("aidAssetId") %>' /><%

%><assetset:getattributevalues name="asFlexData" attribute="testA" listvarname="listFlexData" typename="TestAsset_A" /><%
%><ics:if condition='<%= ics.GetList("listFlexData")!=null && ics.GetList("listFlexData").hasData() %>'><ics:then><%
  %><ics:listget listname="listFlexData" fieldname="value" output="o_testA" /><%
%></ics:then></ics:if><%
%><assetset:getattributevalues name="asFlexData" attribute="testB" listvarname="listFlexData" typename="TestAsset_A" /><%
%><ics:if condition='<%= ics.GetList("listFlexData")!=null && ics.GetList("listFlexData").hasData() %>'><ics:then><%
  %><ics:listget listname="listFlexData" fieldname="value" output="o_testB" /><%
%></ics:then></ics:if><%
%><assetset:getattributevalues name="asFlexData" attribute="testC" listvarname="listFlexData" typename="TestAsset_A" /><%
%><ics:if condition='<%= ics.GetList("listFlexData")!=null && ics.GetList("listFlexData").hasData() %>'><ics:then><%
  %><ics:listget listname="listFlexData" fieldname="value" output="o_testC" /><%
%></ics:then></ics:if><%
%><assetset:getattributevalues name="asFlexData" attribute="testD" listvarname="listFlexData" typename="TestAsset_A" /><%
%><ics:if condition='<%= ics.GetList("listFlexData")!=null && ics.GetList("listFlexData").hasData() %>'><ics:then><%
  %><ics:listget listname="listFlexData" fieldname="value" output="o_testD" /><%
%></ics:then></ics:if><%
%><assetset:getattributevalues name="asFlexData" attribute="testE" listvarname="listFlexData" typename="TestAsset_A" /><%
%><ics:if condition='<%= ics.GetList("listFlexData")!=null && ics.GetList("listFlexData").hasData() %>'><ics:then><%
  %><ics:listget listname="listFlexData" fieldname="value" output="o_testE" /><%
%></ics:then></ics:if><%

2)assetset:getmultiplevaluesタグ

%><assetset:setasset name="asFlexData" type="TestAsset_C" id='<%= ics.GetVar("aidAssetId") %>' /><%

%><assetset:getmultiplevalues name="asFlexData" byasset="false" immediateonly="true" prefix="atlst"><%
  %><assetset:sortlistentry attributetypename="TestAsset_A" attributename="testA"/><%
  %><assetset:sortlistentry attributetypename="TestAsset_A" attributename="testB"/><%
  %><assetset:sortlistentry attributetypename="TestAsset_A" attributename="testC"/><%
  %><assetset:sortlistentry attributetypename="TestAsset_A" attributename="testD"/><%
  %><assetset:sortlistentry attributetypename="TestAsset_A" attributename="testE"/><%
%></assetset:getmultiplevalues><%

%><ics:if condition='<%= ics.GetList("atlst:testA")!=null && ics.GetList("atlst:testA").hasData() %>'><ics:then><%
  %><ics:listget listname="atlst:testA" fieldname="value" output="o_testA" /><%
%></ics:then></ics:if><%
%><ics:if condition='<%= ics.GetList("atlst:testB")!=null && ics.GetList("atlst:testB").hasData() %>'><ics:then><%
  %><ics:listget listname="atlst:testB" fieldname="value" output="o_testB" /><%
%></ics:then></ics:if><%
%><ics:if condition='<%= ics.GetList("atlst:testC")!=null && ics.GetList("atlst:testC").hasData() %>'><ics:then><%
  %><ics:listget listname="atlst:testC" fieldname="value" output="o_testC" /><%
%></ics:then></ics:if><%
%><ics:if condition='<%= ics.GetList("atlst:testD")!=null && ics.GetList("atlst:testD").hasData() %>'><ics:then><%
  %><ics:listget listname="atlst:testD" fieldname="value" output="o_testD" /><%
%></ics:then></ics:if><%
%><ics:if condition='<%= ics.GetList("atlst:testE")!=null && ics.GetList("atlst:testE").hasData() %>'><ics:then><%
  %><ics:listget listname="atlst:testE" fieldname="value" output="o_testE" /><%
%></ics:then></ics:if><%

※アセットを格納したリスト作成、ループ処理のコードは省略しています。

測定開始です。

・・・測定・・・測定・・・測定・・・。

出ました。結果です。

アセット数

属性数

タグ

assetset:getattributevalues

assetset:getmultiplevalues

10

5

50.8ms

43.4ms

50

5

438.2ms

256ms

100

5

922.2ms

514.4ms

※動作環境や定義がもつ属性の数によって変動はあります。正確な数値ではありません。

※同じアセットタイプ、同じ定義で、すべて異なるアセットを使っています。

※フレックスアセットの参照はassetset:setassetタグを使っています。

結果を見てみましょう。assetset:getmultiplevaluesタグが速いですね。

assetset:getattributevaluesタグは、アセット数と処理時間を見ると、単純に倍の時間がかかるというわけではなさそうですね。アセット数が多ければ多いほど、時間がかかります。アセットや条件を変更して測っても同じような結果がでました。ということで、アセットタグは、assetset:getmultiplevaluesを使うで決まりですね!メリークリスマスです!

ただ、assetset:getmultiplevaluesタグのデメリットはtext型の属性は取得できないという点です。これは仕様です。ですので、text型の属性は、assetset:getattributevaluesタグを使って取得するしかないですね。うまく使い分けをすれば、十分なパフォーマンスを得ることができると思います。

では、assetAPIを使うとどうでしょうか。タグより速いのでしょうか。

次回(3月頃を予定)はassetAPIを使って測定してみようと思います。christomas_2


無駄な改行を省こう

今回はWCS開発初級編としまして、TemplateやCSElementを使用して出力されるHTMLの無駄な改行を省くノウハウを、会話形式でゆる目にお届けしたいと思います。
突然コラムの雰囲気が変わってしまいますが…、戸惑わないで頂けると幸いです。

◆登場人物紹介◆
mega02
メガネ先輩
ベテランSE。数々のWCS案件を経験してきたツワモノ。

risu02
リス田
新米プログラマー。WCSについて学び始めてまだ3日目。
risu06 先輩!アセットの属性値を取得して、表示を行うTemplateが出来ました!

mega02 どれどれ…。うん、いい感じだね。
Templateのコードも見せてもらえるかな?
risu01 はい!

<assetset:setasset name="asFlexData" type="Music_P" id='<%=ics.GetVar("assetID")%>' />
<assetset:getattributevalues name="asFlexData" attribute="artistname" listvarname="listFlexData" typename="Music_A" />
<ics:listget listname="listFlexData" fieldname="value" output="icsArtistname" />
<assetset:getattributevalues name="asFlexData" attribute="mediatitle" listvarname="listFlexData" typename="Music_A" />
<ics:listget listname="listFlexData" fieldname="value" output="icsTitle" />
<assetset:getattributevalues name="asFlexData" attribute="releasedate" listvarname="listFlexData" typename="Music_A" />
<ics:listget listname="listFlexData" fieldname="value" output="icsReleasedate" />

アーティスト名:<%=ics.GetVar("icsArtistname")%><br />
タイトル:<%=ics.GetVar("icsTitle")%><br />
発売日:<%=ics.GetVar("icsReleasedate")%><br />

mega02 ふむ。ちゃんとassetset:getattributevaluesタグも使いこなせてるね。
risu03 楽勝っすよ!もっとレベルの高い課題を出してくださいよー。
mega01 ほう…。
じゃあ次の課題を出す前に、ちょっと表示されたページのソースを見てみようか。
risu02 ソース?Templateじゃなくて?あ、Webページの方ですか?
mega01 うん、右クリックで「ソースの表示」を選んで…

risu04 えっ…!?うわぁぁぁぁ!改行だらけえぇぇ!!な、なんで?
mega03 ひゃっひゃっひゃっひゃっひゃ!
risu04 って、なんでこんなに改行だらけになっちゃうんですか?てかその笑い方ムカつきます!
mega01 いやぁ、WCS開発を始めたばかりの人がはまりがちなポイントに、
見事にはまってくれたからね。
risu05 ガーン。はめられた…んですか僕。
mega01 という訳で、何でこんなに改行だらけのコードになったかだが、さっきのTemplateのコードをもう一度よく見てごらん。

<assetset:setasset name="asFlexData" type="Music_P" id='<%=ics.GetVar("assetID")%>' />
<assetset:getattributevalues name="asFlexData" attribute="artistname" listvarname="listFlexData" typename="Music_A" />
<ics:listget listname="listFlexData" fieldname="value" output="icsArtistname" />
<assetset:getattributevalues name="asFlexData" attribute="mediatitle" listvarname="listFlexData" typename="Music_A" />
<ics:listget listname="listFlexData" fieldname="value" output="icsTitle" />
<assetset:getattributevalues name="asFlexData" attribute="releasedate" listvarname="listFlexData" typename="Music_A" />
<ics:listget listname="listFlexData" fieldname="value" output="icsReleasedate" />

アーティスト名:<%=ics.GetVar("icsArtistname")%><br />
タイトル:<%=ics.GetVar("icsTitle")%><br />
発売日:<%=ics.GetVar("icsReleasedate")%><br />

risu05 えーと……。
……。
risu07 あ…、も、もしかして「assetset…」タグ部分の改行も、改行として見なされた?
mega01 そう!その通り。
このコードだと■印をつけたところの改行が、そのままソース中の改行と見なされたんだね。

<assetset:setasset name="asFlexData" type="Music_P" id='<%=ics.GetVar("assetID")%>' />■
<assetset:getattributevalues name="asFlexData" attribute="artistname" listvarname="listFlexData" typename="Music_A" />■
<ics:listget listname="listFlexData" fieldname="value" output="icsArtistname" />■
<assetset:getattributevalues name="asFlexData" attribute="mediatitle" listvarname="listFlexData" typename="Music_A" />■
<ics:listget listname="listFlexData" fieldname="value" output="icsTitle" />■
<assetset:getattributevalues name="asFlexData" attribute="releasedate" listvarname="listFlexData" typename="Music_A" />■
<ics:listget listname="listFlexData" fieldname="value" output="icsReleasedate" />■
■
アーティスト名:<%=ics.GetVar("icsArtistname")%><br />
タイトル:<%=ics.GetVar("icsTitle")%><br />
発売日:<%=ics.GetVar("icsReleasedate")%><br />

risu05 oh…。
risu07 え、でもこうやってタグを記述する以上、改行が出来てしまいますよね…?
これからどんどん複雑なタグやループ処理を書く事になると、もっともっと改行が…。
ど、どうすれば…。
mega01 そこはちゃんと改行が入らない様な書き方があるんだよ。
ノウハウ…って程でも無いけど、まぁ、ちょっとしたTipsみたいなもんかな?
risu01 ほうほう。で、どんな書き方なんですか?
mega01 んーと(カタカタカタ…)、こんな感じだね。

<assetset:setasset name="asFlexData" type="Music_P" id='<%=ics.GetVar("assetID")%>' /><%
%><assetset:getattributevalues name="asFlexData" attribute="artistname" listvarname="listFlexData" typename="Music_A" /><%
%><ics:listget listname="listFlexData" fieldname="value" output="icsArtistname" /><%
%><assetset:getattributevalues name="asFlexData" attribute="mediatitle" listvarname="listFlexData" typename="Music_A" /><%
%><ics:listget listname="listFlexData" fieldname="value" output="icsTitle" /><%
%><assetset:getattributevalues name="asFlexData" attribute="releasedate" listvarname="listFlexData" typename="Music_A" /><%
%><ics:listget listname="listFlexData" fieldname="value" output="icsReleasedate" /><%

%>アーティスト名:<%=ics.GetVar("icsArtistname")%><br />
タイトル:<%=ics.GetVar("icsTitle")%><br />
発売日:<%=ics.GetVar("icsReleasedate")%><br />

risu07 ???な、なんか「%」がいっぱい…。
mega01 そうだね、ソースコードの可読性は少し落ちちゃうね。
まぁ、そのうち慣れると思うよ。
で、この書き方だけど行の末尾に「<%」、あと行の先頭に「%>」を追加したんだ。
こうすると、<% ~ %>間がJSPブロックとしてみなされるから、その間の改行はHTMLソース上には出力されないんだ。
risu01 へぇ…!こういう書き方があるんですね。
mega01 ブラウザ上での見た目は勿論大事だけれど、HTMLソースの見た目も美しくね。
risu01 はい!
早速さっきのTemplateを修正して、無駄な改行のないHTMLが出力されるようにしますね!!

risu05 (10分後)…あ、あの。
mega02 ん?出来たかな?
risu05 ええと、それが…。ちゃんと<% ~ %>でくくったんですけど、どうしても1ヵ所無駄な改行が残っちゃいまして…。
HTMLの一番先頭なんです。

mega03 ひゃっひゃっひゃっひゃっひゃ!!
risu04 ってまたそんな笑い方する!ガーン!!
mega03 いや、君がまたはまりがちなポイントにはまってくれたからねぇ。
risu05 また、ですか…。(ガクッ)
mega01 HTMLの先頭に改行が入っちゃう場合は、jspコードの一番末尾を見てごらん。
「</cs:ftcs>」の後に改行が入ってないかい?
risu04 ああっ!
mega01 やっぱり。

mega01 ここに改行が入っていると、HTMLの一番頭にその改行が表示されちゃうんだよ。
注意してね。
risu05 はい…。
◇ ◇ ◇
risu05 WCSって、Templateの書き方だけでも沢山ノウハウがあるんですねぇ。
全部覚えられるかなぁ…。
mega02 そこは案件をこなしていく内に自然と蓄積されていくよー(遠い目)。
risu02 ふーん。そんなもんですかねぇ。
mega01 ところで、HTMLコード内に無駄な改行が入らないようなソースの書き方については、ちゃんとDeveloper’s Guideに書いてあるんだな~。
risu01 えっ!そ、そうなんですか?
mega01 Developer’s Guide、全部目を通した??
risu05 い、いや、さすがにまだ全部は…。
mega01 ほら、この最後の方の、「Appendix C」のとこ。
risu05 え、英語…。(ビクビクビク)
mega01 Developer’s Guideは一通り読んどいた方がいいよ。
基本的な事が一通り書いてあるからね!
ちなみに…日本語版もある。
risu06 ガタッ!!ほ、ほんとですか…!!!
mega04 お前…。
WCSの勉強もいいけど、英語の勉強もやろうな。
risu05 …はい。

以上、WCS開発初級編、「無駄な改行を省こう」でした!
次回(は果たしてあるのか?)をお楽しみに!


WebCenter Sitesを使った開発ではキャッシュも考えましょう

 通常、動的なページを出力するシステムでは、データベースから必要な情報を取得し、様々な処理を行った上でページを出力します。しかし、取得する情報が多くなったり、複雑な処理になるほど、ページの出力は遅くなっていきます。

WebCenter Sites(WCS)にはページ出力をアップさせるための仕組みを持っています。

それが「キャッシュ」です。

WCSのキャッシュは以下の特徴があります。

  • 一度生成したページ(またはページの一部)をメモリに保持しておき、表示条件が同じ場合には処理を行わずにメモリから結果をブラウザに戻す。
  • ページ単位やページをパーツに分けて、それぞれにキャッシュの有効/無効を設定したり、キャッシュとして残す時間を設定することが可能。
  • そのページと関連があるアセット(データ)を公開した際に、キャッシュを再作成することが可能。

 ただし、WCSのキャッシュは強力な反面、適切な設定を行わないと様々なトラブルの元になります。
例えば

  • キャッシュの時間が長すぎて、新着情報がなかなか表示されない。
  • キャッシュ生成の条件にミスがあり、うまくキャッシュが効かない。
  • 情報更新時に、大量のキャッシュを更新するような作りになっているため、情報更新に非常に時間がかかり、システムの負荷が高くなる。

 実際のところ、機能開発を行う際は、ついついキャッシュ管理を含めた運用への考慮を忘れがちになりますが、これが意外と開発の手戻りとなったりするものなのです。

 WCSでキャッシュを扱うには、システムや開発に対する知識だけでなく、コンテンツ更新のタイミングまで含めた運用的な視点と戦略が必要となってきます。

 なかなか複雑で面倒な仕組みではありますが、有効に活用できた際には、驚く程の効果があるのも確かで、キャッシュあってこそのWCSと言っても過言ではありません。(どれほどの効果があるのかは、また別の機会にお話ししましょう。今後もキャッシュについては、テーマとして書いていく予定です。)

 ジークスは、これまでの開発からキャッシュの強さ、怖さを経験してきました。そのような経験があったからこそ、WCSで最適なシステムを構築することができます。