2009年2月4日水曜日

CMD.EXE に URL を渡す場合の注意

すこしはまったので、書いておく。

 openURL.cmd などという感じでURLを元にブラウザを開くスクリプトを書いた場合に、渡すパラメータの文字には、CMDとしての制限が存在する。
 Unix系だと、shやcshに渡す場合に 「*」や「$」や「&」がShellに解釈されてしまってそのままの文字としては渡されないのと同じである。
 実は、CMDの場合も同様であり、以下のものは解釈されてしまう。
「% ^ " < > & | ( ) = ; ,」などが特殊な意味をもつものであり、特に「& && || | 」は、クォートされていない場合は、文区切りを意味してしまう。たとえば、以下の例だと、

openURL.cmd http://x.y.z/s?a=b&c=d

「&」の前までと後ろが別の文とみなされるため、CMD.EXEでは以下のような実行をする。

openURL.cmd http://x.y.z/s?a=b
c=d

もちろん、2行目はエラーとなる。クォートすればOKであり、きちんとURLを認識する。

openURL.cmd "http://x.y.z/s?a=b&c=d"


問題はクォートしてもだめな文字が入った場合であり、代表格は「%」であるが、これは「%%」となり、他の多くの特殊文字のエスケープである「^」ではないところが注意点である。

参照:CMD.EXE TIPs

パフォーマンスチューニング

実行速度のパフォーマンスが悪いと感じる場合の対処法をまとめる。
■前提として
 実行速度や処理効率の目安として以下の2つを想定する
  ・反応速度:ある処理を起動してから応答が返るまでの時間
  ・スループット:単位時間あたりに処理できる件数
 単独で測定している場合は、反応速度を見ていることになるのだが、
同時複数の処理をさせる場合にはスループットが重要になる。システムが
理想的なスケーラブル性を持っている場合は、規模を調節することで
スループットを自由に変更できることになるのだが、実際には様々
な要因により、反応速度が速くても、ある件数以上になるとスループット
が落ちてしまうのが普通である。
 速度の早い、遅いは相対的なものであり、絶対的な指標は存在しない。
対象とするシステムにおいて妥当な値から見てどれくらい劣化しているか
と考える必要がある。慣用的に用いられる4秒ルールなどは、人間相手の
反応速度としては妥当であろう。(ちなみに、この4秒はTV放送などの世界で
は黙っていられる限界と思われているようで、これ以上沈黙が続くと視聴者
が違和感を感じる長さのようだ)

■解決のための一般的ステップ
 以下のような順序で対応すれば解決への糸口が見つかるであろう。
1)調査:詳細な情報の収集
2)対象範囲確定:関連のありそうな部分とそれ以外を分離
3)データ収集:ログや設定値など
4)問題個所の推定:3)との繰り返し
5)再現:環境や条件をなるべく合致させて
6)対処:設定変更やコード修正
7)確認:

■調査
 できる限り詳しく状況を聞き取る。早い、遅いは個人的・相対的な値である
場合が多いので、数値の表わせるものとして取得すること。ポイントは下記のもの。

・処理状況:
  どんな状況で、どの処理や操作をした場合にパフォーマンス劣化を認められたか
・データ
  特定のデータを使用した場合に発生するか
・繰返し:
  特定の回数繰り返した場合に発生するか、単独で発生するか
・時系列的推移:
  いつからそうなったのか
・他の処理との関連:
  特定の時間帯でないと発生しないか
  他の処理を同時に行った場合にのみ発生するか

■対象範囲確定
 関連しない部分を切り離し、関連する部分を明らかにする。
・ネットワーク
  実行環境でネットワークに依存する部分がある場合
・データベース
  実行環境がデータベースを使用している場合
・マシン
  該当するマシンすべて

■データ収集
 設定値一覧やログファイルなどの処理実行の定義と経過に関するデータを取得する。
 当該アプリケーションそのものだけでなく、その動作環境において調査対象とした
