「逆引きリファレンス」カテゴリーアーカイブ

コードサイニング署名

Curlはローカルアクセスなど自由度が高いため、ユーザが信頼できるアプレット(アプリケーション)として公開するため、Curlアプレットに対してコードサイニング署名をすることができます。これにより信頼性の高いアプリケーションとしての証明と、改ざん検証ができます。

手順は以下のようになります。

  1. 信頼できるCA(ベリサインGlobalSignなど)に申請し、CA証明書を発行してもらいます。Curlではpkcs#12形式をサポートしております。
  2. Curl IDE上で、上記CA証明書を使ってCurlアプレットに署名します。(IDEでメニューの「プロジェクト」→「ターゲット設定の編集」→「ターゲット」タブからターゲットを選択し、「設定」ボタンを押下します。「ディプロイコードを署名」にチェックを入れ、「証明書のロケーション」(上記CA証明書ファイル)を指定します。ここまで指定できたらすべてOKでポップアップ画面を閉じます。
  3. メニュー「プロジェクト」から「XXXXのディプロイメント」を行いますと、起動フィイル(start.curl)とマニフェストファイル(manifest.mcurl)にcurl-file-signatureというブロックが追加されます(署名されます)。
  4. この上記のディプロイメントされたファイルをwebサーバ上にアプリケーションを公開します。(とりあえずテスト的にローカルに作られた上記ファイルを起動して、テストできます。)
  5. start.curlを実行すると、「Curlアプレットのセキュリティ警告ポップアップ」が表示されます。(※「常に許可」ボタンを押下しますと、コントロールパネルの証明書の欄に登録されます。)

 

 

共通鍵暗号方式

Curlで共通鍵暗号方式を利用して、暗号化・復号化を実現するには、EncryptStream(暗号)、DecryptStream(複合)クラスを利用します。(これらを利用する際は、CURL.CRYPTO.CIPHERパッケージをインポートしてください。) Curlでは共通鍵暗号方式のアルゴリズムとして、トリプルDES, rc2, rc4、AES AES-128、AES-192、AES-256 AESはVer.8より提供開始 }をサポートしています。詳細はAPIドキュメントのAlgorithmクラスを参照ください。このアルゴリズムを共通鍵のSessionKeyクラスに指定し、EncryptStreamを利用して暗号化します。詳細は以下のサンプルを御覧下さい。

※ Curl RTEの利用者は本暗号化機能を変更して利用することはできません。また、本暗号化機能を使用する際に、本サイトのサンプルや、製品ドキュメントによって、利用することが可能です。

{import * from CURL.CRYPTO.CIPHER}

{define-proc public inline {encrypt
algorithm:Algorithm = Algorithm.des3,
common-key:{Array-of byte},
message:{Array-of byte},
out:ByteOutputStream
}:void
{with-open-streams enc-out =
{TranscodingTextOutputStream
{EncryptStream
out,
{SessionKey.from-bytes algorithm, common-key}
},
CharEncoding.utf8,
false
}
do
{for i:int = 0 below message.size do
{enc-out.write-one message[i] asa byte}
}
}
}

{define-proc public inline {decrypt
algorithm:Algorithm = Algorithm.des3,
common-key:{Array-of byte},
in:ByteInputStream
}:String
def buf = {StringBuf}
{with-open-streams dec-in =
{TranscodingTextInputStream
{DecryptStream
in,
{SessionKey.from-bytes algorithm, common-key}
}
}
do
{for b in {dec-in.read} do
{buf.append b asa char}
}
{return {buf.to-String}}
}
}

{do
def secret-file = “secret-file”
def key = {{Array-of byte}
1,2,3,4,0,0, 0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0,0
}

|| 暗号
{encrypt
key, ||キー
{{Array-of byte} 50, 51, 52},
{write-open-byte {url secret-file}}
}

{decrypt
key, ||キー
{read-open-byte {url secret-file}}
}
}


Ver.8よりAESを指定することができます。

Algorithm.aes-128-cbc、 Algorithm.aes-192-cbc、 Algorithm.aes-256-cbc

上記サンプルにてアルゴリズム、キー長を変更することにより確認することができます。


ちなみに、以下の拡張ライブラリを利用するとさらに簡単に暗号化できます。

拡張ライブラリ(暗号・複合API)

WSDKを使ったExcel(XMLスプレッドシート)の取り込み

ここでは、Excelのデータ形式の1つであるXMLスプレッドシートをWSDKを使用し読み込む際のtipsを紹介いたします。

WSDKを使用したXML解析で、パス表現を使って要素を抽出したいときは、下記のように要素を抽出します。

{XDMElement.search “タグ名”}

該当するXMLに名前空間がつけられていると、単純に名前のみではパスの認識ができません。(下記のXML参照)
XMLが名前空間を含んでいる場合はひと手間加える必要があります。

{XDMElement.search “名前空間:タグ名”}

ただし、単純に上記のように検索を行うと「XDMException: No declaration for prefix ‘名前空間’」

という例外が出てしまいます。

そこで、名前空間を検索前に認識させる必要が出てきます。(名前空間認識プロシージャを参照)

 

 

名前空間を持ったXML(Book2.xml)

 



<Workbook xmlns=”urn:schemas-microsoft-com:office:spreadsheet”
 xmlns:o=”urn:schemas-microsoft-com:office:office”
 xmlns:x=”urn:schemas-microsoft-com:office:excel”
 xmlns:ss=”urn:schemas-microsoft-com:office:spreadsheet”
 xmlns:html=”http://www.w3.org/TR/REC-html40“>
 <Styles>
  <Style ss:ID=”Default” ss:Name=”Normal”>
   <Alignment ss:Vertical=”Center”/>
   <Borders/>
   <Font ss:FontName=”MS Pゴシック” x:CharSet=”128″ x:Family=”Modern” ss:Size=”11″/>
   <Interior/>
   <NumberFormat/>
   <Protection/>
  </Style>
  <Style ss:ID=”s21″>
   <Borders>
    <Border ss:Position=”Bottom” ss:LineStyle=”Continuous” ss:Weight=”1″/>
    <Border ss:Position=”Left” ss:LineStyle=”Continuous” ss:Weight=”1″/>
   </Borders>
  </Style>
  <Style ss:ID=”s23″>
   <Borders>
    <Border ss:Position=”Bottom” ss:LineStyle=”Continuous” ss:Weight=”1″/>
    <Border ss:Position=”Left” ss:LineStyle=”Continuous” ss:Weight=”1″/>
   </Borders>
   <Interior ss:Color=”#FFCC00″ ss:Pattern=”Solid”/>
  </Style>
 </Styles>
</Workbook>

 

名前空間認識プロシージャ

 

{define-proc {dwim-prefix-declarations
                 subject:XDMElement,
                 context:XDMNamespaceContext = xml-namespace-context
             }:void
    {subject.walk-children
        || walk descendants and self
        include-self? = true,
        include-descendants? = true,
        {proc {n:XDMNode}:bool
            {type-switch n
             case e:XDMElement do
                || check declared prefixes
                {if-non-null ps = e.namespace-declarations then
                    {for p in {ps.get-prefixes} do
                        {if-non-null ns = {ps.get-uri p} then
                            {if {context.get-uri p} == null
                             then
                                || extend global declarations accordingly
                                {context.declare-prefix? p, ns}}}}}}
            || continue walking
            {return true}}}
}

 

 

{value
    let loc:Url = {url “TESTDATA/Book2.xml”}
    ||XMLdocumentModelエレメント
    let xml:XDMElement =
        {build-xml preserve-whitespace? = false, loc}.root
    
    ||名前空間認識
    {dwim-prefix-declarations xml}
    let worksheets:XDMNodeSet = {xml.search “ss:Styles”}
    {output worksheets.size}
}

 

グラフカスタマイズ-円グラフのカスタマイズ

Curlでは様々なグラフが提供されており、また色々とカスタマイズが可能ですが、どのようにカスタマイズしたらよいか悩んでいる人もいるのではないでしょうか。

このシリーズでは、円グラフのカスタマイズ例をご紹介していきます。

まず、Curlの円グラフはPieSetとPieChartから構成されています。

簡単に説明するとPieSetが実際の円グラフで、PieChartはその円グラフを入れる箱のようなものです。

今回はPieSetで使用されるラベルと凡例のカスタマイズ方法をご紹介します。

まず、円グラフの元となるデータを下記の形式で設定します。

let rs:RecordSet =  {RecordSet
                               {RecordFields
                                   {RecordField
                                       “Event”,
                                       domain = String
                                   },
                                   {RecordField
                                       “Risk”,
                                       domain = double
                                   },
                                   {RecordField
                                       “Number”,
                                       domain = int64
                                   }
                               },
                               {RecordData Event = “むぎ茶”, Risk = 25.0, Number = 250},
                               {RecordData Event = “玄米茶”, Risk = 50., Number = 500},
                               {RecordData Event = “烏龍茶”, Risk = 12.5, Number = 125},
                               {RecordData Event = “緑茶”, Risk = 12.5, Number = 125}
                            }

