2007-06-30

OpenJPA: JPQLでパラメータプレースホルダに使ってはいけない言葉

日付範囲を指定するUIを作って、開始日を from 終了日を to という名前にした。
で、日付範囲で請求書(Invoice)を抽出する
select i from Invoice i where i.date between :from and :to order by i.date'
みたいなJPQLを発行しようとしたら

org.apache.openjpa.kernel.jpql.ParseException: Encountered "i . date between : from" at character 31, but expected: ...

というようなエラーになった。
パラメータのプレースホルダに予約語を使うとこうなるらしい。というわけで、:frmとか:fro にして回避する。

JPQLの仕様なのか OpenJPAの仕様なのかは不明。

ラベル:

2007-06-23

Gentoo:電源ボタンの押下で電源が切れるようにする

客先にちょっとしたアプライアンスめいたヘッドレスサーバをGentooで構築して置いておくなんていう場合、問題になるのがシャットダウン手順だ。
ログインして root権限でシャットダウンコマンドを実行するといった簡単な操作でも、コマンドライン操作に慣れていない人にはかなり厳しいものがある。Macならともかく、そもそも Windows端末には sshクライアントが入っていない。
ここで「TeraTermなりPoderosaなりを入れればいいじゃん」って言い出す奴は、まず顧客というものを分かっていない。

いいかよくきけ。顧客というモノには、Officeと InternetExplorerとOutlook(Express)の操作スキルしか要求してはいかんのである。基本的には。顧客はパソコンを使いたいから使っているのではなく、使わないと仕事にならないから仕方なく使っているのだということを忘れてはならぬ。

というわけで、電源ボタンをポチリと押せば自動でOSがシャットダウンされたのちに電源が切れるようにしておきたい。そうすればターミナルの使い方のような「一生触れずに済むのならそれが幸せに違いないモノ」を顧客から遠ざけることが出来るのだ。これは感謝されるべきことである。別に感謝されないけど。

Gentooの場合 ACPIデーモンが標準では入っていないのでそれを入れる。

# emerge acpid

/etc/acpi/events/default というファイルが出来るので、
#event=button.power.*
#action=/sbin/init 0
となっている行をコメントインする。(この2行が電源ボタンが押されたときに何をするか?の定義らしい)

ACPIデーモンを起動する

# /etc/init.d/acpid start

試しにPCの電源ボタンを押してみよう(長押しは有無を言わさず切れてしまうので禁止)。
OSのシャットダウンが行われ、電源が切れるはずだ。もし切れなかったらマザーボードがおかしいかBIOS設定がおかしいかカーネル設定がおかしい。

次回起動時から acpidを自動起動するには

# rc-update add acpid default

とする。
おめでとう、あなたの顧客は幸せだ。本人は知るよしもないけど。

ラベル:

2007-06-16

P904i購入


データプランのSIMカードを差して秋葉ヨドバシで買い増ししようとしたら、店員のマニュアルにない完全にイレギュラーなフローになりやたらと時間がかかったが、いちおう買えた。

10ヶ月以上の買い増しで卓上ホルダーも付けて 36,330円(店頭表示価格は3万円ちょっとなのだが、今回買い増しした回線はデータプランのため年割適用ができず割引条件の関係で高くなってしまった)

音楽も聴かないしカメラも使わないしメールも受信専用だしゲームもしないしフルブラウザもよほどの時しか使わないので総合評価はともかく、以前の機種と比べて Bluetooth周りの機能へすぐにアクセス出来るようになっている。またメモリ容量はP902iの時と比べて格段に多いので、勝手着うたはたくさん入りそう。

2007-06-12

libdm.so.0 が無いといって Sambaが起動できない

* samba -> start: smbd .../usr/sbin/smbd: error while loading shared libraries: libdm.so.0: cannot open shared object file: No such file or directory

emerge dmapi で解決できた。
dependency漏れ?

dmapiの Descriptionには "XFS data management API library" と書いてあるので、XFSを使用している環境に特有の依存関係なのかもしれない。(そういうのあるのか?)

ラベル:

OpenJPAのビルドタイムエンハンサをantからコールする

JPAのエンティティクラスはエンハンスされていないと使えない。

コンパイル後(実行前)に classファイルを書き換えてしまうのがビルドタイムエンハンス
実行中にリアルタイムでクラスをエンハンスするのがランタイムエンハンス