すべての部分を考慮する必要がある。例を以下に示す。

・システム設定、システムログ
・サーバ設定、ログ:アプリケーションがAppServerなどで動作している場合
・データベース設定、ログ:DBを使用している場合
・ネットワーク設定、ログ:ネットワークを使用していて関連がある場合

 もし、有用な情報が取得できない場合は、フラグを設定して詳細情報を出力するように
変更してから再現させてログを取得するべきである。

■問題個所の推定
 収集したデータから問題となりそうな対象と無関係な対象を切り分けていく。
 関連がある対象に関しての情報を精査し、問題個所を推定する。
・ネットワーク
  同じネットワークを使用する別のアプリケーションの動作状況などを調査して問題性の有無を確認
・データベース
  同じデータベースを使用する別アプリケーションなどを調べる
・マシン
  同じマシンで稼働する別のアプリケーションや、システムログの情報から

 対象がしぼれてくれば、フラグを追加して詳細ログを取ったり、ソースを調査して原因と
なりそうな部分を見つけるなどの方法を試す。

2009年1月30日金曜日

CMD.EXE 変数の評価

CMDなどの変数は遅延評価しないのがデフォルト。
下記のようなコードでは、%ERRORLEVEL%は起動時に値が「0」で入ってしまい、途中では変化しない。

@ECHO ON

@ECHO OFF
::cmd.exe
SET NETADRS=%1
for /L %%i in (1,1,254) do (
CALL ping -l 0 -n 1 -a %NETADRS%.%%i
ECHO ERROR : %ERRORLEVEL%
IF %ERRORLEVEL%==0 ECHO FOUND %%i
)


ただしくは、以下のように「ERRORLEVEL」を裸で使用する。

IF ERRORLEVEL 0 ECHO FOUND %%i


 ところが、これだといつでも「FOUND」となってしまう。調べると「 DOS コマンド一覧 > If 」にあるように、ERRORLEVELの指定はその数値以上という意味であった。
 上記のコードではエラーレベルが0以上ならと解釈されていつでも実行することになった。正しくは、下記のようにする。


@ECHO OFF
REM search network ips with ping
::cmd.exe
SET NETADRS=%1
SET DSPNORES=%2
IF "%NETADRS%"=="" (
ECHO "usage: %0 NETADRS(xx.xx.xx) [DSPNORES]"
GOTO END
)

for /L %%i in (1,1,254) do (
ping -l 0 -n 1 -a %NETADRS%.%%i >:NULL
IF ERRORLEVEL 1 (
IF NOT "%DSPNORES%"=="" ECHO -NORES %NETADRS%.%%i
)ELSE ECHO +FOUND %NETADRS%.%%i
)
:END
@ECHO ON

2009年1月29日木曜日

Teeda(Seasar2) のSelectアイテム

Selectタグに項目を埋めるためにListでフィールドを作成したが、意味不明のエラー。

public List<Map<String, String>> locidItems;


* text

java.lang.NullPointerException: text
at org.seasar.framework.util.AssertionUtil#assertNotNull (AssertionUtil.java#41)
at org.seasar.teeda.core.context.html.HtmlResponseWriter#writeText (HtmlResponseWriter.java#152)
at org.seasar.teeda.core.render.html.HtmlSelectManyListboxRenderer#renderSelectItems (HtmlSelectManyListboxRenderer.java#179)
at org.seasar.teeda.core.render.html.HtmlSelectManyListboxRenderer#encodeHtmlSelectListboxEnd (HtmlSelectManyListboxRenderer.java#91)
at org.seasar.teeda.core.render.html.HtmlSelectManyListboxRenderer#encodeEnd (HtmlSelectManyListboxRenderer.java#68)
at javax.faces.component.UIComponentBase#encodeEnd (UIComponentBase.java#348)
at org.seasar.teeda.core.util.RendererUtil#renderChild (RendererUtil.java#327)
以下省略