次に円グラフとなるPieSetを作成します。少し長いですが、ポイントはコメントで記述してあります。

    let pieset:PieSet = {PieSet
                            rs,
                            “Risk”,
                            ||枠線の色
                            wedge-group =
                                {ShapeGroup
                                    border-color = “white”
                                },
                            ||ラベルに使用するデータ
                            label-data =
                                {ChartDataSeries rs, “Event”},
                ||ラベルの作成
                            label-factory = {proc {pie-set:PieSet,
                                                   set-label:#String,
                                                   data-label:#String,
                                                   value-label:#String,
                                                   position:Distance2d,
                                                   data:ChartDataSeries,
                                                   record:Record,
                                                   record-index:int,
                                                   inner-radius:Distance,
                                                   outer-radius:Distance,
                                                   total-radius:Distance,
                                                   start-angle:Angle,
                                                   stop-angle:Angle
                                                  }:Shape   ||返却の型がShapeなので文字以外でも画像等をラベルに指定することも可能です

                                                let font-col:FillPattern = “#222222” ||まず、基本の文字色を宣言します
                                                {if record[“Risk”] asa double >= 25 then ||Risk項目が25%以上であれば、文字色を赤に設定します
                                                    set font-col = “red”
                                                }
                                               
                                                {return
                                                    {TextShape
                                                        font-size = 10pt,
                                                        color = font-col,
                                                        halign = “center”,
                                                        valign = “center”,
                                                        translation = position, ||文字の配置は、この部分で変更できます
                                                        {non-null data-label}
                                                    }
                                                }
                                            },
                            ||凡例の表示
                            legend-enabled? = true,
                            ||凡例の作成
                            legend-entry-factory =  {proc {chart:Chart,
                                                           data-series:ChartDataSeries,
                                                           record:#Record,
                                                           color:FillPattern,
                                                           legend-index:int
                                                          }:Graphic
                                                        let font-col:FillPattern = “black”
                                                        {return
                                                            {HBox
                                                                valign = “center”,
                                                                 ||%に連動した棒グラフを作成しています
                                                                {Fill
                                                                    width = (record[“Risk”] asa double * .5pt) + 10pt,
                                                                    height = 8pt,
                                                                    background = color, ||色は円グラフの色と連動しています
                                                                    border-width = 0px
                                                                },
                                                                {Fill width = {make-elastic minimum-size = 20pt}},
                                                                ||%が25%以上のデータに対しては、文字列を赤く変更しています
                                                                {if-non-null record then
                                                                    {if record[“Risk”] asa double >= 25 then
                                                                        set font-col = “red”
                                                                    }
                                                                    {HBox
                                                                        color = font-col,
                                                                        {TextFlowBox
                                                                            width = 50pt,
                                                                            {data-series.field.domain.format
                                                                                record[data-series.field.name]
                                                                            }
                                                                        },
                                                                        {TextFlowBox width = 40pt, record[“Number”] & “件”},
                                                                        {TextFlowBox width = 30pt, {String record[“Risk”]} & “%”}
                                                                    }
                                                                 else
                                                                    data-series.field.caption
                                                                }
                                                            }
                                                        }
                                                    }
                        }

最後に円グラフを入れる箱となるPieChartを作成します。 

    {let testpiechart:PieChart = {PieChart
                                     width = 15cm,
                                     height = 10cm,
                                     pieset
                                 }
    }

 このPieChartを表示するとカスタマイズされた円グラフが表示されます。

 

ちなみに、カスタマイズしていない凡例とラベルの場合は下記のようになります。

 

 

あまり派手な変化ではないですが、このように凡例とラベルの変更は、PieSet作成時に設定することができます。

 次の記事では、この円グラフに対してよりインタラクティブな機能を持たせる方法をご紹介します。

グラフカスタマイズ-インタラクティブな円グラフ

Curlでは様々なグラフが提供されており、また色々とカスタマイズが可能ですが、どのようにカスタマイズしたらよいか悩んでいる人もいるのではないでしょうか。

このシリーズでは、円グラフのカスタマイズ例をご紹介していきます。

まず、Curlの円グラフはPieSetとPieChartから構成されています。

簡単に説明するとPieSetが実際の円グラフで、PieChartはその円グラフを入れる箱のようなものです。

 今回は、PieSetを継承して作成した、マウスオーバーをするとその項目がハイライトされるInterractivePieSetをご紹介します。

API説明

InteractivePieSetクラス

マウスオーバーした領域をハイライトします。

パッケージ

COM.CURLAP.ADVANCED-CHART

スーパークラス

PieSet

プロパティ

sample-color-array:{Array-of FillPattern} 色を保持するフィールド

highlight-color:FillPattern ハイライトした際の色

コンストラクタ

default
引数1(records:RecordSet)  表示用データ
引数2(major:String)          円の比率を決定する基準レコード名
引数3(event-name:String) 凡例に用いるレコード名

下記の引数は任意になります
引数4(colors:{Array-of FillPattern} = self.sample-color-array) 円グラフの色
引数5(highlight-color:FillPattern = “red”) ハイライトする色(独自色)
引数6(just-hilight?:bool = true)ハイライトの際に、ただ色を薄くするだけかの判断
引数7(wedge-border-color:FillPattern = “white”)円グラフを縁取る色

メソッド

なし

利用方法

InteractivePieSetとして宣言します。独自の引数のほかに、PieSetの引数も使用することが可能です。 
今回は、円グラフのカスタマイズの記事で使用したPieSetを引用してInteractivePieSetを宣言します。

 

    let pieset:InteractivePieSet= {InteractivePieSet
                            rs,
                            “Number”,
                            “Event”,
                            ||ここから下の引数はPieSetと同じです
                            ||枠線の色
                            wedge-group =
                                {ShapeGroup
                                    border-color = “white”
                                },
                            ||ラベルに使用するデータ
                            label-data =
                                {ChartDataSeries rs, “Event”},
                ||ラベルの作成
                            label-factory = {proc {pie-set:PieSet,
                                                   set-label:#String,
                                                   data-label:#String,
                                                   value-label:#String,
                                                   position:Distance2d,
                                                   data:ChartDataSeries,
                                                   record:Record,
                                                   record-index:int,
                                                   inner-radius:Distance,
                                                   outer-radius:Distance,
                                                   total-radius:Distance,
                                                   start-angle:Angle,
                                                   stop-angle:Angle
                                                  }:Shape   ||返却の型がShapeなので文字以外でも画像等をラベルに指定することも可能です

                                                let font-col:FillPattern = “#222222” ||まず、基本の文字色を宣言します
                                                {if record[“Risk”] asa double >= 25 then ||Risk項目が25%以上であれば、文字色を赤に設定します
                                                    set font-col = “red”
                                                }
                                               
                                                {return
                                                    {TextShape
                                                        font-size = 10pt,
                                                        color = font-col,
                                                        halign = “center”,
                                                        valign = “center”,
                                                        translation = position, ||文字の配置は、この部分で変更できます
                                                        {non-null data-label}
                                                    }
                                                }
                                            },
                            ||凡例の表示
                            legend-enabled? = true,
                            ||凡例の作成
                            legend-entry-factory =  {proc {chart:Chart,
                                                           data-series:ChartDataSeries,
                                                           record:#Record,
                                                           color:FillPattern,
                                                           legend-index:int
                                                          }:Graphic
                                                        let font-col:FillPattern = “black”
                                                        {return
                                                            {HBox
                                                                valign = “center”,
                                                                 ||%に連動した棒グラフを作成しています
                                                                {Fill
                                                                    width = (record[“Risk”] asa double * .5pt) + 10pt,
                                                                    height = 8pt,
                                                                    background = color, ||色は円グラフの色と連動しています
                                                                    border-width = 0px
                                                                },
                                                                {Fill width = {make-elastic minimum-size = 20pt}},
                                                                ||%が25%以上のデータに対しては、文字列を赤く変更しています
                                                                {if-non-null record then
                                                                    {if record[“Risk”] asa double >= 25 then
                                                                        set font-col = “red”
                                                                    }
                                                                    {HBox
                                                                        color = font-col,
                                                                        {TextFlowBox
                                                                            width = 50pt,
                                                                            {data-series.field.domain.format
                                                                                record[data-series.field.name]
                                                                            }
                                                                        },
                                                                        {TextFlowBox width = 40pt, record[“Number”] & “件”},
                                                                        {TextFlowBox width = 30pt, {String record[“Risk”]} & “%”}
                                                                    }
                                                                 else
                                                                    data-series.field.caption
                                                                }
                                                            }
                                                        }
                                                    }
                        }

このInteractivePieSetをPieChartにセットして表示させると結果は下記のようになります。

 

サンプル

円グラフサンプル

*Version7で作成しています。ランタイムのダウンロードはこちらから。

拡張ライブラリ v0.7 / v0.8 概要

Curl拡張ライブラリは、ユーティリティ機能をはじめとして、コレクション操作、ロギング、キャッシング、入出力などのコンポーネントが多数含まれています。これはオープンソース(Apache License2.0)として提供しており、SourceForgeからダウンロードできます。

具体的には以下のコンポーネントが梱包されています。

LANG
– ユーティリティ:String, Number, DateTime, Unit (Distance, Time), Reflection, only-if, a few switch (since0.7)

COLLECTIONS
– ユーティリティ:Array, HashTable
– コレクションクラス:MultiHashTable, MultiKeyHashTable, OrderedHashTable, OrderedSet
– マクロ:collect, range

UI
– 2度押し防止, DTO from/to Controls, Graphic検索

CACHING
– メモリキャッシュ, キャッシュのディスク保存

DATA-ACCESS
– ユーティリティ:RecordSet, RecordData

CODEC
– hex-encode, hex-decode

Messages
– MessageList

UTIL
– diff (since0.7)
– stop-watch
– Properties

ENVIRONMENT
– environment-switch, if-local-applet, IP・ホスト名取得

CRYPTO
– MD5, SHA-1, HMAC-SHA-1(since0.7), DES3, RC2, RC4

JAPAN
– 郵便番号、都道府県

MATH
– 数学関数

IO
– ディレクトリ検索
– 圧縮・解凍, オブジェクト保存・復元, RecordSet保存・復元

LOGGING
– ログ取得, ログローテート