Eclipseで開発作業をしているときにはランタイムエンハンスが便利。OpenJPAの場合、Java VMに -javaagent:/path/to/openjpa.jar オプションを与えてやることでランタイムエンハンスが有効になる。

しかし warファイルを作って Tomcatにデプロイしようとしたとき、どうしてもランタイムエンハンスをうまく適用させることが出来なかった(JAVA_OPTS環境変数に -javaagentをセットするとTomcatが起動しない・・・)
仕方ないので antのタスクでビルドタイムエンハンスをすることにした。OpenJPAでは、ビルドタイムエンハンス用のAntタスクが提供されている。

build.xmlに加えた内容


コンパイルの後、パッケージングの前に

<taskdef name="openjpac" classname="org.apache.openjpa.ant.PCEnhancerTask">
<classpath>
<fileset dir="OpenJPAや依存jarが入っているディレクトリ" includes="*.jar"/>
<pathelement location="対象クラス及びMETA-INF/persistence.xmlを含むクラスパス"/>
</classpath>
</taskdef>
<openjpac />

エンハンス対象となるクラスを特定するため、persistence.xmlの persistence-unit内に class要素を羅列しておく必要がある(これはランタイムエンハンスの場合でも実行時間を短縮するために有用)。

これでアプリケーションサーバに特別な設定をすることなく OpenJPAを使った Webアプリケーションがデプロイできるようになった。

ラベル:

2007-06-11

OpenJPA がエンティティクラスを認識しない問題

JPAでは、JPQLという SQLによく似た問い合わせ言語を使ってデータベースを利用できる。SQLとの違いは、SQLが「行」や「列」を扱うものであるのに対して(当然)、JPQLは行や列の代わりに「オブジェクト」「プロパティ」を扱うようになっていることだ。

下記の例では、hogeプロパティが honyaと等価な MyEntityクラスオブジェクトのリストが返ってくる。(むろん、実際にはRDBのテーブル・行・列が検索される)

Collection col =
entityManager.createQuery(
"select m from MyEntity m where m.hoge=?1")
.setParameter(1, honya)
.getResultList();

ところが、このコードでOpenJPAが下記のような例外を投げてくるという現象が発生した。

org.apache.openjpa.persistence.ArgumentException: Could not locate metadata for the class using alias "MyEntity". Registered alias mappings: "{MyEntity=null}"

要するに MyEntityなんてクラスは知らないよと。
EntityManager#find()を使った場合などはこのエラーが出なかったのだが・・・

どうやら、OpenJPAでは createQuery(など)が行われる前に対象のエンティティクラスが最低いちどは VMにロードされていなくてはいけないらしい。(利用のしかたにもよるのかも)

というわけで、格好悪いけど JPAを利用する Beanに下記のような staticコンストラクタを書き足した。余計な依存性は発生しないし、ひとまずこれで良いとする。

static {
try {
MyEntity.class.newInstance();
} catch (Exception e) {
// ここにはこないで・・・
}
}

ラベル:

Springで JPAの共有EntityManagerを利用する

EntityManagerFactoryにさえアクセスできるようセットアップされていれば、いちおう JPAが利用出来ることになるのだが、毎度ファクトリから EntityManagerを取り出して使い終わったらクローズするといった処理の記述を省略できればさらに良い。

Java EEでは @PersistenceContext アノテーション (javax.persistenceパッケージにある) を用いることによって、コンテナから Beanに対して自動的に EntityManager (Factoryじゃなく、さっそく使える方)をインジェクトしてもらえるらしい(ちゃんと調べていないが多分そう)。これならファクトリから EntityManagerのインスタンスをもらったり、使った後に閉じたりする処理を記述しなくて済む分プログラムが少し短くできる(どれほどのもんよ?という疑問はあるが)。

実はこの機能、SpringでもSharedEntityManagerBeanとPersistenceAnnotationBeanPostProcessorの組み合わせで実現できるらしいので試してみた。

Bean定義ファイルに追加する内容

<bean id="entityManager"
class=
"org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

EntityManagerをインジェクトされる側

private EntityManager entityManager;
@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
インジェクトされる側に必要なのはアノテーションのみで、Bean定義ファイルに property定義をする必要はない模様。

