FlatServe
0.3

FlatServe API仕様 バージョン0.3

FlatServeは、Webアプリケーション開発のための、シンプルで軽量なライブラリです。

参照先:
          説明

パッケージ
com.small_it_office.flatserve.core メインのサーブレットクラスと、その他FlatServe内で利用する汎用クラスを提供します。
com.small_it_office.flatserve.core.config FlatServeの設定を行うためのクラスを提供します。
com.small_it_office.flatserve.core.plugin プラグインに関するクラスを提供します。
com.small_it_office.flatserve.core.request クライアントから受信したHTTPリクエストの読み込みに関するクラスを提供します。
com.small_it_office.flatserve.core.response HTTPレスポンスをクライアントに送信するためのクラスを提供します。
com.small_it_office.flatserve.core.service HTTPサービスメソッドの作成に関するクラスを提供します。

 

FlatServeは、Webアプリケーション開発のための、シンプルで軽量なライブラリです。 シンプルなプログラミング・シンプルな環境設定で、できる限り簡単に利用可能であることを目指しています。

FlatServeの特徴

FlatServeの使用方法

HTTPサービスクラスの作成

HTTPサービスクラスは、特定のクラスを継承したり、インターフェースを実装したりする必要はありません。 POJOとして作成することができます。

HTTPサービスメソッドの基本

HTTPサービスメソッドとして公開したいメソッドには、@HttpService アノテーションを付加します。

public class MyHttpService {
    @HttpService
    public void serviceMethod1(HttpServletRequest request, HttpServletResponse response) {
        ....
    }
}

HTTPサービスメソッドは、publicでなければなりません。また、スーパークラスに定義されたHTTPサービスメソッドを 実行することもできます。ただし、HTTPサービスメソッドオーバーライドした場合は、オーバーライドしたメソッドにも @HttpServiceアノテーションを付加する必要があります。

HTTPサービスメソッドの引数

HTTPサービスメソッドは、以下の型の引数を受け取ることができます。引数の順序や組み合わせは固定ではありません。

引数アノテーション 受け取る内容
javax.servlet.http.HttpServletRequest なし Java Servlet APIのHTTPサーブレットリクエストオブジェクト
javax.servlet.http.HttpServletResponse なし Java Servlet APIのHTTPサーブレットレスポンスオブジェクト
javax.servlet.ServletConfig なし Java Servlet APIのサーブレットコンフィグオブジェクト
java.lang.String @Param Webブラウザなどから送信されたリクエストパラメータ
java.lang.String[] @Param Webブラウザなどから送信されたリクエストパラメータ
java.lang.String @RequestBody HTTPリクエストボディ全体
byte[] なし HTTPリクエストボディ全体
任意のJavaBean なし リクエストパラメータを格納したオブジェクト

なお、コアモジュール単体では、HTMLフォームからのリクエストパラメータはString型の引数か、 JavaBeanのString型のフィールドでのみ受け取れますが、Validatorプラグインを利用すると、intやDate、BigDecimalなど、 さまざまな型で引数を受け取ることができるようになります。詳細はValidatorプラグインのドキュメントを参照してください。

以下のHTTPサービスメソッドでは、"param1"という名前のリクエストパラメータと、HTTPレスポンスオブジェクトが 実行時に自動的に引数で渡されます。