注意)バージョン0.7からCurl6.0及び7.0に対応されています。0.8からはCurl8.0に対応されています。

いくつかのswitch文

switch文を拡張した、新たなswitchマクロがバージョン0.7から追加されました。

■正規表現による文字列のスイッチ文

            def str = “Curl is great, I like Curl”
            {regexp-switch str
             case “^Curl.*Curl$” do
                {output strは正規表現^Curl.*Curl$に一致。}
             case “^Java.*Java$”, “^Ruby.*Ruby$” do
                {output strは正規表現^Java.*Java$もしくは^Ruby.*Ruby$に一致。}
             else
                {output str}
            }

■文字列の先頭文字によるスイッチ文(この逆でsuffix-switchもあります。)

            def str = “abcdef”
            {prefix-switch str, ignore-case? = true
             case “abc” do
                {output strはabcから始まります。}
             case “xyz”, “xxx” do
                {output strはxyzもしくはxxxから始まります。}
             else
                {output str}
            }

■数値の範囲によるスイッチ文

            def i = 50
            def result =
                {range-switch i
                    case 0 to 20 do “Too bad”
                    case 26 to 50 do “Bad”
                    case 51 to 75 do “Not bad”
                    case 75 to 99 do “Good”
                    case 100 do “Excellent”
                    case 101 to 200, 400 to 600 do “Strange!?”
                    else {unreachable}
                }
            {output result} || ==> “Bad”

注意)バージョン0.7からサポートされます。

 

diffプロシージャ(文字列の差分)

diffコマンドのような文字列の差分を比較するプロシージャがCOM.CURLAP.LIB.UTILパッケージに含まれます。

これは以下のサンプルように利用することができます。

 

            {diff
                “map”, “apple”,
                {fn ses, o, n, p1, p2 =>
                    {switch ses
                     case ShortestEditScript.common do
                        {output “common:” & o}
                     case ShortestEditScript.added do
                        {output “appended:” & n}
                     case ShortestEditScript.deleted do
                        {output “deleted:” & o}
                    }
                }
            }

比較する引数を第1と第2引数に指定し、比較した1文字ごとに第3引数のプロシージャが実行されます。このプロシージャの1個目の引数で、2つの文字列内で共通した文字か、削除されたものか、追加されたものかを判断できます。このサンプルの場合、apが共通、mが削除、pleが追加された文字と認識されます

注意)バージョン0.7からサポート

RecordSet大量更新の高速化

RecordSetを大量更新する際、更新毎に更新イベントが発生します。これを一時的に回避することで、何十倍もしくはそれ以上、高速になります。

以下がサンプルになります。大量更新をするロジックをwithブロックで囲み、RecordSetのbatch-events?セッターにtrueをセットします。

 

def rs = {RecordSet …….} || RecordSet定義
{with rs.batch-events? = true do
    {for r in rs do
        || RecordSetの更新ロジック
    }
    {rs.commit} || 更新をcommit
}

 

CurlORB サンプルダウンロード

CurlORB0.6もしくは0.7のサンプルコードです。Apache Tomcat5.5もしくはApache Tomcat6.0上で簡単に動作確認を行うことができ、サンプルコードを見ることができます。

サンプルダウンロード(0.6用)

サンプルダウンロード(0.7用)

【サーバ】

①.CurlORBモジュールを下記サイトからダウンロードします。(0.7stable版)
http://sourceforge.net/projects/curlorb/

※ curl-orb_0.7_stable_bin.zipをダウンロード

②.Tomcatをインストールし、CurlORBモジュールのjavaディレクトリ配下にあるwebディレクトリをcurl-orb-serverに名称を変更してTomcatのwebapps配下にコピーします。

③.当サンプルのjava/webディレクトリ配下のWEB-INFディレクトリを、上記java/web配下のWEB-INFディレクトリに上書きコピーします。

④.Tomcat起動します。

【クライアント】

①.CurlIDEもしくはCurlRTEをインストールします。

②.当サンプルのcurlディレクトリをCurlORBモジュールのcurlディレクトリ配下にコピーします。

③.curlディレクトリ配下にあるsample1.curlもしくはsample2.curlを実行しますとサンプル画面が起動します。(とてもしょぼいですが・・・・。)

④.各コードの詳細については、別のCurlORBページを参照ください。

クィックスタート

ダウンロード

ダウンロードはSourceForge(下記URL)からダウンロードします。(curl-orb-V0.8.zipをダウンロードします。)

http://sourceforge.net/projects/curlorb

Eclipse開発環境へCurl ORBをセットアップ

Curl ORBサーバをEclipseへセットアップする手順を説明します。この開発環境をセットアップする前に、以下のツールをダウンロード及びインストールします。

ツールのインストール後、Eclipseを起動し、新規プロジェクトを作成します。”File – New – Other”を選択し、”New”画面のツリーから、”Web – Dynamic Web Project”を選択し、”Next”ボタンを押下します。次に”New Dynamic Web Project”画面が表示されますので、任意の”Project name”を入力し”Next”ボタンを押下します。最後に”Context Root”に”curl-orb-server”を入力し、”Finish”ボタンを押下しますと、新規プロジェクトが作成されます。

次にCurl ORBサーバを当プロジェクトに取り込むため、ダウンロードしたファイルの”java/web/WEB-INF”と”java/web/index.html”を当プロジェクトのWebContentディレクトリ配下に上書きコピーします。

上記の設定が終了しましたら、Eclipse上でTomcatを起動します。これには、当プロジェクトを右クリックし、”Run AS – Profile on Server”でサーバの設定(Tomcatのホームや当プロジェクトをこのサーバ設定に追加等の設定)をし、サーバを起動します。WTPの詳細については、ThinkITが参考になると思います。
(注意)EclipseでTomcatを起動する前に、Tomcatが停止されていることを確認してください。

動作確認

動作確認をするには、http://localhost:8080/curl-orb-server にブラウザからアクセスしてください。”Welcome to Curl ORB for java”と表示されましたらサーバのセットアップは成功です。

簡易アプリケーションの構築手順

CurlとJavaを連携するアプリケーションを構築するには以下の手順を実施します。

  1. サーバサイドのサービスクラス(POJO)作成
  2. サーバサイドのサービスクラス(POJO)からCurlコードを自動生成
  3. クライアントコードを記述

1.サーバサイドのサービスクラス(POJO)作成

サーバサイドでcom.testパッケージと以下のようなHelloクラスを作成します。(ここでは@RemoteServiceアノテーションを付け忘れないようにしてください。)

package com.test;

import com.curl.orb.security.RemoteService;

@RemoteService
public class Hello {

// constructor
public Hello() {
}

// methods
public String sayHello(String str) {
return “Hello ” + str;
}
}

作成しましたら、サーバを再起動します。(下図ようにサーバを選択し、”右クリック-Restart”を実行します。)

orb-q1.jpg

2.サーバサイドのサービスクラス(POJO)からCurlコードを自動生成(コード・ジェネレータ)

次にダウンロードして解凍したファイルのcurl-orb-V0.8/curl/COM.CURL.ORB-V0.8/8.0ディレクトリ にあるcode-generator.dcurlを起動します。(もちろん事前にCurlランタイムのインストールが必要です。)

ws000002.jpg

上記画面にて”Service Class (Http Session)”を選択してNextボタン押下します。

ws00.jpg

上記画面にてcom.test.Hello(パッケージ名.クラス名)を入力してNextボタンを押下します。(Browseボタンを押下しますと一覧から選択することもできます。)

WS000001.jpg

上記画面にてClass Fileの”File”ボタンを押下し、出力先を決定した後、”Generator”ボタンを押下します。これによりHello.scurlとload.scurlが生成されます。(以下が生成されたコード)

Hello.scurl

{import * from COM.CURL.ORB}