以上で EntityManagerがインジェクトされてくるようになるのを確認できた。
それって本当にスレッドセーフなのか?という疑問が当然のごとく湧いてくるかと思うが、そのあたりは SharedEntityManagerBeanや AbstractEntityManagerFactoryBeanがうまくやっているに違いないと信じている。

とりあえず JPAのAPIを通じて進行中のトランザクションに干渉してみるのはどうだろう、と考え、entityManager.getTransaction().setRollbackOnly() を試してみたところ、あえなく拒否された(それは使えないから SpringのPlatformTransactionManagerを使え、といったメッセージで)。

OpenJPAでの注意事項


上記のようにしてインジェクトされてきたEntityManagerをトランザクションの外で使おうとすると OpenJPAが例外をスローする。
org.apache.openjpa.persistence.InvalidStateException: The context has been closed. The stack trace at which the context was closed is available if Runtime=TRACE logging is enabled.
従って、共有EntityManagerを使う際は宣言的もしくはプログラム的トランザクションの内側で行うこと。

ソースコードがSpring依存にならない Keep POJOな 宣言的トランザクション
ソースコードはSpring依存になるが細かい制御の可能なプログラム的トランザクション

なおOpenJPA以外のJPAプロバイダではどうなるか試していない。

ラベル: ,

2007-06-10

すぐに始める Struts2 (Mayaa編)

Eclipseを入れて、Subversionからソースをチェックアウトして、アプリケーションサーバを Runして、動作を見ながら JSPを書き換えてくれる HTMLライターさんなんて数えるほどしかいないのだよ、世の中には!

というわけで Struts2の画面表示をするにあたって JSPのかわりに Mayaa を使う方法を調べた。
Mayaaを私の理解している範囲で簡単に説明すると、IEや Firefoxでそのまま表示できてしまうようなごく普通の HTMLファイルが不思議と動的なページの表示に使えてしまうテンプレートエンジン(動的要素の定義はHTMLファイルの隣に mayaaファイルとして配置する)ということらしい。これだと HTMLライターとプログラマの協業が殴り合いも発生せずスムーズにいく(かもしれない)というわけ。
とはいえ Mayaaについてそれほど深く知らないので、ここではStruts2との統合についてだけ取り扱う。実際に思惑通りの使い方が出来るかどうかはこれから試してみる。

Struts2 Mayaa Plugun

このプラグインのサンプルには当然 struts.xmlでの設定方法が含まれているが、このブログでは struts.xmlなしでどこまで行けるかチャレンジすることになっているので(そうなの?)アノテーションだけで Mayaaを呼び出すことにした。

WEB-INF/lib に追加で入れたものは下記の通り。

commons-beanutils-core-1.7.0.jar
commons-collections-3.1.jar
jaxen-1.1.jar
js-1.6R5.jar
mayaa-1.1.10.jar
nekohtml-0.9.5.jar
struts2-mayaa-plugin-1.0.0.jar
xercesImpl-2.7.1.jar

web.xmlには下記の設定を追加。

<servlet>
<servlet-name>MayaaServlet</servlet-name>
<servlet-class>org.seasar.mayaa.impl.MayaaServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

MayaaServletを呼び出すことは無いのだが、load-on-startupでこれを自動ロードしておかないといくつかの内部コンポーネントが初期化されないという問題があるため設定を追加する必要がある。この servletに対する servlet-mappingは不要。

アクションクラスに対する Resultアノテーションは下記のようになる。Resultの typeが MayaaResult.classになり、valueが HTMLファイルを指す。

@Results({
@Result(name="success",type=MayaaResult.class,value="success.html"),
})

上記の例ではアクションが successを返したときに success.htmlと success.mayaa が処理される形になる。
HTMLファイルとmayaaファイルを表側から直接見られないように WEB-INFの下へ配置してみたところ、org.seasar.mayaa.impl.source.ForbiddenPathException: Access Forbidden to /WEB-INF/.... などと言われて読み込めなかった。これは何か設定で回避できるのかもしれないがまだ調べていない。というかGoogle Code Searchで Mayaaのソースが見つからなかった。(追記:WEB-INF/page 以下に HTMLファイルを置けることが判明、このパスは自動的に検索されるので、例えばWEB-INF/page/hoge.htmlを使用したい場合単に hoge.htmlと指定すれば良い )