ここにも同じ経験の人がいて、解決も乗っていた。(解決を見る前に自分でも解決したが、、、)

 サンプルがいまいち分かりにくかったのだが、ListならDtoでよく、Mapなら単独のMapでよかった。
それを、MapのListにし、各Mapには put(labelStr, keyStr) の形でデータを入れていたのだが、MapのListの場合はDtoと同じ扱いになり、"label","value"という名称のフィールドとして扱えることが必須であった。
 つまり、今回の場合だと、Listに追加するMapには、以下のようにデータを入れる必要があった。
map.put("value",keyStr);
map.put("label",labelStr);

2009年1月23日金曜日

Ejb On GlassFish 続き

GlassFishのACCでのLoad-Balance/Fail-Overに関して、SUNのForumに質問して分かったこと。
1)クラスタ内のEJBに対するLB/FOの設定はORBの機能
2)GFのORMは、DynamicにLBする機能はなく、初期接続時のLBのみである
つまり、InitalContext を作成して、Lookupした時点でLBされるのであり、それ以後はおなじクラスタメンバにアクセスすることになる。JBOSSやWAS、WebLogicでは、Optionが必要な場合もあるが、複数の方式のLBをサポートしている。たとえば以下のようなもの。
接続時にLB
毎回LB
トランザクションごとにLB
UDS/Forteでは、最初から上記の方式をサポートしていたことを考えると、GFのORBは退化してしまっているように感じる。ただし、EJBの世界ではUDSのようなRouterとなるプロセスやスレッドを持たないため、ベンダー毎の独自拡張となっているようだ。

2009年1月7日水曜日

Ejb on GlassFIsh

クラスタを組んだGFにEJBを配置してクライアントから呼び出していたが、以下の原因不明のエラーが発生。


Caused by: java.lang.NullPointerException
at com.sun.enterprise.util.ORBManager$1.run(ORBManager.java:386)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.enterprise.util.ORBManager.setORBSystemProperties(ORBManager.java:381)
at com.sun.enterprise.naming.SerialInitContextFactory.(SerialInitContextFactory.java:65)
... 28 more

結局ソースを調べてわかったのは、System.getProperty("java.vendor") が null になっていた。
これは、SystemPropertiesの設定をするところで、以下のようにしたため。
System.setProperties(prpty);
これをすると、prptyに定義されているものだけが残り、ほかはすべてNULLとなる。
Propertiesの指定をした理由はSunのACCを使用せずにクラスタが使えないかを調べるためだったが、
結局普通のクライアントからだとクラスタ化されたJNDIを引くことができずに撃沈。

ACCを使用すると、関連するインスタンスを探し出してそのJNDIをリストアップし、重みづけをして負荷分散できるように設定しているらしいことがログからわかった。ただし、実際のコードの実行部分になると、以下のようなエラーが発生してしまう。


Caused by: java.lang.RuntimeException: メインクラス内の持続性ユニットの注釈の確認中にエラーが発生しました
at com.sun.enterprise.appclient.StandAloneAppClientInfo.classContainsAnnotation(StandAloneAppClientInfo.java:101)
at com.sun.enterprise.appclient.AppClientInfo.mainClassContainsPURefcAnnotations(AppClientInfo.java:413)
at com.sun.enterprise.appclient.AppClientInfo.appClientDependsOnPersistenceUnit(AppClientInfo.java:382)
at com.sun.enterprise.appclient.AppClientInfo.completeInit(AppClientInfo.java:175)
at com.sun.enterprise.appclient.AppClientInfoFactory.buildAppClientInfo(AppClientInfoFactory.java:149)
at com.sun.enterprise.appclient.MainWithModuleSupport.(MainWithModuleSupport.java:366)

2009年1月5日月曜日

大阪王将が閉店

国道沿いとはいえ、ちょっと入りにくい場所だったのが災いしたのか赤字だったようだ。
30日にASAPASS割引を使って6人で親睦会、アツアツのバイキングを堪能して7500円と
お得だったのに残念だ。