{define-class public Hello {inherits HttpSessionClient}

{constructor public {default server-url:#Url = null}
{construct-super.HttpSessionClient “com.test.Hello“, server-url = server-url}
}

{method public {say-hello v0:String}:#String
{return {self.invoke “sayHello“, arguments = {FastArray v0}}}
}

}

load.scurl

{curl 8.0 package}
{package COM.TEST}
{include “Hello.scurl”}

コード生成ツールの詳細な利用方法についてはこちらを参照ください。

注意
CurlのネーミングルールとJavaのネーミングルールの差を吸収するため、Javaのパッケージ名がCurl側では大文字に変換されます。(例えば、com.test->COM.TEST)またメソッド名は大文字部分がハイフン+小文字となります。(例えば、sayHello – say-hello、sayHELLO – say-hello)

3.クライアントコードを記述

まず、Curl側で新規プロジェクトを作成(”ファイル – 新規 – 新規プロジェクト – アプレットを含んだプロジェクト”を選択)します。次にCurl ORBクライアントを取り込むため、”プロジェクト – デリゲート先の追加”でダウンロードしたCurl ORBディレクトリのcurl/COM.CURL.ORB-V0.8/8.0/manifest.mcurlを選択します。

次に生成されたファイル(Hello.scurlとload.scurl)をプロジェクトに追加するため、”プロジェクト – パッケージの追加”を選択し、生成されたload.scurlを選択します。

上記準備が完了しましたら以下のようなテストアプレット(start.curl)を作成しますと、自動的にサーバサイドへリクエストを投げ、サーバサイドのHelloクラスのsay-helloメソッドを実行し、結果をクライアントで受け取ることができます。

{curl 8.0 applet}
{curl-file-attributes character-encoding = “shift-jis”}
{applet manifest = “manifest.mcurl”}

{import * from COM.TEST} || import

{value
def h = {Hello} || new insntace
{popup-message {h.say-hello “foo”}} || invoke method
}

上記の結果は”Hello foo”というメッセージがポップアップで出力されます。

注意
サーバサイドのCurl ORBのデフォルトURLはhttp://localhost:8080/curl-orb-serverです。変更方法は、こちらです。

補足.通信するデータにユーザ定義クラスを利用する

上記の例では通信はStringで行いましたが、String以外にも多くのデータ型をサポートします。たとえば、Javaで以下のようなPersonクラスを作成します。

package com.test;

public class Person implements java.io.Serializable {
private String name;
private int age;

public Person() {
// データクラスには引数なしのコンストラクタが必要です。
}

public Person(String name, int age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

このクラスからCurlコードを自動生成します。このクラスのコードを生成するために、コード生成ツールで”Data class”を指定します。(*サーバの再起動が必要です。)

また、JavaのHelloクラスも以下のように書き換え、コード生成ツールによってコードを再生成します。
※生成方法は、上記「2.サーバサイドのサービスクラス(POJO)からCurlコードを自動生成」参照

package com.test;

import com.curl.orb.security.RemoteService;

@RemoteService
public class Hello {

// constructor
public Hello() {

}

// methods
public String sayHello(String str) {
return “Hello ” + str;
}

public Person callPerson() {
return new Person(“hokada”, 25);
}
}

これらを利用するため、先ほど作成したCurlテストアプレットを以下のように変更します。

{curl 8.0 applet}
{curl-file-attributes character-encoding = “shift-jis”}
{applet manifest = “manifest.mcurl”}

{import * from COM.TEST} || import

{value
def h = {Hello}
def person = {h.call-person}
{popup-message person.name & ” ” & person.age}
}

実行しますと、ポップアップメッセージで”hokada 25″と表示されます。
このようにユーザ定義クラスもデータ通信クラスとして利用することができます。

(*’any’ から暗黙的キャストは禁止(または不正使用)されています。というメッセージのエラーが出る場合はこちら。)

最終的なディレクトリ・ファイル構成は以下のようになります。

orb-classes.jpg

orb-q3.jpg

似たような記事ですが、CodeZineにも掲載しております。

その他機能

各種機能については、こちらを参照ください。

コード生成ツール・マニュアル

CurlORBに付属する「コード生成ツール」の利用方法を記載します。コード生成ツールは、JavaクラスからCurlクラスを生成することができます。また、生成時に名称等々変更することや、テスト用のコードも生成することができます。

サービスクラスとデータクラス

生成できるコードについては大きく分けて2種類あります。

  • サービスクラス
  • データクラス

サービスクラスは、クライアントから呼び出すクラスで、データクラスは、クライアント-サーバ間のデータ通信で利用するDTOです。例えば、以下のような場合、クライアント(Curl)からFooというクラスのdoSomethingメソッドをPersonクラスを引数に渡して実行する場合、FooをサービスクラスPersonをデータクラスと呼びます。

// Foo
public class Foo {

public Foo() {
}

public void doSomething(Person p) {
// do something
}
}

// Person
public class Person {
private String name;
private int age;

public String getName() {return name;}
public int getAge() {return age;}
public void setName(String name) {this.name = name;}
public void setAge(int age) {this.age = age;}
}

また、サービスクラスの中にも以下のように2種類あります。

  • サービスクラス(DI)
  • サービスクラス(HttpSession)

DIのほうは、DIコンテナ(Spring framework, Seasar2など)やServletContextで管理されるオブジェクトのクラスで、HttpSessionは、ステートフルなアプリケーションを構築するためのクラスで、サーブレットのHttpSession内で管理されるオブジェクトのクラスのことです。サービスクラスのコードを生成する際、どちらかを選択します。

service-class.jpg

起動

コード生成ツールを起動するため、code-generator.dcurlを実行します。(ダブルクリック)

起動しましたら、コード生成ツールのクラスタイプ選択画面が以下のように立ち上がります。まず最初に4つのクラスタイプから1つ選択します。

  • Service Class (DI) … サービスクラス(DI)
  • Service Class (HttpSession) … サービスクラス(HttpSession)
  • Data Class … データクラス
  • Exception Class … 例外クラス

また、Service urlに入力することで、サービスのあるサーバを指定することもできます。

注意)セキュリティ設定がproduction, testのときはコード生成ツールが利用できません。詳細はこちらを参照ください。

ws000002.jpg

設定

Configurationボタンを押下しますと以下の画面が表示します。

  • Default Server url : 上記画面のServer urlのデフォルト値を指定します。
  • Base save directory : 保存先のルートディレクトリを指定できます。最終画面にて、自動的に保存先が指定されます。

WS000002-2.jpg

サービスクラス(DI)の生成

Service Class(DI)を選択しますと以下の画面が表示されます。DIコンテナ上で管理されている名前を入力するか、Browseボタンを押下し、検索します。指定したらNextボタンを押下します。

WS000003.jpg

Browseボタンを押下した場合は、以下の検索画面が表示され、Choose a class nameのテキストフィールドに対照の名前を入力します。一覧はオートコンプリートで絞り込むことができます。一覧からダブルクリックをしますと上記画面に名前がセットされます。(一覧はDIの場合はコンポーネント名、その他の場合はクラス名が表示されます。)

WS000004.jpg

対象のクラスがインターフェースをimplementsしている場合、インターフェースの一覧選択画面が表示されます。ない場合は、スキップされて、クラス詳細画面が表示されます。

WS000005.jpg

上記インターフェース選択画面でインターフェースを選択しますと、そのインターフェースと同一名称及びインターフェースのもつメソッドのみが自動生成されます。(インターフェースとして作成したくない場合は、選択しないことも可能です。)

WS000006.jpg

クラス詳細画面では、クラス情報の紹介と編集ができます。
編集可能な項目は、

  • クラス名
  • フィールド名とそのmodifier、必要不要(need?)
  • コンストラクタとそのmodifier、必要不要(不要の場合blankを指定)
  • メソッド名とそのmodifier、必要不要(need?)、非同期通信(async?)
  • コードの出力先(Class File) ※Configure画面でBase directoryを設定した場合は、自動的に出力先が設定。
  • interfaceは表示されているだけで、コードは非生成。
  • load.scurl(クラスファイルと同一ディレクトリに生成。既に存在する場合は追記されます)

※Styleボタン : CurlコーディングスタイルとJavaの名称そのままかを選択できます。Curlコーディングスタイルは、パッケージ名なら大文字、メソッド名・フィールド名なら大文字をハイフン+小文字に変換します。(例:com.test -> COM.TEST, loadFileList -> load-file-list)

*メソッドの引数・戻り値の表示 : テキストフィールドにマウスカーソルをあわせるとツールチップとして引数が表示されます。

最後にGenerateボタンを押下しますと指定した場所にCurlコードが生成されます。(基本的に生成されたコードを編集することはないはずです。)

*注意:AOPを利用する場合、サービスクラスのコードを生成するには、interfaceを作り、それを実装する必要があります。interfaceを生成したくない場合は、生成時にAOPを無効にしておく必要があります。

サービスクラス(HttpSession)の生成

サービスクラスを生成する場合、下の画面で対象のクラス名を入力します。(パッケージ名.クラス名)もしくはBrowseボタンを押下し、検索します。

ws00.jpg

Nextボタンを押下しますと以下のクラス詳細画面が表示されます。(Service Class(DI)同様、インターフェースを実装している場合は、インターフェース選択画面が表示されます。)

WS000001.jpg

画面の利用方法はサービスクラス(DI)と同様です。

データクラスの生成

データクラスを選択した場合、以下の画面が表示されます。ここで対象のクラス名を入力します。(パッケージ名.クラス名)もしくはBrowseボタンを押下し、検索します。ちなみにデータクラスはシリアル化可能である必要があります。(implements java.io.Serializable)

WS000007.jpg

Nextボタンを押下しますと、以下のクラス詳細画面が表示されます。

WS000008.jpg

サービスクラスとは違い、”get”や”is”で始まる名称のメソッド名は、getterとして, ”set”で始まる場合は、setterとしてチェックされます。もし、通常のメソッドとして生成したい場合は、チェックされているgetter/setterのチェックをはずしてください。

注意点として、もしgetterやsetterとフィールド名が重複する場合は、フィールド名がアンダーバー+フィールド名に変更されます。(例:nameフィールドとnameセッター・ゲッターを持つ場合、フィールド名は、_nameとなります。)また、コンストラクタは選択することができません。

最後にGenerateボタンを押下しますと指定した場所にCurlコードが生成されます。

例外クラスの生成

例外クラスを選択しますと以下の画面が表示されます。ここで対象のクラス名を入力します。(パッケージ名.クラス名)

WS000009.jpg

Nextボタンを押下しますと以下のようなクラス詳細画面が表示されます。

WS000010.jpg

上記画面の基本的な利用方法はデータクラスと同様です。生成されるクラスには、Exceptionを継承されます。そのため、コンストラクタは選択することはできず、{default message:String}というコンストラクタが作成されます。

テストクラスのコード生成

サービスクラスはサーバ通信を行わない空のテスト用クラスとして生成することができます。このクラスの中にテストコードを記載し、サーバを必要とすることなくクライアント単体で実装・テストが実施できます。これはサーバとクライアントを分離して開発を行いための機能です。

生成するためには、クラス詳細画面の一番下のチェックボックス”With test’s template”にチェックを入れます。そうしますと、_template_クラス名.scurlという名称のファイルも同時に作成されます。開発時はこれを利用し、テストスタブとして利用し、サーバと連携する場合は、生成したサービスクラスと切り替えます。例えば、Fooクラスの場合、_template_Foo.scurl(テスト)とFoo.scurlをload.scurlのinclude文を書き換えることできりかえれます。

{curl 8.0 package}
{package COM.TEST}
|| {include “_template_Foo.scurl”}
{include “Foo.scurl”}

クラス一覧の絞込み(Class検索画面)

一覧表示されるクラスを絞り込むことができます。これはサーバ側の設定で行います。これには以下のようにweb.xmlのcontext-paramに設定します。パラメータ名はcom.curlap.orb.generator.filterとなり、値にカンマ(,)区切りで一覧表示しないパッケージを記述することができます。

<context-param>
<param-name>com.curlap.orb.generator.filter</param-name>
<param-value>org.apache.commons.,org.springframework.,junit.</param-value>
</context-param>

注意)これはサービスクラス(DI)には適用されません。サービスクラス(DI)は、DIの登録されているもののみ一覧表示されるためです。また、java., javax., com.curlap.orb., com.curl.io.は、常に表示されません。

NotNullアノテーションによる戻り値のNot null化(0.7からサポート)

CurlではNot null化否かを「#」を用いて厳密に扱う必要があります。(例えば、#String, #Personのように)そのため、戻り値が必ずNullではない場合でもクライアント側でnullチェックをしなければなりません。これをコード生成時に、Java側で@NotNull、@DefaultNotNull、@Nullableアノテーションを利用することで、排除することが可能です。以下が例です。

Java

import com.curl.io.serialize.types.annotation.NotNull;

public class NonNullService1 {

@NotNull
public String genNonNull1() {
return “”;
}
@NotNull
public Person getNonNull2() {
return new Person(“”, 1);
}

public String genNull1() {
return “”;
}
public Person getNull2() {
return new Person(“”, 1);
}
}

————————–
import com.curl.io.serialize.types.annotation.DefaultNotNull;
import com.curl.io.serialize.types.annotation.Nullable;

@DefaultNotNull // このアノテーションはクラスに付与
public class NonNullService2 {

public String genNonNull1() {
return “”;
}
public Person getNonNull2() {
return new Person(“”, 1);
}

@Nullable
public String genNull1() {
return “”;
}
@Nullable
public Person getNull2() {
return new Person(“”, 1);
}
}

Curl

{import * from COM.CURL.ORB}

{define-class public NonNullService1 {inherits HttpSessionClient}
{constructor public {default server-url:#Url = null}
{construct-super.HttpSessionClient “tests4.NonNullService1”, server-url = server-url}
}

{method public {gen-non-null1}:String
{return {self.invoke “genNonNull1”} asa String}
}

{method public {get-non-null2}:Person
{return {self.invoke “getNonNull2”} asa Person}
}

{method public {gen-null1}:#String
{return {self.invoke “genNull1”} asa #String}
}

{method public {get-null2}:#Person
{return {self.invoke “getNull2”} asa #Person}
}
}
———————–
{import * from COM.CURL.ORB}

{define-class public NonNullService2 {inherits HttpSessionClient}
{constructor public {default server-url:#Url = null}
{construct-super.HttpSessionClient “tests4.NonNullService2”, server-url = server-url}
}

{method public {gen-non-null1}:String
{return {self.invoke “genNonNull1”} asa String}
}

{method public {get-non-null2}:Person
{return {self.invoke “getNonNull2”} asa Person}
}

{method public {gen-null1}:#String
{return {self.invoke “genNull1”} asa #String}
}

{method public {get-null2}:#Person
{return {self.invoke “getNull2”} asa #Person}
}
}

DIコンテナ(Seasar2)との連携

Curl ORBでは、DIコンテナ上で管理されているオブジェクトのメソッドをコールすることができます。今回は、各種設定及びCurlからの呼び出し方法を紹介していきます。

 

Seasar2 framework利用準備

まずは、Curl ORBとSeasar frameworkを連携するため、ここから S2Container 2.4.xの Zipファイルをダウンロード及び解凍しますと、解凍先のディレクトリ、seasar2/lib直下の4つのファイル

aopalliance-1.0.jar
javassist-3.4.ga.jar
ognl-2.6.9-patch-20070908.jar
s2-framework-2.4.29.jar

をWEB-INF/lib配下へ保存します。

を設定し、ファイルを作成します。(この例ではcom.testパッケージの中にサービスクラスが存在する場合です。もしサービスクラスのパッケージ名として別の名前を利用する場合は、ここを変更してください。)

Seasar2では通信のスコープが選択できます。

instance=”request”
instance=”session”
instance=”application”

スコープを変更したい場合はapp.diconの中の<component>タグの中に、上記のいずれかを記述してください。

(例:  <component name=”hi” class=”com.test.HiImpl” instance=”application” />

次に、web.xmlにSeasar2用のフィルタを設定します。

   <filter>
    <display-name>s2filter</display-name>
    <filter-name>s2filter</filter-name>
    <filter-class>org.seasar.framework.container.filter.S2ContainerFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>s2filter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

また、app.diconの名前、場所を任意に記述、配置した場合は、web.xmlにその情報を記述します。

例:

 <context-param>
    <param-name>configPath</param-name>
    <param-value>../2app.dicon</param-value>  *classesから見た相対パスで表現します。
 </context-param>

また、CurlORB内でSeasar2を利用するため、同様にWEB-INF/web.xmlに以下のように指定します。 

  <context-param>
    <param-name>com.curlap.orb.applicationContextClass</param-name>
    <param-value>com.curlap.orb.context.Seasar2ApplicationContext</param-value>
  </context-param>

web.xml


<web-app xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns=”http://java.sun.com/xml/ns/javaee” xmlns:web=”http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd” xsi:schemaLocation=”http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd” id=”WebApp_ID” version=”2.5″>

  <!– InvokeApplicationContextServlet –>
  <servlet>
    <servlet-name>InvokeApplicationContextServlet</servlet-name>
    <servlet-class>com.curlap.orb.servlet.InvokeApplicationContextServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>InvokeApplicationContextServlet</servlet-name>
    <url-pattern>/invoke-application-context</url-pattern>
  </servlet-mapping>

  <!– NewInstanceServlet –>
  <servlet>
    <servlet-name>NewInstanceServlet</servlet-name>
    <servlet-class>com.curlap.orb.servlet.NewInstanceServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>NewInstanceServlet</servlet-name>
    <url-pattern>/new-instance</url-pattern>
  </servlet-mapping>
 
  <!– InvokeHttpSessionServlet –>
  <servlet>
    <servlet-name>InvokeHttpSessionServlet</servlet-name>
    <servlet-class>com.curlap.orb.servlet.InvokeHttpSessionServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>InvokeHttpSessionServlet</servlet-name>
    <url-pattern>/invoke-http-session</url-pattern>
  </servlet-mapping>

  <!– DestroyInstanceServlet –>
  <servlet>
    <servlet-name>DestroyInstanceServlet</servlet-name>
    <servlet-class>com.curlap.orb.servlet.DestroyInstanceServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>DestroyInstanceServlet</servlet-name>
    <url-pattern>/destroy-instance</url-pattern>
  </servlet-mapping>
 
  <!– DefaultFilter –>
  <filter>
    <display-name>s2filter</display-name>
    <filter-name>s2filter</filter-name>
    <filter-class>org.seasar.framework.container.filter.S2ContainerFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>s2filter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <filter>
 
    <filter-name>DefaultFilter</filter-name>
    <filter-class>com.curlap.orb.servlet.DefaultInstanceManagementFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>DefaultFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  
  <!–
    Curl ORB – Environment – (since 0.6)
      default: none
        – none (none security)
        – development
        – test
        – production
  –>
  <context-param>
    <param-name>com.curlap.orb.environment</param-name>
    <param-value>development</param-value>
  </context-param>

  <!–
    Curl ORB – DI container integration – (since 0.6)
      default: com.curlap.orb.context.ServletApplicationContext
        – spring : com.curlap.orb.context.Spring2_5ApplicationContext
        – seasar2: com.curlap.orb.context.Seasar2ApplicationContext
  –>
 
  <context-param>
    <param-name>com.curlap.orb.applicationContextClass</param-name>
    <param-value>com.curlap.orb.context.Seasar2ApplicationContext</param-value>
  </context-param>

 
  <session-config>
    <session-timeout>60</session-timeout>
  </session-config>

</web-app>

サービスクラスの作成

サーバサイドのサービスクラスとして、Hi実装クラスを作成します。

// インターフェースクラス
package com.test;

public interface Hi{
 // sayHi
 public String sayHi(String name);
}

// 実装クラス
package com.test;
import com.curlap.orb.security.RemoteService;

@RemoteService
public class HiImpl implements Hi {
 // sayHi
 public String sayHi(String name) {
  return “Hi ” + name + ” (Seasar2 Framework)”;
 }
}

 

次にWEB-INF直下に、classesフォルダを作成し、その直下にapp.diconを作成し、以下のような設定を行います。

  <!DOCTYPE components PUBLIC “-//SEASAR//DTD S2Container 2.4//EN”
“http://www.seasar.org/dtd/components24.dtd”>
<components>
  <component name=”hi” class=”com.test.HiImpl” />
</components>

ここでAPサーバ(Tomcat等)を再起動します。

再起動後、コード生成ツールを利用して、以下のようなCurlのコードを生成します。ServiceClass(DI)を選択し、interface nameとしてhiを選択して生成します。(コード生成ツールの詳細な利用方法はこちらです。)

|||
||| Curl ORB for java (version 0.6)
|||  This code was generated by the Curl code generator automatically.

|||  package name   : COM.TEST
|||  generated date : 2008-12-18 15:01:52.174000
|||

{import * from COM.CURLAP.ORB}

{define-class public Hi {inherits ApplicationContextClient}
 

  {constructor public {default server-url:#Url = null}
    {construct-super.ApplicationContextClient “hi”, server-url = server-url}
  }

  {method public {say-hi v0:String}:#String
    {return {self.invoke “sayHi”, arguments = {FastArray v0}}}
  }
 
}

サービスクラスへのアクセス

生成されたコード(Hiサービスクラス)に対して、以下のようにアクセスいたします。(通常のCurlのクラスに対するアクセスと同様です。)

 

{curl 6.0 applet} || or 7.0
{curl-file-attributes character-encoding = “shift-jis”}
{applet manifest = “manifest.mcurl”,
    {compiler-directives careful? = true}
}

{import * from COM.TEST}
{value
  def h = {Hi}
  {popup-message {h.say-hi “akira”}}
}

これにより、Curl側のsay-hiメソッドをコールしますと、サーバサイドのDIコンテナ(Seasar2)で管理されているHiImplオブジェクトを呼び出し、say-hiメソッドを実行し、戻り値をCurlへ返します。(このサンプルでは、”Hello akira (Seasar2 Framework)”と表示されます。)

このように、簡単にサーバサイドとの連携を行うことができます。

 

DIコンテナ(Spring framework)との連携

Curl ORBでは、DIコンテナ上で管理されているオブジェクトのメソッドをコールすることができます。今回は、各種設定及びCurlからの呼び出し方法を紹介していきます。

 

Spring framework利用準備

まずは、Curl ORBとSpring frameworkを連携するため、ここからZipファイルをダウンロード及び解凍しますと、spring.jarというファイルが含まれますので、これをWEB-INF/lib配下へ保存します。

【前提】
Spring2.5

次にapplicationContext.xmlに以下のような<context:component-scan base-package=”samples”/>を設定し、ファイルを作成します。(この例ではsamplesパッケージの中にサービスクラスが存在する場合です。もしサービスクラスのパッケージ名として別の名前を利用する場合は、ここを変更してください。)このファイルをWEB-INF/applicationContext.xmlに保存します。 


<beans xmlns=”http://www.springframework.org/schema/beans
        xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
        xmlns:p=”http://www.springframework.org/schema/p
        xmlns:aop=”http://www.springframework.org/schema/aop
        xmlns:context=”http://www.springframework.org/schema/context
        xmlns:jee=”http://www.springframework.org/schema/jee
        xmlns:tx=”http://www.springframework.org/schema/tx
        xsi:schemaLocation=”
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-2.5.xsd
            http://www.springframework.org/schema/jee
            http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx-2.5.xsd“>

  <context:component-scan base-package=”samples”/>

</beans>

次にWEB-INF/web.xmlにSpring用のリスナーを追加します。

   <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

また、CurlORB内でSpringを利用するため、同様にWEB-INF/web.xmlに以下のように指定します。 

  <context-param>
    <param-name>com.curlap.orb.applicationContextClass</param-name>
    <param-value>com.curlap.orb.context.Spring2_5ApplicationContext</param-value>
  </context-param>

これで、Curl ORBとspringを連携する事前設定は完了しましたので、実際にSpringで管理されているクラスの利用方法を以下に記載します。

サービスクラスの作成

サーバサイドのサービスクラスとして、HelloインターフェースとHelloImpl実装クラスを作成します。HelloImplクラスを作成する場合、サービスクラスとして定義するため、Serviceアノテーションを指定します。(これによりapplicationContext.xmlにbeanタグを記載する必要がなくなります。) ※RemoteServiceアノテーションについての詳細は、こちらを参照ください。

// インターフェース(Java)
package samples;

public interface Hello {
 // sayHello
  public String sayHello(String name);
}

 

// 実装クラス(Java)
package samples;

import com.curlap.orb.security.RemoteService;
import org.springframework.stereotype.Service;

@RemoteService
@Service(“hello“)
public class HelloImpl implements Hello {
 // sayHello
 public String sayHello(String name) {
  return “Hello ” + name + ” (Spring Framework)”;
 }
}

ここでAPサーバ(Tomcat等)を再起動します。

再起動後、コード生成ツールを利用して、以下のようなCurlのコードを生成します。ServiceClass(DI)を選択し、interface nameとしてHelloを選択して生成します。(コード生成ツールの詳細な利用方法はこちらです。)

{import * from COM.CURLAP.ORB}

{define-class public Hello {inherits ApplicationContextClient}

   {constructor public {default}
    {construct-super.ApplicationContextClient “hello”}
  }

  {method public {say-hello v0:String}:#String
    {return {self.invoke “sayHello”, arguments = {FastArray v0}}}
  }
}

サービスクラスへのアクセス

生成されたコード(Helloサービスクラス)に対して、以下のようにアクセスいたします。(通常のCurlのクラスに対するアクセスと同様です。)

{import * from SAMPLES}

{value
  || new
  def hello = {Hello}
  || invoke method
  {popup-message {hello.say-hello “Hitoshi Okada”}}
}

これにより、Curl側のsay-helloメソッドをコールしますと、サーバサイドのDIコンテナ(spring)で管理されているHelloオブジェクトを呼び出し、sayHelloメソッドを実行し、戻り値をCurlへ返します。(このサンプルでは、”Hello Hitoshi Okada (Spring Framework)”と表示されます。)

このように、簡単にサーバサイドとの連携を行うことができます。

また、下記サイトにSpring Frameworkとの連携を詳細に記述した記事を掲載しております。

第1回 サンプルアプリケーションを動かしてみよう

第2回 デモ・アプリケーション開発

第3回 ユーザ認証とアクセス制御

 

関連ページ

Spring Framework

@IT

 

インターセプターの利用

インターセプターとは

インターセプターを用いることで、リクエスト時のHTTPリクエストヘッダーやHTTPレスポンスヘッダーに追加したり、メソッド実行時の前と後、例外発生後などに、クラスやメソッドの中身を修正することなく任意の処理を埋め込むことができます。これはspring frameworkやseasar2などで有名な、AOP(Aspect Oriented Program) のようなものです。

例えば、メソッド実行時にログ出力を行ったり、キャッシングを行ったりすることが可能となります。

インターセプターの利用方法

インターセプターを利用するには、ClientInterceptorクラスを継承して、新たなインターセプターを作成します。下記サンプルに従って説明していきます。

下記サンプルはコンソールにログを出力するもの(TraceInterceptor)です。以下のようにClientInterceptorを継承し、各メソッドをオーバーライドし、新たなインターセプターを作成します。

{import * from COM.CURL.ORB}

|| Traceインターセプター
{define-class public TraceInterceptor
{inherits ClientInterceptor}

{constructor public {default
client-filter:{proc-type {AbstractClient}:bool} =
{fn client => true}
}
{construct-super client-filter = client-filter}
}

{method protected open {register-interceptor
client:AbstractClient
}:void
{super.register-interceptor client}
}

{method protected open {build-server-url
server-url:Url
}:Url
{self.print “url is ” & server-url.full-filename}
{return {super.build-server-url server-url}}
}

{method protected open {build-orb-request-headers
headers:#HashTable
}:#HashTable
{if-non-null hs = headers then
{for v key k in hs do
{self.print k & ” ” & v}
}
}
{return {super.build-orb-request-headers headers}}
}

{method protected open {build-http-request-headers
headers:#HttpRequestHeaders
}:#HttpRequestHeaders
{if-non-null hs = headers then
{for v key k in hs do
{self.print ” ” & k & ” ” & v}
}
}
{return {HttpRequestHeaders “Content-Encoding”, “gzip”}}
}

{method protected open {handle-http-response-headers
headers:#HttpResponseHeaders
}:void
{if-non-null hs = headers then
{for v key k in hs do
{self.print ” ” & k & ” ” & v}
}
}
}

{method protected open {handle-before-request ||before-advice
method-name:String,
arguments:#FastArray
}:void
{self.print “before invoking ” & method-name}
}

{method protected open {handle-after-response ||after-returning-advice
method-name:String,
arguments:#FastArray,
return-value:#any
}:void
{self.print “after invoking ” & method-name & “, get ” & return-value}
}

{method protected open {handle-exception ||throw-advice
method-name:String,
arguments:#FastArray,
exception:Exception
}:void
{self.print “after throwing ” & exception}
}

|| — private —
{method private {print str:String}:void
{output “[TraceInterceptor] ” & str}
}
}

以下は各メソッドの説明です。

  • register-interceptor :Interceptor登録時の処理を定義できます。
  • build-server-url :サーバのURL定義する際の処理を記述できます。
  • build-orb-request-header :ORB独自リクエストヘッダーへ定義する際の処理を記述できます。(送信した情報はServletFilter内で取得InstanceManagementUtil.getRequestメソッドでInstanceManagementRequestオブジェクトを取得し、そのInstanceManagementRequest.getHeaderでヘッダー情報を取得できます。(Mapオブジェクトとして取得)
  • build-http-request-header :HTTPリクエストヘッダーへ定義する際の処理を記述できます。
  • handle-http-response-header :HTTPレスポンスヘッダーの定義を利用する際の処理を記述できます。
  • handle-before-request :メソッド実行前の処理を定義できます。
  • handle-after-response :メソッド実行後の処理を定義できます。
  • handle-exception :例外発生時の処理を定義できます。

インターセプターの登録はregisterクラスプロシージャで可能です。各サービスクラスには、インスタンスが生成された際にインターセプターが付与されます。そのため、インスタンス生成時より以前にregisterする必要があります。

{ClientInterceptor.register
|| client-filterはInterceptorをセットするクラスをフィルタリングできます。
{TraceInterceptor client-filter = {fn c => (c isa Hoge)}}
}

セキュリティ設定

Curl ORBは、クライアントからアクセスできるサービスクラスを制限するすることができます。これには、サーバのweb.xmlの設定と@RemoteServiceアノテーションで制限できます。(WEB-INF/web.xml)

まず、アプリケーションの環境として、以下のようにweb.xmlのcontext-paramにnone, development, test, productionを設定します。

  <context-param>
    <param-name>com.curlap.orb.environment</param-name>
    <param-value>development</param-value>
  </context-param>

次に公開したいサービスクラスに@RemoteServiceアノテーション(com.curlap.orb.securityパッケージ)を指定します。@RemoteServiceアノテーションの引数には、列挙型であるEnvironment(com.curlap.orb.securityパッケージ)を指定します。Environmentには、DEVELOPMENT, TEST, PRODUCTIONを指定できます。サンプルを以下に記載します。

@RemoteService(Environment.DEVELOPMENT)
public class Foo {

  // ….

}

この@RemoteService(Environment.DEVELOPMENT)の意味はweb.xmlに指定した環境がdevelopementの際、クライアントからアクセス可能という意味です。またこの例の場合、環境がtest, productionの場合はアクセスできないという意味となります。また、もう一つの例をあげますと、@RemoteService(Environment.PRODUCTION)を指定した場合は、環境がdevelopment, test, productionどれでもクライアントからアクセスできます。これを以下の表にまとめました。

アプリケーション環境 説明 アクセス可能なサービスの@RemoteServiceに指定するEnvironment
none 非セキュリティ設定 すべてアクセス可能(@RemoteServiceアノテーションも不要)
development 開発環境用 Environment.DEVELOPMENT, Environment.TEST, Environment.PRODUCTION
test テスト環境用 Environment.TEST, Environment.PRODUCTION
production 本番環境用 Environment.PRODUCTION

 注意)none以外は@RemoteServiceアノテーションが必要です。
 注意)@RemoteServiceのように引数を省略した場合は、@RemoteService(Environment.PRODUCTION)と同等になります。

ちなみに、コード生成ツールはdevelopment環境のみ利用可能です。

 

いろいろなデータ型のサポート

Curl ORBのデータ通信には以下のデータ型を利用することができます。(要はサービスクラスのコンストラクタやメソッドの引数及び戻り値、フィールドのデータクラスとして利用できる方です。)

Curl Java
int int
int8 byte
int16 short
int32 int
int64 long
float float
double double
bool boolean
char char
String java.lang.String
DateTime java.util.Date
FastArray-of データ型 配列
Array (Array-of any) List, ArrayList
HashTable (HashTable-of any) Map, HashMap
ByteArray com.curl.io.serialize.types.ByteArray
COM.CURL.ORB.TYPE.SerializableRecordSet
COM.CURL.ORB.TYPE.SerializableRecordField
COM.CURL.ORB.TYPE.SerializableRecordData(0.7以上でサポート)
com.curl.orb.type.SerializableRecordSet
com.curl.orb.type.SerializableRecordField
com.curl.orb.type.SerializableRecordData
ユーザ定義型(フィールドは上記のものに限る) ユーザ定義型(フィールドは上記のものに限る)

バージョン0.6から以下のデータ型もサポートされました。

Curl Java
COM.CURL.ORB.TYPE.BigInteger java.math.BigInteger
COM.CURL.ORB.TYPE.BigDecimal java.math.BigDecimal
COM.CURL.ORB.TYPE.Date java.util.Date
COM.CURL.ORB.TYPE.CDate java.sql.Date
COM.CURL.ORB.TYPE.CTime java.sql.Time
COM.CURL.ORB.TYPE.CTimestamp java.sql.Timestamp
COM.CURL.ORB.TYPE.Blob java.sql.Blob
COM.CURL.ORB.TYPE.Clob java.sql.Clob

注意) サーバからのレスポンスとして受け取る場合(戻り値)は、すべてNull許容の型となる。(例、#String, #Foo)

また、Curlのユーザ定義型をJavaのクラスから生成する場合は、”Data Class”としてコード生成ツールから生成します。

さらにバージョン0.8からValueクラスDecimal型 (Curl8.0のみ)もサポートされました。

注意) Valueクラスを利用する際は、Javaクラスに@ValueClassアノテーションを付与する必要があります。

レコードセットのサンプル

以下のようにサーバ側でレコードセットを作成し、クライアントへ返すことができます。

Java

// 0.6 の場合
public SerializableRecordSet createRecordSet() {
SerializableRecordSet records =
new SerializableRecordSet(
new SerializableRecordField[]{
new SerializableRecordField(“name”, String.class),
new SerializableRecordField(“age”, int.class),
new SerializableRecordField(“money”, double.class),
new SerializableRecordField(“date”, DateTime.class)});
records.addRecord(new Object[]{“hokada”, 32, 10.1, new DateTime()});
records.addRecord(new Object[]{“amori”, 27, 20000.01, new DateTime()});
records.addRecord(new Object[]{“tyamamoto”, 30, 0.0001, new DateTime()});
records.addRecord(new Object[]{“foo”, 20, 2.2, new DateTime()});
return records;

}

// 0.7の場合
public SerializableRecordSet createRecordSet() {
SerializableRecordSet records = new SerializableRecordSet(
new SerializableRecordField[]{
new SerializableRecordField(“name”, String.class),
new SerializableRecordField(“age”, int.class),
new SerializableRecordField(“money”, double.class),
new SerializableRecordField(“dt”, DateTime.class),
new SerializableRecordField(“ts”, CTimestamp.class),
new SerializableRecordField(“bigint”, com.curlap.orb.type.BigInteger.class)
}
);
records.addRecord(
new SerializableRecordData(
new String[]{“name”, “age”, “money”, “dt”, “ts”, “bigint”},
new Object[]{“hokada”, 32, 10.1, new DateTime(), new Timestamp(0), new BigInteger(“100”)}
)
);
records.addRecord(
new SerializableRecordData(
new String[]{“name”, “age”, “money”, “dt”, “ts”, “bigint”},
new Object[]{“amori”, 27, 20000.01, new DateTime(), new Timestamp(0), new BigInteger(“200”)})
);
records.addRecord(
new SerializableRecordData(
new String[]{“name”, “age”, “money”, “dt”, “ts”, “bigint”},
new Object[]{“tyamamoto”, 30, 0.0001, new DateTime(), new Timestamp(0), new BigInteger(“300”)})
);
records.addRecord(
new SerializableRecordData(
new String[]{“name”, “age”, “money”, “dt”, “ts”, “bigint”},
new Object[]{“foo”, 20, 2.2, new DateTime(), new Timestamp(0), new BigInteger(“400”)})
);
return records
}

Curl

{method public {create-record-set}:#SerializableRecordSet
{return {self.invoke “createRecordSet”}}
}

|| 利用例
{RecordGrid record-source = {foo.create-record-set}}

BigInteger、BigDecimalのサンプル

Java

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;

public class TestTypes {

public BigInteger echoBigInteger(BigInteger bigInteger) {
return bigInteger;
}

public BigDecimal echoBigDecimal(BigDecimal bigDecimal) {
return bigDecimal;
}

public Date echoDate(Date sqlDate) {
return sqlDate;
}

public Time echoTime(Time sqlTime) {
return sqlTime;
}

public Timestamp echoTimestamp(Timestamp sqlTimestamp) {
return sqlTimestamp;
}

public Blob echoBlob(Blob blob) {
return blob;
}

public Clob echoClob(Clob clob) {
return clob;
}
}

Curl

{define-class public TestTypes {inherits ApplicationContextClient}

|| これは生成されたコード
[…] 

{method public {echo-date v0:CDate}:#CDate
{return {self.invoke “echoDate”, arguments = {FastArray v0}}}
}

{method public {echo-complex-type v0:ComplexTypeDto}:#ComplexTypeDto
{return {self.invoke “echoComplexType”, arguments = {FastArray v0}}}
}

{method public {echo-big-integer v0:BigInteger}:#BigInteger
{return {self.invoke “echoBigInteger”, arguments = {FastArray v0}}}
}

{method public {echo-big-decimal v0:BigDecimal}:#BigDecimal
{return {self.invoke “echoBigDecimal”, arguments = {FastArray v0}}}
}

{method public {echo-time v0:CTime}:#CTime
{return {self.invoke “echoTime”, arguments = {FastArray v0}}}
}

{method public {echo-timestamp v0:CTimestamp}:#CTimestamp
{return {self.invoke “echoTimestamp”, arguments = {FastArray v0}}}
}

{method public {echo-blob v0:Blob}:#Blob
{return {self.invoke “echoBlob”, arguments = {FastArray v0}}}
}

{method public {echo-clob v0:Clob}:#Clob
{return {self.invoke “echoClob”, arguments = {FastArray v0}}}
}
}

|| 以下のように利用

{import * from COM.CURL.ORB}

|| from-int64, from-int, from-String, from-doubleファクトリでBigIntegerのインスタンス生成可能
|| add(+), subtract(-), multiple(*), divide(/), to-int, to-int64, to-Stringというメソッドなどで操作可能
def big-integer:BigInteger = {ct.echo-big-integer {BigInteger.from-int 123}}

|| from-int64, from-int, from-String, from-doubleファクトリでBigDecimalのインスタンス生成可能
|| add(+), subtract(-), multiple(*), divide(/), to-int, to-int64, to-Stringというメソッドなどで操作可能

def big-decimal:BigDecimal = {ct.echo-big-decimal {BigDecimal.from-double 123.10}}

def date:CDate = {ct.echo-date {CDate}}

def time:CTime = {ct.echo-time {CTime 20000}}

def timestamp:CTimestamp = {ct.echo-timestamp {CTimestamp 40000}}

def blob:Blob = {ct.echo-blob {Blob {{Array-of byte} ‘a’, ‘b’, ‘c’}}

def clob:Clob = {ct.echo-clob {Clob {{Array-of char} ‘a’, ‘b’, ‘c’}}}

*各クラスは、基本的にJavaのAPIと同等のメソッドを持っています。

Exceptionハンドリングとバインディング

Curl ORBは、サーバサイドで発生したExceptionを、クライアントサイドでcatchすることができます。また、サーバサイドで定義したExceptionをクライアントの任意のExceptionにバインディングすることができます。

Exceptionハンドリング

通常サーバサイドにてExceptionが発生した場合、クライアントサイドではCOM.CURLAP.ORB.SERVLET.ORBServerExceptionというExceptionとしてcatchすることができます。サーバサイドにて発生したExceptionクラス名を取得するには、このORBServerExceptionのexception-content.exception-nameで取得できます。また、メッセージはexception-content.messageで取得できます。

{try

    || ここにORBを使ったサーバサイド連携のコード

 catch e:ORBServerException do
    || サーバサイドのException名
    {output “exception name” & e.exception-content.exception-name}
    || パッケージ名が大文字での出力(Curlのコーディングスタイル)
    {output “exception name for curl” & e.exception-content.exception-name-as-curl-style
    || メッセージ
    {output “message” & e.exception-content.message}
    || javaのprintStackTrace()のようなもの
    {e.print-stack-trace}
}

また、サーバ通信に関係ない場合に発生するExceptionはORBClientExceptionとなります。

Exceptionバインディング

サーバサイドにて発生したExceptionに対して、クライアントサイドのExceptionにマッピングすることができます。例えば、サーバサイドのtest.SVExceptionをTEST.CLExceptionにマッピングすることができます。マッピングしますとクライアントサイドでは、TEST.CLExceptionをcatchできるようになります。このマッピングにはbind-exceptionプロシージャを利用します。

{import * from TEST}

|| arg1:java exception (String)
|| arg2:Curl exception (ClassType)

{bind-exception “test.SVException”, CLException}

|| 複数登録可能
{bind-exception “test.SVException1”, CLException1}
{bind-exception “test.SVException2”, CLException2}

|| 同一のCLExceptionにまとめることも可能
{bind-exception “test.SVExceptionXX”, CLException}

{try

   || サーバサイドでtest.SVExceptionが発生する可能性のあるコード

 catch e:CLException do
    {dump e.message}
}

サービスクラスの利用方法

はじめに

サービスクラスについての説明は、こちらを参照ください。

サービスクラス(HttpSession)

サービスクラス(HttpSession)はステートフルなアプリケーションを構築するためのクラスで、サーブレット上のHttpSession上に生成されます。生成されたコードのコンストラクタをnewした時点でHttpSession上に作成されます。また、メソッドをコールすることで、その生成されたオブジェクトのメソッドを実行します。

HttpSession上からクリアするには、生成されたクラスのdestroy-instanceメソッドを実行します。これを実行しないとタイムアウトになるまで、HttpSession上に残ってしまうので注意してください。またdestroy-instanceを実行する際にHttpSession自体をクリアすることができます。これには、destroy-instanceのkill-session? = trueを指定してください。(kill-session?はバージョン0.6からの機能です。)(以下のコードを参考)

def foo1 = {Foo} || これはサービスクラス(HttpSession)とします。
{foo1.say-hello}
{foo1.destroy-instance}

def foo2 = {Foo} || これはサービスクラス(HttpSession)とします。
{foo2.say-hello}
{foo2.destroy-instance kill-session? = true} || Sessionもクリアします。

また、サービスクラス(HttpSession)のコンストラクタやメソッドの引数に、サーバ上で既に生成されたサービスクラス(HttpSession)を指定することができます。(以下のコードを参考)

|| Fooはサービスクラス(HttpSession)とします。
def foo = {Foo}
|| Hogeはサービスクラス(HttpSession)とします。引数にサービスクラス(HttpSession)Fooを指定。
def Hoge = {Hoge foo}
{hoge.say-good-bye}

{hoge.destroy-instance}
{foo.destroy-instance}

注意)現段階では引数のサービスクラス(HttpSession)は、配列やクラスのフィールドとして扱うことはできません。

サービスクラス(DI)

サービスクラス(DI)は、DIコンテナ上(Spring frameworkやSeasar2など)で管理されているオブジェクトのメソッドをコールするために利用されます。そのため、スコープもDIのほうで管理されているため、クライアントでコンストラクタをnewしても、サーバ側に何もアクションは行いません。また、サービスクラス(HttpSession)のようにdestroy-instanceも用意されておりません。

 

Apache jmeterを使った性能テスト

Curl ORB for Javaの性能がどの程度のものであるか、 jmeterを使ってテストしてみましょう。
Curl ORB for Curl 0.6には、性能テストを行うためのライブラリが用意してあります。

Curl ORB for Curlの中のパッケージ、 com.curlap.orb.client を使ってテストを行います。

Curl ORB for Javaはこちらから最新版をダウンロードしてください。

テストケースを作成する為に必要なモジュール

1.下記のパッケージを含むjarファイル。これらのパッケージはダウンロードした中の、curl-orb_0.6_beta_bin\java\client\libの中に入っています。

このjarファイルの中には、
・com.curlap.orb.client
・com.curlap.orb.common
・com.curlap.orb.io
・com.curlap.orb.type   の4つのパッケージが含まれています。

2.curl-serializer.jar(curl-orb_0.6_beta_bin\java\web\WEB-INF\libの直下にあります。)
3.ApacheJMeter_core.jar(JMeter内のライブラリ)
4.ApacheJMeter_java.jar(JMeter内のライブラリ)
5.junit3.8.2.jar(JMeter内のライブラリ)

Apache JMeterは事前にダウンロードを行っておいてください。(Apache JMeterのダウンロードはこちら)

テストケースの作成

それでは、クライアント側から、サーバ側のサービスを呼び出すクラスを作成していきましょう。

まず、Eclipseを開き、[File]-[New]-[Java Project] を選択します。今回、プロジェクト名はjmeter-testという名前にします。(JREのバージョンは、1.5に設定します。)

次に、プロジェクト内にフォルダを作り(今回はlibという名前にしました)、そこに
・curl-orb-client.jar(先ほど作成したjar)
・ApacheJMeter_core.jar
・ApacheJMeter_java.jar
・junit3.8.2.jar

を追加します。

追加したら、プロジェクトを右クリックし、コンテキストメニューから[Properties]-[Java Build Path]から[Add JARs]を選択し、先ほどlibに追加した3つのjarファイルを追加します。

(結果のイメージ)

jm2.jpg

まずは、簡単なテストケースを作成してみましょう。

プロジェクトを右クリックし、コンテキストメニューから、[New]-[Package] を選択し、testという名前のパッケージを作成します。そのtestパッケージを右クリック、コンテキストメニューから、[New]-[Class] を選択します。名前をTestSamplerとし、superclassにはAbstractJavaSamplerClientを指定します。

jm3.jpg

作成されたクラスを選択してみますと、中には runTest というメソッドが一つ作成されています。

Apache JMeterでは、このrunTestの中身が実行されます。

それではこの中に、テストケースを書きます。

まずは、クイックスタートの最初に作成したHelloクラスのsayHelloメソッドを呼び出すテストを作成します。

ちなみに、呼び出すクラスは下記のようなクラスです。

package com.test;

import com.curlap.orb.security.RemoteService;

@RemoteService
public class Hello {

  // constructor
  public Hello() {
  }

  // methods
  public String sayHello(String str) {
    return “Hello ” + str;
  }
}

TestSampler.java

package test;

import junit.framework.Assert;

import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;

import com.curlap.orb.client.HttpSessionClient;
import com.curlap.orb.client.ORBClientException;

public class TestSampler extends AbstractJavaSamplerClient {

public SampleResult runTest(JavaSamplerContext arg0) {
try {
HttpSessionClient orb = new HttpSessionClient(“com.test.Hello”, new Object[]{});
// args = methodName, args
Assert.assertEquals(“Hello invokeMethod1”, orb.invokeMethod(“sayHello”, new Object[]{“invokeMethod1”}));
orb.destroy();

System.out.println(“test finish”);
}catch (ORBClientException e) {
e.printStackTrace();
}catch (Exception e) {
e.printStackTrace();
}
return null;
}

}

Apache JMeterへのテストケース追加

TestSampler.javaを作成しましたら、このテストケースをApache JMeterへ追加します。

コンテキストメニューから[Export]-[JAR file]を選択します。テストケースのみExportしたいので、testパッケージのみ選択した状態でExportします。今回名前はorb-test.jarとしました。

jm4.jpg

次に、テストケースとテストに必要なモジュールを JMeterの lib\ext直下 にに追加していきます。

テストに(JMeterの lib\ext直下に)必要なモジュール
・curl-orb-client
・curl-serializer.jar

テストに必要なモジュールは、一度追加するだけでOKです。

では、実際にApache JMeterを立ち上げてテストを行いましょう。

Apache JMeterでのテスト

JMeterの bin フォルダの直下の jmeter.batをクリックしJMeterを立ち上げます。

テストケースを右クリック、コンテキストメニューから、[追加]-[スレッドグループ]

スレッドグループを右クリック、コンテキストメニューから、[追加]-[サンプラー]-[Javaリクエスト]を選択します。

jm5.jpg

あとは、このテストケースを保存し、実行します。

*サーバ側で、curl-orb-server.warという名前でorb-serverのwarファイルが展開されており、Tomcatが起動しているか確認して下さい。

無事に動いていれば、test finishの文字がJMeterのコンソールに表示されます。