@HttpService
public void serviceMethod2(@Param("param1") String param1, HttpServletResponse response){
    ....

引数の型をbyte[]にすると、リクエストボディ全体を引数で受け取ることができます。また、 @RequestBodyをつけたString型の引数で リクエストボディ全体を文字列として受け取る方法もあります。

@HttpService
public void serviceMethod3(byte[] body){
    ....

以下のように、HTTPリクエストボディ全体を受け取る引数と、リクエストパラメータを個別で受け取る引数を 混在させることはできません。このようなメソッドを定義した場合、実行時に例外が発生します。

@HttpService
public void wrongMethod1(@Param("param1") String param1, byte[] body){
    ....
リクエストパラメータを受け取るJavaBean

リクエストパラメータを格納するためのJavaBeanを作成し、HTTPサービスメソッドの引数の型にすることで、 FlatServeがJavaBeanのオブジェクトを生成し、リクエストパラメータをオブジェクトに格納してHTTPサービスメソッドに渡します。

JavaBeanのフィールドににリクエストパラメータを格納するために、以下のいずれかに従っている必要があります。

また、リクエストパラメータを格納するフィールドの型については、 HTTPサービスメソッドの引数に準じます。

以下の例では、HTTPサービスメソッドserviceMethod4の実行時に、"param1"、"param2"という名前のリクエストパラメータが、 MyParameterBeanオブジェクトのフィールドに自動的に格納された状態で渡されます。

@HttpService
public void serviceMethod4(MyParameterBean bean, HttpServletResponse response) {
    String param1 = bean.getParam1();
    String[] param2 = bean.getParam2Array();
    ....
}

//引数のJavaBeanクラス
public class MyParameterBean {
    private String param1;
    
    @Param("param2")
    private String[] param2Array;
    
    public String param1() {
        return param1;
    }
    
    public String[] getParam2Array() {
        return param2Array;
    }
}
プログラミングによるJavaBeanの生成

リクエストパラメータをHTTPサービスメソッドの引数で受け取るのではなく、リクエストパラメータを格納したJavaBeanを プログラミングによって生成することもできます。 リクエストパラメータを静的に決められないアプリケーションフレームワークなどで利用できます。

JavaBeanを生成するには、Populatorを使用します。 JavaBeanクラスの作成方法は、リクエストパラメータを受け取るJavaBeanと同様です。

@HttpService
public void serviceMethod5(HttpServletResponse response) {
    MyParameterBean bean = Populator.getInstance().populate(MyParameterBean.class);
    String param1 = bean.getParam1();
    String[] param2 = bean.getParam2Array();
    ....
}
HTTPクライアントへの応答

HTTPサービスメソッドの責務は、HTTPクライアントへの応答も含まれます。応答の方法は、以下の2通りあります。

  1. javax.servlet.http.HttpServletResponseオブジェクトを引数で受け取り、直接応答を出力する
  2. HTTPサービスメソッドの戻り値で、応答を表すオブジェクトを返す

前者の方法の場合、HTTPサービスメソッドの戻り値はvoidとします。void以外の型にした場合の結果は保証されません。 後者の方法の場合、HTTPサービスメソッドの戻り値は、以下の表のいずれかの型とします。これ以外の型を戻り値とした場合は 例外がthrowされます。

応答方法
java.lang.String Content-Typeを"text/plain"、文字セットをUTF-8で、プレーンテキストとして応答を返します。
byte[] Content-Typeを"application/octet-stream"として、バイトストリームの応答を返します。
Responseのサブクラス 各クラスに応じた応答を返します。

Responseと、そのサブクラスの詳細については、com.small_it_office.flatserve.core.response パッケージの各クラスの説明を参照してください。

HTTPサービスメソッドの同期実行(※環境依存機能)

サーブレットは通常、マルチスレッドで動作するため、複数のリクエストを同時に受信した場合、 並列でHTTPサービスメソッドが実行されます。しかし、Webブラウザのボタンの二度押しなどの操作によって、 同一クライアントからの複数のリクエストを同時に実行することは避けたい場合もあります。

同一のセッションにおける並行処理を避けるために、以下のようにHttpServiceアノテーションにsessionSynchronized要素を記述して、 HTTPサービスメソッドを同期化することができます。

@HttpService(sessionSynchronized = true)
public void synchoronizedService1() {
    ....
}

@HttpService(sessionSynchronized = true)
public void synchoronizedService2() {
    ....
}

@HttpService
public void nonSynchronizedService() {
    ....
}

この例では、同一のクライアントから同時にリクエストがあっても、synchronizedService1メソッドが複数、あるいは synchronizedService1メソッドとsynchronizedService2メソッドが同時に、並列で実行されることはありません。 片方のリクエストは、もう片方のリクエスト処理が終わるまで待たされます。しかし、nonSynchronizedServiceメソッドには sessionSynchronized = trueが指定されていない(指定されない場合のデフォルト値はfalseです)ため、 synchronizedService1メソッドとnonSynchronizedServiceメソッドは、同時に並列で実行されます。

このようなHTTPサービスメソッドの同期が機能するのは、すでにjavax.servlet.http.HttpSessionオブジェクトが 既に生成されている場合のみとなります。つまり、HttpServletRequest#getSession(false)がnullを返す場合は、 同一セッションであることを確認できないため、同期化は行われません。

※注意:この機能を利用できる環境は限定されます。サーブレットコンテナの実装によってはこの機能は 正常に動作しません。Apache Tomcat 5.5.xおよび6.xで動作することは確認できています。 その他のサーブレットコンテナについては未確認です。 また、クラスタリングによって負荷分散を行う場合、同一セッションのリクエストが必ず 同一のノード(サーバ)で処理されることが保証されない限り、この機能は正常に動作しません。

URLマッピング

FlatServeは、HTTPクライアントからのリクエストURLに対して、実行するHTTPサービスクラス・メソッドをマッピングします。 設定によってURLとHTTPサービスクラスのマッピングを一つ一つ指定することもできますが、まったく設定をせずにマッピングを 行うこともできます。

URLマッピングは、以下に示すルールで行われます。

URLをそのままHTTPサービスクラスの完全修飾名とメソッド名に変換

何も設定を行わない場合、リクエストURLのコンテキストルートより下の階層を、HTTPサービスクラスの完全修飾名およびメソッド名と 解釈します。このとき、URL内の「/」は「.」に変換し、URLの拡張子やクエリーストリングは無視します。また、URLの「/」 で区切られた最後の文字列が、英小文字で始まる場合はメソッド名が指定されたとみなし、その前の部分までをクラスの完全修飾名と みなします。大文字で始まる場合は、それがクラス名とみなし、メソッド名は省略されたとみなします。 メソッド名が省略された場合は、デフォルトである「execute」をメソッド名として扱います。

例1:

http://host:port/contextroot/foo/bar/baz/MyHttpService/service1.fs

この場合、コンテキストルートより下で、拡張子を除いた文字列を抜き出すと、「foo/bar/baz/MyHttpService/service1」となります。 「/」で区切られた最後の文字列「service1」は小文字で始まるので、メソッド名とみなします。したがって、それより前の部分の 「/」を「.」に置換した文字列、すなわち、「foo.bar.baz.MyHttpService」が、HTTPサービスクラス名とみなされます。 FlatServeは、foo.bar.baz.MyHttpServiceクラスのservice1メソッドをHTTPサービスメソッドとして実行しようとします。 もしこのクラスが存在しなかったり、メソッドがHTTPサービスメソッドと認められなかった場合には、このURLは存在しないものとして、 HTTPステータス404で応答します。

例2:

http://host:port/contextroot/foo/bar/baz/MyHttpService.fs

この場合は、最後の「MyHttpService」が大文字で始まるため、クラス名であるとみなし、 したがってメソッド名は省略されたとみなされます。この場合、FlatServeは、 foo.bar.baz.MyHttpServiceクラスのexecuteメソッドをHTTPサービスメソッドとして実行しようとします。

パッケージ名の共通部を追加してHTTPサービスクラス名を生成

前項で示したマッピングルールは、HTTPサービスクラスの完全修飾名が、そのままURLの表現に現れます。しかし、 クラスの完全修飾名は長くなりがちで、URLとしてはかなり扱いにくいものになります。 また、一つのWebアプリケーション内のクラスが属するパッケージは、名前が長いものの、通常は企業や団体のドメイン名で始まるため、 すべてのパッケージは途中まで同じ名前を持つケースがほとんどです。 このため、この共通部を、設定オブジェクトに登録しておくことで、URLではそれより後の部分だけを指定できるようになります。 設定オブジェクトの詳細については、後述のFlatServeの設定を参照してください。

たとえば、設定オブジェクトで以下のように設定します。

    Config config = new Config();
    config.setPackageHeadName("foo.bar");

このとき、以下のようなURLに対してリクエストがあったとします。

http://host:port/contextroot/baz/MyHttpService/service1.fs

FlatServeは、前項と同様の手順で、「service1」をメソッド名、「baz/MyHttpService」の部分をクラス名部分とみなしますが、 パッケージ名の共通部として「foo.bar」が指定されているため、これをパッケージ名の先頭に追加し、HTTPサービスクラス名は 「foo.bar.baz.MyHttpService」となります。

個別指定されたURLとHTTPサービスクラスのマッピング

前項までのマッピングルールにより、非常に少ない設定でURLからHTTPサービスクラス・メソッドへのマッピングを行うことができます。 しかし、URLとクラスやメソッドの名前を関連させたくない場合は、設定オブジェクトによって、 URLに対して実行するHTTPサービスクラスを一つ一つ個別に指定できます。 設定オブジェクトについての詳細は、FlatServeの設定を参照してください。 指定方法は、以下のような記述になります。

    Config config = new Config();
    config.addRequestPathMapping("my/service", MyHttpService.class);

Config.addRequestPathMapping(java.lang.String, java.lang.Class)メソッドの第一引数には、 サーブレットのコンテキストルートより下の部分で、拡張子を除いた文字列を指定します。上記の例では、 http://host:port/contextroot/my/service.fsのようなURLへのリクエストに対して、MyHttpServiceクラスをHTTPサービスクラスとして マッピングします。このようなマッピングルールは、いくつでも追加することができます。

なお、上記のようにマッピングを個別指定する場合は、HTTPサービスメソッド名を指定することはできません。メソッド名は 「execute」に固定されます。

FlatServeの設定

FlatServeは、設定ファイルを持ちません。 各種設定内容は、Configオブジェクトに集約されます。このオブジェクトを設定オブジェクトと呼びます。 Javaプログラミングで設定オブジェクトを生成し、各種設定値を格納することで設定を行います。 Configオブジェクトの生成は、アプリケーションの初期化処理の中で行います。 以下、設定オブジェクトを生成するための実装手順を示します。

  1. アプリケーション初期化クラスの作成
    FlatServeは、アプリケーションの初期化を行うフックポイントを提供しています。 アプリケーション開発者は、ApplicationInitializerインターフェースを実装したクラスを作成します。 initメソッドは、FlatServeの初期化時(javax.servlet.http.HttpServlet#init()実行時)に実行されます。
  2. アプリケーション初期化クラスで設定オブジェクトを生成するための実装
    initメソッドで、Configオブジェクトを生成する実装を行います。
  3. アプリケーション初期化クラス名を配備記述子に記述
    Webアプリケーション配備記述子(web.xml)に、サーブレットのinit-paramとして、アプリケーション初期化クラス名を記述します。 記述方法は、Webアプリケーション配備記述子(web.xml)の説明を参照してください。

アプリケーション初期化クラスの記述方法の例を以下に示します。

public class MyApplicationInitializer implements ApplicationInitializer {
    public Config init(ServletConfig servletConfig) {
        Config config = new Config();
        config.setPackageHeadName("com.foo");
        config.setRequestEncoding("EUC-JP");
        return config;
    }
}

アプリケーション初期化クラスは、作成しなくてもかまいません。その場合は、デフォルトの設定が自動的に適用されます。

プラグインを利用する場合は、プラグインに対する設定もアプリケーション初期化クラス内で行います。 設定方法の詳細は、コアモジュールとプラグインおよび、各プラグインのドキュメントを参照してください。

設定オブジェクトの設定項目については、Configクラスのドキュメントを参照してください。

Webアプリケーション配備記述子(web.xml)

FlatServeを使うには、Webアプリケーション配備記述子(web.xml)にサーブレットの設定を記述する必要があります。

<servlet>要素

FlatServeを、<servlet-class>要素で登録します。<servlet-name>は任意です。

また、必要に応じてアプリケーション初期化クラスに関する記述を行います。 <init-param>で<param-name>要素に"init-class-name"、 <param-value>要素にアプリケーション初期化クラスの完全修飾名を指定します。これにより、 FlatServeはアプリケーションの配備時に自動的にアプリケーション初期化クラスを実行します。


<servlet-mapping>要素

<servlet>要素で設定したサーブレットに対して、任意のURLパターンをマッピングします。 すなわち、<servlet-name>要素には上記<servlet>要素内で指定したservlet-nameと同じ名前、 <url-pattern>要素にはFlatServeを実行する任意のURLパターンを指定します。

Webアプリケーション配備記述子の記述例を以下に示します。

<servlet>
    <servlet-name>flatserve</servlet-name>
    <servlet-class>com.small_it_office.flatserve.core.FlatServe</servlet-class>
    <init-param>
        <param-name>init-class-name</param-name>
        <param-value>com.foo.MyApplicationInitializer</param-value>
    </init-param>
</servlet>

<servlet-mapping>
    <servlet-name>flatserve</servlet-name>
    <url-pattern>*.fs</url-pattern>
</servlet-mapping>

コアモジュールとプラグイン

FlatServeの本体を、コアモジュールと呼びます。コアモジュールは、できる限り簡単に習得可能とするため、 シンプルな機能に絞って提供しています。コアモジュールとは別に、様々なプラグインが提供されており、 必要な機能を持つプラグインをあわせて利用することで、アプリケーション構築に必要な機能を追加することができます。

プラグインを追加する方法はとても簡単で、プラグインの提供物に含まれるJARファイルを、クラスパスに追加するだけです。 設定ファイルなどは一切記述しなくても、FlatServeはプラグインの存在を認識します。逆に、クラスパス上に存在するプラグインを 使用したくない場合は、設定オブジェクトによって、自動的にプラグインを読み込まない設定も可能です。

設定オブジェクトのConfig.addOptionalConfig(Object)メソッドは、 プラグインの設定情報を追加するためのメソッドです。各プラグインは、プラグイン毎に設定を行うための オプション設定クラスを提供しています。オプション設定クラスのインスタンス(オプション設定オブジェクト)を生成し、 Config.addOptionalConfig(Object)メソッドで設定オブジェクトに追加することで、 各プラグインに対する設定が反映されます。

ログ出力

FlatServeはJava標準ロギングライブラリを使用してログ出力を行います。FlatServeが出力するログのレベルを変更したい場合は、 ロギング構成ファイル(logging.properties)で"com.small_it_office.flatserve"という名前のLoggerのログレベルを、 以下の例のように指定してください。

com.small_it_office.flatserve.level=WARNING

国際化・地域化

FlatServeは、ログメッセージおよび例外メッセージを、リソースバンドルを使って読み込んでいます。 デフォルトで提供されているメッセージは日本語のみですが、 各ロケールに対応したリソースバンドルファイルを作成することで国際化・地域化することができます。

ログ出力メッセージおよび例外メッセージのリソースバンドル名は、flatserve-messagesです。 JARファイル内にはflatserve-messages_ja.propertiesファイルが含まれているため、日本語のメッセージはそのまま利用可能です。 その他の言語で記述されたリソースバンドルファイルを、クラスパスが通ったディレクトリに配置することで国際化・地域化できます。 たとえば、ログや例外のメッセージを英語化する場合は、flatserve-messages_en.propertiesをクラスパス上に配置します。 実行時のロケールは、設定オブジェクトによって指定できます。指定しない場合は、実行環境のデフォルトロケールが適用されます。


FlatServe
0.3