「オープンソース – Curl ORB for Java」カテゴリーアーカイブ

CurlORB 0.9 リリースノート

orb.png

Curl ORB for javaとは

Curl ORB for javaとは、CurlとJavaをシームレスに結合し、高速なデータ通信を実現するためのツールです。Curl ORBを利用することで、CurlアプリケーションからPOJO(Plain Old Java Object)で作成されたjavaオブジェクトのメソッドをコールし、戻り値をCurlアプリケーションで受け取ることができます。また、サーバサイドのjavaクラスからCurlのソースコードを自動生成することも可能です。このツールを用いれば、Curlとサーバサイドjavaとの連携を利用したシステム開発が容易になります。Curl ORB for javaはオープンソースプロジェクト(Apache License2.0)として公開されています。

orb.jpg

(上図説明)
コード自動生成ツールにてJavaのクラスからCurlコードを自動生成します。(CORBAなどのIDLは不要で、その代わりにCurlのスタブクラスを生成。)クライアントサイドでは、自動生成されたCurlクラス(サービスクラス)を実行しますと、自動的にサーバサイドのサービスクラスをコールし、処理を実施して結果をクライアントへ返します。 またこの際、Spring frameworkやSeasar2などのDIコンテナで管理されているJavaオブジェクトに対してもコールすることが可能となっています。

CurlORB for javaバージョン0.9 新機能

  • モバイル開発環境「Caede」のサポート (参考ページ)
  • 【注意点】CurlRTE 6.0, 7.0は未サポート(バージョン0.8をご利用ください)
  • その他、バグフィックス …など

CurlORB for javaバージョン0.8 新機能

  • CurlRTE8.0対応(6.0, 7.0も対応)
  • Valueクラスのサポート
  • Decimal型のサポート(Curl8.0以上)
  • クライアントキャッシュ機能
  • 【注意点】 パッケージ名の変更(COM.CURLAP.ORB → COM.CURL.ORB)
  • その他、バグフィックス …など