ラベル:

すぐに始めるStruts2(フォームとバリデーション編)


相変わらず struts.xml無しでどこまで出来るかを検証中。
「できないこと」も色々(というか、かなり)あることがわかりつつあるが、ひとまずできるところまで紹介したい。
なお無設定運用の Struts2では、アクション名とアクションメソッド名の区切りを URL上で ! 文字を用いることで表現する(デフォルトのアクションメソッド名は execute)。
アクションクラスEmailActionの場合は、ブラウザから email!input.action がリクエストされると input() がコールされる。
単に email.action がリクエストされた場合は execute() がコールされる。

EmailAction.java

import org.apache.struts2.config.Result;
import org.apache.struts2.config.Results;

import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.validator.annotations.EmailValidator;
import com.opensymphony.xwork2.validator.annotations.RequiredStringValidator;
import com.opensymphony.xwork2.validator.annotations.ValidatorType;

@Results({
@Result(name="input",value="input.jsp"),
@Result(name="success",value="success.jsp")
})

public class EmailAction extends ActionSupport {

private static final long serialVersionUID = 1L;

private String email;

/**
* @return the email
*/

public String getEmail() {
return email;
}

/**
* @param email the email to set
*/

@EmailValidator(type = ValidatorType.FIELD,
message="メールアドレスが正しくない様です。")
@RequiredStringValidator(type = ValidatorType.FIELD,
message="メールアドレスを入力して下さい。")
public void setEmail(String email) {
this.email = email;
}

public String input()
{
// フォームの初期値設定などをここでする。不要な場合はこのメソッド自体省略しても良い
// (ActionSupport#input()で { return "input" } が実装されているから)
return "input";
}

public String execute()
{
// バリデーションが通過したのちにこのメソッドがコールされる。
// ここでユーザの入力内容をデータベースに保存するなどの処理をする

return "success";
}

}

input.jsp

<%@page contentType="text/html;charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<s:head/>
</head>
<body>
<h1>アドレスを追加する</h1>

<s:actionerror />
<s:form>
<%-- s:textfieldのようなUIタグを使うとバリデーションエラーが自動で表示される --%>
<s:textfield label="メールアドレス" name="email"/>
<s:submit />
</s:form>

</body>
</html>

フォームに表示すべきエラーにはアクションエラーとフィールドエラーがある。
フィールドエラー(メールアドレスが正しくありません、など)は UIコンポーネントと
共に自動的に表示されるが、アクションエラー(特定のフィールドに属さないエラー)は
明示的に <s:actionerror/>タグで表示場所を指定する必要がある。もしあればだが。

参考リンク

Apache Struts 2 Documentationより
Annotations
Struts Tags
Class ActionSupport

サンプルアプリケーションの中に収録されているなかなか役に立つ文書
A Walking Tour of the Struts 2 MailReader Application

ラベル:

ちょっと便利なOGNL式

JSPを書くときに OGNL式が便利だと思った例。

JSTL+EL式の場合

性別:
<c:if test="${sex==1}">男性</c:if>
<c:if test="${sex==2}">女性</c:if>
<c:if test="${sex==3}">その他</c:if>

Struts2 Taglib+OGNL式の場合

性別:
<s:property value="#{1:'男性',2:'女性',3:'その他'}[sex]"/>


OGNLでは#{...} 式を使うことによってその場で Mapオブジェクトを生成出来るので、上記のように定数に対応するラベルを表示したい(しかも内容的にマスタを持って管理するほどでもない)場合に記述が短くできる。

ラベル:

ブログに載せるプログラムコードや設定ファイルをenscriptでHTMLに整形する

enscript -o - --language=html

で、標準入力からテキストを読み込み、HTMLに整形して標準出力へ出力してくれる。

さらに、--color --highlight=xxxxを付けるとハイライトもしてくれる(配色のセンスについてはともかく)
xxxxの部分は HTMLやXMLなら html を指定する。
他には awkだのcだのcppだのdiffだのdelphiだのhaskellだのjavaだのjavascriptだのmakefileだのperlだのpythonだのsqlだのが指定できる。詳しくは enscript --help-highlight で見れる。

追記:Mac OS X(Darwin 8.9.1)に enscriptが標準で入っていた。素晴らしいね。但しハイライトの指定が --highlight=xxxxじゃなくて --pretty-print=xxxx だった。