CurlORB for javaバージョン0.7 新機能

  • CurlRTE7.0対応(6.0も対応)
  • サーバプッシュ・インターオペラビリティ(Cometフレームワーク Atmosphere などとの連携)
  • チューニングパラメータ(@DoNotShareアノテーション) (参考ページ
  • NotNull機能(@NotNull, @DefaultNotNull, @Nullableアノテーション) (参考ページ)
  • サロゲートペア対応
  • SerializableなRecordDataサポート(参考ページ
  • その他、バグフィックス …など

CurlORB for javaバージョン0.6 新機能

  • 追加されたデータ型として、java.math.BigInteger, java.math.BigDecimal, java.sql.Date, java.sql.Timestamp, java.sql.Time, java.sql.Blob, java.sql.Clobを対応 (参考ページ
  • Apache Jmeterなど負荷試験用のORBクライアント (参考ページ
  • 新しいセキュリティ設定 (参考ページ
  • データ通信の圧縮・解凍参考ページ
  • クライアント・インターセプター(AOPのような) (参考ページ
  • コード生成ツールのユーザビリティ向上(クラスの一覧検索、デフォルト値の設定など) (参考ページ
  • サービスクラス機能追加(引数にリモートのクラスを指定可能、セッションKILLなど) (参考ページ)
  • サービスオブジェクトのコンテナ管理 (参照ページ
  • その他、各種名称変更及びバグフィックス、パフォーマンス向上 …など

CurlORB for javaバージョン0.5までの機能

  • CurlからPOJOで作成されたサービスクラスをコール(ステートフル、ステートレス)
  • 高速なデータ通信(バイナリデータを使って通信します。)
  • コード生成ツール
  • 各種データ型(プリミティブ型、String、配列、List、Map、ユーザ定義クラス、RecordSetなど)を対応
  • 非同期同期通信
  • 例外ハンドリング(サーバ例外をクライアントでCatchできます。) …など

モバイル開発環境「Caede」のサポートについて

バージョン0.9からモバイル開発環境「Caede」でもORBの機能を利用できるようになりました。

以下にCaedeでの利用方法、サポートしているデータ型、制限事項を記載します。

なおCaede バージョン3.0.0で利用する場合、別途注意事項があります。こちらのページを参照してください。

Caedeでの利用方法

  • SorceForgeからcurl-orb-V0.9.zipをダウンロードします。
  • Eclipse開発環境へCurl ORBをセットアップし、以下の手順でCaedeとJavaを連携するアプリケーションを構築します。以下の手順の詳細についてはCurl ORB for Javaのクイックスタートを参照してください。
    1. サーバサイドのサービスクラス(POJO)作成
    2. サーバサイドのサービスクラス(POJO)からCurlコードを自動生成
  • 新しいCaedeプロジェクトを作成します。Caedeプロジェクトの作成の詳細はデベロッパーセンターのCaedeのドキュメントを参照してください。
  • CaedeプロジェクトにCurl ORBクライアントを取り込むため、ダウンロードしたCurl ORBディレクトリのcurl/COM.CURL.ORB-V0.9/8.0/manifest.mcurlをデリゲート先として選択します。
  • Caedeプロジェクトのmanifest.mcurlにダウンロードしたCurl ORBディレクトリのcurl/COM.CURL.ORB.CAEDE-V0.9/8.0/COM.CURL.ORB.CAEDE/load.pcurlを追加します。
    (以下はC:/curl-orb-V0.9にダウンロードした場合の例です)
    {component package COM.CURL.ORB.CAEDE,     location = "C:/curl-orb-V0.9/curl/COM.CURL.ORB.CAEDE-V0.9/8.0/COM.CURL.ORB.CAEDE/load.pcurl" }
  • Caedeプロジェクトにクライアントコードを記述します。
  • あとは通常のCaedeプロジェクトと同じようにCaedeアプリケーションに変換します。

サポートしているデータ型

Caede 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
FastArray-of データ型 配列
Array (Array-of any) List, ArrayList
HashTable (HashTable-of any) Map, HashMap
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.BigInteger java.math.BigInteger
COM.CURL.ORB.TYPE.BigDecimal java.math.BigDecimal
ユーザ定義型(フィールドは上記のものに限る) ユーザ定義型(フィールドは上記のものに限る)

CaedeORBでは以下の変換はサポートしていません。

Curl Java
DateTime java.util.Date
ByteArray com.curl.io.serialize.types.ByteArray
COM.CURL.ORB.TYPE.SerializableRecordSet com.curl.orb.type.SerializableRecordSet
COM.CURL.ORB.TYPE.SerializableRecordField com.curl.orb.type.SerializableRecordField
COM.CURL.ORB.TYPE.SerializableRecordData com.curl.orb.type.SerializableRecordData
COM.CURL.ORB.TYPE.Blob java.sql.Blob
COM.CURL.ORB.TYPE.Clob java.sql.Clob

またValueクラス、Decimal型もサポートしていません。

利用できない機能

Caede側の制限により、以下の機能は現在利用できません。

  • get-jsessionid-in-cookies/clear-jsessionid-in-cookies
  • Exceptionバインディング(bind-exception/bind-exceptions/get-exception/get-exceptions/remove-exception/clear-exceptions)
  • クライアントキャッシュ
  • クライアント・インターセプター
  • データ通信の圧縮・解凍
  • ヘッダー情報の送信
  • サービスクラスをクライアントでコンテナ管理する機能
  • パフォーマンス改善アノテーション(@DoNotShare)
  • NotNull機能(@NotNull, @DefaultNotNull, @Nullableアノテーション)
  • transient属性のフィールドを含むユーザ定義型クラス

Caede バージョン3.0.0でCurl ORB for Java 0.9を利用する場合の注意事項

Caede バージョン3.0.0でCurl ORB for Java 0.9を利用する場合は、最初に1回だけ事前準備の作業 が必要です。
こちらに記載された手順を実行する前に以下の作業を行ってください。

  • Caede SDKをインストールしたフォルダの下にある以下のファイルを退避した後、ダウンロードしたCurl ORBディレクトリに含まれているCOM.CURL.CAEDE.JSON-ORB.jsをコピーしてください。

    libcommonjscaede-libCOM.CURL.CAEDE.JSON-ORB.js


  • すでにCOM.CURL.CAEDEライブラリがインストール済みのライブラリに含まれている場合は、再度ライブラリのインストールを行ってください。

※元のファイルは必ず退避して保存してください。元の環境に戻す場合は退避したファイルを元に戻してください。

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のコンソールに表示されます。

Curl ORB性能検証ライブラリ

Curl ORB for Curl 0.6には、性能テストを行うためのライブラリが追加されています。

Curl ORB for Curlの中のパッケージ、 com.curlap.orb.clientがそれに該当します。

ここでは、パッケージの中の各クラスの概要についてご説明いたします。メソッド、コンストラクタ等はアクセス修飾詞がパッケージ、パブリックのみご紹介しています。

詳細につきましては、javadocをご参照ください。

クラスの紹介(概要)

ClientUtil
ORBへのリクエスト/レスポンスのインターフェースです。内部的にこのクラスを通じてHTTP通信を行います。

HTTPSessionClient
セッション単位でのORB呼び出し用のクラスです。

ApplicationContextClient
Spring等のDIコンテナとの連携用のクラスです。

ORBClientException
クライアント側の例外をハンドリングするクラスです。

ORBServerException
サーバ側の例外をハンドリングするクラスです。

ORBDefaultServerUrl
デフォルトのORB呼び出しのためのURLが記述されています。

デフォルトのORB用URL     :DEFAULT_SERVER_URL = “http://localhost:8080/curl-orb-server”
インスタンス作成用コンテキスト :NEW_INSTANCE_CONTEXT_NAME = “/new-instance”
メソッド呼び出し用コンテキスト  :INVOKE_HTTPSESSION_NAME = “/invoke-http-session”
DIコンテナ用コンテキスト      :INVOKE_APPLICATIONCONTEXT_NAME = “/invoke-application-context”
インスタンス廃棄用コンテキスト  :DESTROY_CONTEXT_NAME = “/destroy-instance”

クラスの紹介(詳細)

ClientUtilクラス(直接呼び出すことはありません)

パッケージ

com.curlap.orb.client

スーパークラス

なし

フィールド

HttpClient

コンストラクタ

ClientUtil()
ClientUtilクラスをインスタンス化します。

メソッド

requestToORB (管理するイベントを登録)
引数1(request:InstanceManagementRequest):リクエスト内容
引数2(uri:String):curl ORB サーバのURL
戻り値:Object リクエストに対してのレスポンス

HTTPSessionClientクラス

パッケージ

com.curlap.orb.client

スーパークラス

なし

フィールド

なし

コンストラクタ

HTTPSessionClient (指定したクラスをインスタンス化)
引数1(serverUrl:String):*オプション。ORBサーバのURLを指定。
デフォルトは“http://localhost:8080/curl-orb-server”
引数2(contextName:String) :*オプション。インスタンス作成用コンテキストを指定。
デフォルトは“/new-instance”
引数3(className:String) :*必須。インスタンス化したいクラス名
引数4(args:Object[]) :*必須。インスタンス化したいクラス必要な引数

呼び出し方
1.HttpSessionClient(java.lang.String className, java.lang.Object[] args)
2.HttpSessionClient(java.lang.String contextName, java.lang.String className, java.lang.Object[] args)
3.HttpSessionClient(java.lang.String serverUrl, java.lang.String contextName, java.lang.String className, java.lang.Object[] args)

メソッド

invokeMethod (インスタンス化したクラスのメソッドを呼び出す)
引数1(contextName:String):*オプション。インスタンス作成用コンテキストを指定。
デフォルトは“invoke-http-session”
引数2(methodName:String):*必須。呼び出したいメソッド名
引数3(args:Object[]):*必須。。呼び出すメソッドに必要な引数
引数4(boolean isStream):*オプション。trueに設定するとデータの返却がStream形式になります。
戻り値:Object リクエストしたメソッド対してのレスポンス

呼び出し方
1.invokeMethod(java.lang.String methodName, java.lang.Object[] args)
2.invokeMethod(java.lang.String methodName, java.lang.Object[] args, boolean isStream)
3.invokeMethod(java.lang.String contextName, java.lang.String methodName, java.lang.Object[] args)
4.invokeMethod(java.lang.String contextName, java.lang.String methodName, java.lang.Object[] args, boolean isStream)

destroy (インスタンス化したクラスの破棄)
引数1(contextName:String):*オプション。インスタンス作成用コンテキストを指定
デフォルトは“/destroy-instance”

呼び出し方
1.destroy(java.lang.String contextName)
2.destroy()

invokeStaticMethod (staticメソッドを呼び出す)
引数1(
serverUrl:String): *オプション。ORBサーバのURLを指定。
デフォルトは”http://localhost:8080/curl-orb-server”
引数2(contextName:String):*オプション。インスタンス作成用コンテキストを指定。
デフォルトは“invoke-http-session”
引数3(className:String):*必須。呼び出したいクラス名。
引数3(methodName:String):*必須。呼び出したいメソッド名。
引数4(args:Object[]):*必須。呼び出すメソッドに必要な引数。
引数5(boolean isStream):*オプション。trueに設定するとデータの返却がStream形式になります。
戻り値:Object リクエストしたメソッド対してのレスポンス

呼び出し方
1.invokeStaticMethod(java.lang.String className, java.lang.String methodName, java.lang.Object[] args)
2.invokeStaticMethod(java.lang.String className, java.lang.String methodName, java.lang.Object[] args, boolean isStream)
3.invokeStaticMethod(java.lang.String contextName, java.lang.String className, java.lang.String methodName, java.lang.Object[] args)
4.invokeStaticMethod(java.lang.String contextName, java.lang.String className, java.lang.String methodName, java.lang.Object[] args, boolean isStream)
5.invokeStaticMethod(java.lang.String serverUrl, java.lang.String contextName, java.lang.String className, java.lang.String methodName, java.lang.Object[] args)
6.invokeStaticMethod(java.lang.String serverUrl, java.lang.String contextName, java.lang.String className, java.lang.String methodName, java.lang.Object[] args, boolean isStream)

ApplicationContextClientクラス

パッケージ

com.curlap.orb.client

スーパークラス

なし

フィールド

なし

コンストラクタ

ApplicationContextClient:(ORBサーバのURLを指定)
引数1(serverUrl:String):*オプション。ORBサーバのURLを指定。
デフォルトは“http://localhost:8080/curl-orb-server”

呼び出し方
1.ApplicationContextClient(java.lang.String serverUrl)
2.ApplicationContextClient()

メソッド

invokeMethod(メソッドの呼び出し)
引数1(contextName:String):*オプション。インスタンス作成用コンテキストを指定。
デフォルトは“/invoke-application-context”
引数2(componentName:String):*必須。呼び出したいコンポーネント名。
引数3(methodName:String):*必須。呼び出したいメソッド名。
引数4(args:Object[]):*必須。呼び出したいメソッドに必要な引数。
引数5(boolean isStream):*オプション。trueに設定するとデータの返却がStream形式になります。
戻り値:Object リクエストに対してのレスポンス

呼び出し方
1.invokeMethod(java.lang.String componentName, java.lang.String methodName, java.lang.Object[] args)
2.invokeMethod(java.lang.String componentName, java.lang.String methodName, java.lang.Object[] args, boolean isStream)
3.invokeMethod(java.lang.String contextName, java.lang.String componentName, java.lang.String methodName, java.lang.Object[] args)
4.invokeMethod(java.lang.String contextName, java.lang.String componentName, java.lang.String methodName, java.lang.Object[] args, boolean isStream)

ORBClientException

パッケージ

com.curlap.orb.client

スーパークラス

Exception

フィールド

なし

コンストラクタ

ORBClientException:(クライアント側でのスローできる例外を定義します)
ORBClientException()

例外を新たに構築します。

呼び出し方
1.ORBClientException()
2.ORBClientException(java.lang.String message)
3.ORBClientException(java.lang.String message, java.lang.Throwable rootCause)
4.ORBClientException(java.lang.Throwable rootCause)

ORBServerException

パッケージ

com.curlap.orb.client

スーパークラス

Exception

フィールド

なし

コンストラクタ

ApplicationContextClient:(ORBサーバのURLを指定)
ORBServerException()

例外を新たに構築します

呼び出し方
1.ORBServerException()
2.ORBServerException(ExceptionContent exceptionContent)
3.ORBServerException(java.lang.String message)
4.ORBServerException(java.lang.String message, java.lang.Throwable rootCause)
5.ORBServerException(java.lang.Throwable rootCause)

メソッド

getExceptionContent(例外の返却)

呼び出し方
getExceptionContent()  

サーバURLの指定

デフォルトサーバURLの指定

サーバサイドのCurl ORBのデフォルトURLはhttp://localhost:8080/curl-orb-serverです。もし変更したい場合は、{set-default-server-url}プロシージャを利用してください。
例えば以下のように記載します。

{import * from COM.CURL.ORB}

{set-default-server-url {url “http://hogehoge:8888/test-server“}}

通常これは、フレームワーク等で、アプリケーション起動の最初に記述することとなります。

サービスクラスごとにサーバURLを指定

下図のようにサービスURLを呼び出すときに変更することができます。

server-url.jpg

これをするには、生成されたコードのコンストラクタに以下のようなserver-urlというキーワード引数があり、こちらを指定することで違うURLにアクセスすることができます。

|| 生成されたコードです。
{define-class public Foo
{inherits HttpSessionClient}

|| constructor
{constructor public {default server-url:#Url = null}
….

以下は指定例です。

def foo = {Foo server-url = {url http://test.curlap.com/test}}

その他 TIPS

クライアントキャッシュ

0.8からクライアントキャッシュ機能が追加されました。クライアント内でキャッシュすることで、サーバ通信の負荷を低減することができます。

キャッシュの種類にはメモリ or ディスク及びLRU[Least Recently Used](LRUCache) or すべて保存(SimpleCache)を選択することができます。

これを利用するためには、ダウンロードしたディレクトリの「ソースディレクトリ/tests/test-cases/cache-case.scurl」が参考になります。

|| 例.
def cache = {create-simple-cache “test”, spec = {CacheSpec disk-persistent? = true}}

{if not {cache.exists? “hoge”} then
set cache[“hoge”] = 1000
else
{output cache[“hoge”]}
}

パフォーマンス改善アノテーション

@DoNotShareアノテーションを利用することで、サービスクラスの戻り値が大量データかつ同一データが少ない場合に改善する可能性がございます。

@DoNotShare
public List<LargeDto> getLargeDto(int num) {
….
}

このアノテーションは、従来バイナリデータ通信をする際に同一データが存在すると、2件目以降はリンク情報を持つだけで、実データを保持しないようになっております。これにより、高速かつコンパクトなデータ通信を実現していますが、同一データが少ない場合は、実際にアプリケーションによっては高速になる場合もあれば、遅くなる場合もございます。当機能はこれを解決する可能性のあるパラメータです。但し、どれほど高速になるかはアプリケーションやデータの種類によって変わりますので、当アノテーションをメソッドに付与して、検証をしていただく必要があります。

データ圧縮

通信時、データを圧縮することができます。これにより大幅にトラフィック量が減ることになります。これは、HTTP圧縮の仕組みを利用します。

リクエスト時、HTTPリクエストヘッダー部(Accept-Encodingにgzip)を追加します。クライアントでは、HTTPレスポンスヘッダーにContent-Encodingがgzipであれば、解凍します。

サーバで圧縮する際は、WebサーバのHTTP圧縮機能を使います。例えばTomcatで実施する際は、server.xmlを以下のように設定します。

<Connector
acceptCount=”100″
compressableMimeType=”application/octet-stream,application/x-javascript,text/html,text/xml,text/javascript,text/css,text/plain”
compression=”on”
compressionMinSize=”2048″
connectionTimeout=”20000″
disableUploadTimeout=”true”
enableLookups=”false”
maxHttpHeaderSize=”8192″
maxSpareThreads=”75″
maxThreads=”150″
minSpareThreads=”25″
noCompressionUserAgents=”gozilla,traviata”
port=”8080″
redirectPort=”8443″
/>

これで、HTTP圧縮機能を利用することができます。

また、クライアントで圧縮機能を利用するか否かは、インターセプターを利用します。インターセプターを作成し、build-http-request-headersメソッドをオーバーライドし、HTTPヘッダーに追加します。

{method protected open {build-http-request-headers
headers:#HttpRequestHeaders
}:#HttpRequestHeaders
{return
{if-non-null h = headers then
{h.set “Accept-Encoding“, “gzip“}
h
else
{HttpRequestHeaders “Accept-Encoding“, “gzip“}} 
}
}

詳しくはインターセプター利用のページを参照ください。

Google App Engine for Javaとの連携

Google App Engine for Javaを利用したクラウド上でORBを動かす記事をCodeZine上に公開しております。

web.xmlの設定

ORBではweb.xmlに4つのサーブレットと1つのフィルターを設定する必要があります。4つのサーブレットは、ダウンロードしたディレクトリにあるものをそのままお使いください。フィルター(DefaultFilter)は、以下のようになっています。

<!– DefaultFilter –>
<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>

もしServlet2.5以上をご利用の方は、以下のようにurl-patternを4つのサーブレットのみに指定してください。(Servlet2.4では複数のurl-patternを指定できないです。)そうしますと、ORBへのリクエストのみこのフィルターを通るようになります。

<!– DefaultFilter –>
<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>/invoke-application-context</url-pattern>
<url-pattern>/new-instance</url-pattern>
<url-pattern>/invoke-http-session</url-pattern>
<url-pattern>/destroy-instance</url-pattern>

</filter-mapping>

また、コード生成の際に、サーバ側でclassファイルやjarファイルを読み込みますが、その読み込みを絞り込むことができます。これには以下のように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.,org.seasar.,ognl.,org.aopalliance.,junit.</param-value>
</context-param>

さらにバージョン0.7からは、WEB-INF/lib配下にあるjarファイルやWEB-INF/classesをコード生成の再にロードするか否かを選択できるようになりました。これにより、不要なクラスをローディングしないようにできます。以下のようにcom.curlap.org.generator.load-filetypeにclassを設定しますと、WEB-INF/classesのみをロード、jarであればWEB-INF/libのみ、bothであれば両方をロードします。

<context-param>
<param-name>com.curlap.orb.generator.load-filetype</param-name>
<param-value>class</param-value>
</context-param>

Curlドキュメントのインストール

ダウンロードしたディレクトリのcurl/COM.CURL.ORB-V0.8-docにmanifest.mcurlがあります。これをCurlIDEのメニュー→ヘルプ→ドキュメントインストールで取り込むことができます。

staticメソッド及びフィールドの扱い

Curl ORBのコード生成ツールでは、Javaで定義したstaticなメソッド及びフィールドは、Curlのクラスプロシージャクラス変数として生成されます。

例えば、Javaのサービスクラスは以下のように生成されます。(クラスプロシージャはdefine-procとして、クラス変数は、letとして生成。)

Java

public class HogeImpl {
public static String str;

public static int getBarBar() {
return 210;
}
}

Curl

{import * from COM.CURL.ORB}

{define-class public HogeImpl {inherits ApplicationContextClient}

let public str:#String

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

{define-proc public {get-bar-bar}:int
{return {ApplicationContextClient.invoke-static “hoge1”, “getBarBar”}}
}
}

これは以下のようにアクセスできます。
・クラスプロシージャ : クラス名.メソッド名
・クラス変数 : クラス名.フィールド名

{do
|| クラス変数
{output HogeImpl.str}

|| クラスプロシージャ
{output HogeImple.get-bar-bar}}
}

Curl ORBのコード生成ツールを利用して、非同期通信のメソッドを生成することができます。(通常は同期通信を行うメソッドがコード生成ツールから生成されます。)

非同期通信用メソッドの生成

コード生成ツールのクラス編集画面のMethods欄に”async?“というチェックボックスがあります。これをチェックしますと非同期通信用のメソッドとしてコードが生成されます。

orb-async.jpg

以下が生成されたコードです。

{import * from COM.CURL.ORB}

{define-class public Hello {inherits ApplicationContextClient}

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

{method public {say-hello v0:String, …:EventHandler}:AsyncWorker
{return {self.async-invoke “sayHello”, arguments = {FastArray v0}, {splice …}}}
}

}

非同期での通信のため、処理を記述する際は結果を待つことなく次の処理に進んでしまいます。(例えば、以下の例ですとsay-helloメソッドを実行した後、終了結果を待たずに{output “xxx”}という行が実行されます。)そこで終了した際の処理を記述するため、生成されたコードの引数”…:EventHandler”に終了時のイベントハンドラーをセットします。この際、AsyncCallbackEvent (COM.CURL.ORB.SERVLETパッケージ内)というイベントを使用します。これによりsay-helloが終了しますと{on e:AsyncCallbackEvent do ….}の中の処理が実行されます。

{import * from COM.CURL.ORB}

{do
def hello = {Hello}
{hello.say-hello 
“this is test”,
{on e:AsyncCallbackEvent do
{if-non-null ex = e.exception then
|| Exceptionが発生した際の処理を記述
{dump ex}
else
|| 成功した際の処理を記述
|| 結果はAsyncCallbackEventのobjプロパティで取得できます。
def result = e.obj asa #String
}
}
}
{output “xxx”}
}

AsyncCallbackEventexceptionプロパティとobjプロパティを持っております。
処理中にExceptionが発生した場合は、このexception:#Exceptionをチェックすることができます。

戻り値を受け取る際は、obj:anyプロパティを参照しますと結果が受け取れます。(通常は上記コードのようにキャストすることとなります。

ヘッダー情報の送信

Curl ORBは、サーバへデータを送信する際、クライアントから任意の付加情報を送信可能です。また、アプリケーション全体に共通なヘッダ情報(グローバルヘッダー)とインスタンスの生成やメソッド実行毎に付与できるヘッダ情報(ローカルヘッダー)が利用可能となっています。

使用するAPI

set-global-headerプロシージャ 
get-global-headerプロシージャ 
clear-global-headerプロシージャ 
HttpSessionClientのコンストラクタ及び各メソッドのrequest-header:HashTableキーワード引数
ApplicationContextClientの各メソッドのrequest-header:HashTableキーワード引数
(COM.CURLAP.ORBパッケージ)

以下にサンプルコードを掲載しておきます。

|| グローバルヘッダーに値をセット
{set-global-header “global-k”, “global-v”}

|| ローカルヘッダーとして値をセット
def orb = {HttpSessionORBClient “tests1.Foo”, request-header = {HashTable “test-header-k”, “test-header-v”}}

※当ヘッダー送信機能はインターセプターを利用することで、実現可能です。(今後インターセプターを推奨としていく予定です。)

サービスクラスをクライアントでシンプルなコンテナ管理

サービスクラスをクライアントでコンテナ管理することで、サービスクラスをシングルトンとして扱うことができます。これには、set-service-to-containerプロシージャを利用して登録し、get-service-from-containerでオブジェクトを取得できます。コンテナ上では、シングルトンとして扱われ、無駄なオブジェクトを生成する必要がなくなります。

また、この際、サービスクラスごとにサーバURLが異なる場合に、サーバURLもserver-urlというキーワード引数を用いて登録しておくことができます。

|| サービスクラスの登録
||   引数は、1.任意の名称(String)、2.クラス(ClassType)、3.server-url = サーバURL(URL)

{set-service-to-container “ServiceA”, Foo}
{set-service-to-container “ServiceB”, Hoge, server-url = {url “http://nothing-url.com“}}

|| サービスの取り出し
||  引数は登録時に指定した任意の名称(String)

def foo = {get-service-from-container “ServiceA”}
def hoge = {get-service-from-container “ServiceB”}

注意)同一の名称で登録することはできません。
注意)サービスクラス(DI)のみ管理できます。 ※サービスクラス(HttpSession)は管理できません。
注意)シングルトンとして扱いたくない場合は、利用しないでください。