追記その2:Gentoo Linuxでは USEフラグに ruby を追加してあると Ruby highlightingが可能な enscriptがインストール出来る。

すぐにTomcatのJNDI DataSourceを設定する

server.xmlと同じディレクトリにある context.xmlの中に

<Resource
name=
"jdbc/MyDB"
auth=
"Container"
type=
"javax.sql.DataSource"
factory=
"org.apache.commons.dbcp.BasicDataSourceFactory"
username=
"scott"
password=
"tiger"
driverClassName=
"org.postgresql.Driver"
url=
"jdbc:postgresql://localhost/mydb"/>

のように書くと、全てのコンテキストから利用できるデータソースが定義できる。(例は PostgreSQL)

Spring JDBCとPostgreSQLでSqlRowSet使用時にエラー

Spring-JDBCとPostgreSQLを組み合わせているときに、JdbcTemplate#queryForRowSet()など SqlRowSetを使うファンクションで "Invalid column display size. Cannot be less than zero"なる SQLExceptionが出る場合、PostgreSQLの JDBCドライバが古いので最新版に差し替えれば直る。

ラベル:

2007-06-05

Oracle用の DataSourceをすぐに作る

あなたは、Oracleデータベースにアクセスする、とあるビジネスコンポーネントを Javaで製造することを命じられました。
コンポーネントには DataSourceオブジェクトがあらかじめインジェクトされることが前提になっているので、あなたは各ビジネスメソッドの中でその DataSourceからデータベース・コネクションを取得し、クエリを実行したのち、正しくコネクションを解放して制御を戻せば良いことになっています。
トランザクションの境界については、フレームワーク側で定義するため意識する必要がないとのことです。

さて、あなたは JDBCを使って目的のクエリを行うコードを書きました。簡単です。しかし、ユニットテストをしなければこのコードが要求仕様を満たしているという保証ができません。ではこのコンポーネントをユニットテストしましょう。
ユニットテストを行うためには、接続先のデータベースが必要です。幸い、開発用のOracleデータベースは用意されています。

しかしながら、結合時にはフレームワークにより自動的にインジェクトされることになっているこの DataSourceも、ユニットテストの時には自分で作成してテスト対象のオブジェクトにインジェクトしてやらなければいけません。
しょうがないのであなたは JavaDoc で、javax.sql.DataSource調べます。
「なんてことだ!こいつはインターフェイスだ!インスタンスを作りたくても new できないじゃないか!」

OracleのJDBCドライバアーカイヴには OracleDataSource という DataSourceの実装が含まれていますので、これを使いましょう。

import oracle.jdbc.pool.OracleDataSource;
:
OracleDataSource ds = new OracleDataSource( );
ds.setUser("scott");
ds.setPassword("tiger");
ds.setURL("jdbc:oracle:thin:@//dbHost/service_name");
// テスト対象オブジェクトに ds をインジェクトする

むろん、これは Oracle専用の DataSource実装です。データベース非依存の DataSource実装を使っておきたければ SpringのSingleConnectionDataSourceあたりを使うと良いでしょう。

ラベル:

スタンドアロン動作中のWebアプリケーションでJNDI DataSourceを利用可能にする

以前、Jettyを使ってWebアプリケーションをスタンドアロン動作可能にするというエントリを書いた。Webアプリケーションの開発を行うさいに面倒なもののひとつに、開発チーム全員に Webアプリケーションサーバの設定を伝播するこいうものがある。Tomcatをダウンロード・展開して、Eclipseのなんとかプラグインを差し込んで、server.xmlを設定して・・・環境設定マニアならどうか知らないが、ソフトウェアアーキテクトの立場からすると、これをレクチャするというのははっきりいって何の価値も生まない作業だ。設定や操作の方法を教えるのは せいぜいSubversionだけにしたい。

ならばアプリケーションサーバもプロジェクトの一部として Subversionのリポジトリに入れてしまおう。最終成果物たる warファイルにはアプリケーション本体のみ入れるよう build.xmlを書けば良いだけの話だ。というわけで Jettyのそのような利用法を考えた次第。

方法は件のエントリを読んで貰えばいいとして、その時は JNDIのことを後回しにしていた。J2EEのきまりでは、アプリケーションがJDBC接続を得るためのデータソースはいちおう JNDIを参照して取得することになっているので(最近はDIコンテナ管理下のものを使うことも多いと思うが)、いちおう対応しておかなくてはなるまい。Jettyの JNDIを有効にするには jetty-naming-6.1.3.jar をクラスパスに追加する。

JNDIにデータソースをバインドするには、下記のようにする。(むろん、org.mortbay.jetty.Server#startを呼ぶ前に)
データソースの実装は、SpringのSingleConnectionDataSourceでも使えば良いだろう。例は Microsoft SQL Serverに接続するための設定となっている。
String dbHost = "MyDBHostForDevelopment";
String dbName = "MyDB"
String userName = "sa";
String password = "secret";
String dataSourceName = "MyDB";
SingleConnectionDataSource ds = new SingleConnectionDataSource();
ds.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
ds.setUrl("jdbc:sqlserver://" + dbHost
+ "\\SQLEXPRESS;DatabaseName=" + dbName
+ ";SelectMethod=cursor");
ds.setUsername(userName);
ds.setPassword(password);
ds.setSuppressClose(true);
((Context)(new InitialContext().lookup("java:/comp")))
.createSubcontext("env").createSubcontext("jdbc").bind(dataSourceName, ds);
これで Webアプリケーションからは java:/comp/env/jdbc/MyDB としてデータソースを参照できる。

上記はあくまで、各個人の開発端末上で作業を行うためのコードであって、いわばアプリケーションサーバの設定ファイルにかわるものにすぎない。くれぐれも Webアプリケーションの”中に”このようなコードを書き入れないようにお願いしたい。

すぐに始める Struts2 (フォームでの日付入力編)


Struts2の Taglibには JavaScript+CSSで出来たリッチなUIコンポーネントが収録されている(DoJo Toolkitなるライブラリを使っているらしい)。今回は s:datetimepicker タグを使い、リッチなUIで日付の入力が可能なフォームを作ってみる。通常だと、フォームからの日付入力を受け取るには文字列型で入力→アクションクラス側でパースしてDate型変数に代入という手順を踏むところだが、この例では直接 java.util.Date型のプロパティにユーザの入力した日付がセットされる。

アクションクラス

この例では、フォームの表示と submitに一つのアクションクラスを使い回している

package yourpackage;

@Results({
@Result(name="success",value="dateinput.jsp")
}
)
public class DateInputAction {
/**
* Date型プロパティ。デフォルトでは newしたDateオブジェクト(現在時刻をさす)
* をセットする。
*/

private java.util.Date date = new java.util.Date();

/**
* この例では、日付入力ボックスの初期値表示時に呼び出される
*/

public java.util.Date getDate() {
return date;
}

/**
* フォームのsubmit時、日付入力ボックスの内容がここに渡される
*/

public void setDate(java.util.Date date) {
this.date = date;
}

public String execute()
{
return "success";
}
}

フォームJSP

<%@page contentType="text/html;charset=UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<s:head/>
</head>
<body>
<h1>日付入力のデモ</h1>
<s:form>
<s:datetimepicker
label=
"日付を選択してください"
displayFormat=
"yyyy/MM/dd"
name=
"date"/>
<s:submit />
</s:form>
</body>
</html>

解説

Struts2の組み込まれたWebアプリケーションのコンテキストでは、/struts 以下の URIに CSSや DoJoのようなJavaScriptといったリソースが自動的に配備されている。例えばコンテキスト名が myapp の場合、URL的には http://yourhost:port/myapp/struts/ 以下がそれにあたる。
HTMLの head要素内に <s:head/> というタグを書いておくことで、それらの呼び出しに必要なスクリプト等が挿入される。(言い方を変えると、これを書いておかないと s:datetimepickerのような リッチUIタグが動作しない)

struts1からの流儀だが、フォームUIタグの name属性に指定された名前は HTML要素の name属性として用いられると同時に、アクションクラス(Struts1の場合フォームBean)のプロパティ名に直接対応づけられ初期表示時にその値が用いられる。この例では s:datetimepickerが name="date"属性によりアクションクラスの dateプロパティと関連づけられている。

なお、action属性の省略された s:form要素はこのページを表示したアクション自身に対してsubmitされる。

ラベル: