slim3 f:dateでorg.slim3.struts.taglib.S2Functions?

簡単な登録 → 完了という画面を作っています。

その中で、SAStrutsの記事を色々とみていると、かなり便利そうな機能が多いので、早速日付とか数値をfmt:format〜で試してみました。

しかし、日付の指定をすると、タイトルのようにS2Functionsと出ています、ソースを見ると、S3Functionsとなっています。
ひとまず、普通に ${f:h(applyDate)} と書きます。

JSP

<Error>
2009-04-21 07:25:07.479::WARN: /register/
org.apache.jasper.JasperException: TLDの中で関数 f:date に指定されているクラス org.slim3.struts.taglib.S2Functions が見つかりません: org.slim3.struts.taglib.S2Functions
at org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:50)
at org.apache.jasper.compiler.ErrorDispatcher.dispatch(ErrorDispatcher.java:411)
at org.apache.jasper.compiler.ErrorDispatcher.jspError(ErrorDispatcher.java:183)
at org.apache.jasper.compiler.Validator$1MapperELVisitor.visit(Validator.java:1349)
at org.apache.jasper.compiler.ELNode$Function.accept(ELNode.java:122)
at org.apache.jasper.compiler.ELNode$Nodes.visit(ELNode.java:193)
at org.apache.jasper.compiler.ELNode$Visitor.visit(ELNode.java:234)
at org.apache.jasper.compiler.ELNode$Root.accept(ELNode.java:53)
at org.apache.jasper.compiler.ELNode$Nodes.visit(ELNode.java:193)
at org.apache.jasper.compiler.Validator$ValidateVisitor.getFunctionMapper(Validator.java:1380)
at org.apache.jasper.compiler.Validator$ValidateVisitor.getJspAttribute(Validator.java:1098)
at org.apache.jasper.compiler.Validator$ValidateVisitor.checkXmlAttributes(Validator.java:923)
at org.apache.jasper.compiler.Validator$ValidateVisitor.visit(Validator.java:696)
at org.apache.jasper.compiler.Node$CustomTag.accept(Node.java:1441)
at org.apache.jasper.compiler.Node$Nodes.visit(Node.java:2163)
at org.apache.jasper.compiler.Node$Visitor.visitBody(Node.java:2213)
at org.apache.jasper.compiler.Validator$ValidateVisitor.visit(Validator.java:716)
at org.apache.jasper.compiler.Node$CustomTag.accept(Node.java:1441)
at org.apache.jasper.compiler.Node$Nodes.visit(Node.java:2163)
at org.apache.jasper.compiler.Node$Visitor.visitBody(Node.java:2213)
at org.apache.jasper.compiler.Node$Visitor.visit(Node.java:2219)
at org.apache.jasper.compiler.Node$Root.accept(Node.java:456)
at org.apache.jasper.compiler.Node$Nodes.visit(Node.java:2163)
at org.apache.jasper.compiler.Validator.validate(Validator.java:1475)
at org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:214)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:470)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:451)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:439)
at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:511)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:295)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:292)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:236)
at com.google.appengine.tools.development.PrivilegedJspServlet.access$101(PrivilegedJspServlet.java:23)
at com.google.appengine.tools.development.PrivilegedJspServlet$2.run(PrivilegedJspServlet.java:59)
at java.security.AccessController.doPrivileged(Native Method)
at com.google.appengine.tools.development.PrivilegedJspServlet.service(PrivilegedJspServlet.java:57)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
at org.slim3.struts.web.S3StrutsFilter.doFilter(S3StrutsFilter.java:100)
at org.slim3.struts.web.S3StrutsFilter.doFilter(S3StrutsFilter.java:72)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:54)
at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:268)
at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:126)
at org.apache.struts.action.RequestProcessor.doForward(RequestProcessor.java:1085)
at org.slim3.struts.action.S3RequestProcessor.processForwardConfig(S3RequestProcessor.java:473)
at org.slim3.struts.action.S3RequestProcessor.process(S3RequestProcessor.java:138)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1196)
at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:713)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
at org.slim3.struts.web.S3StrutsFilter.doFilter(S3StrutsFilter.java:100)
at org.slim3.struts.web.S3StrutsFilter.doFilter(S3StrutsFilter.java:72)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:54)
at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:268)
at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:126)
at org.slim3.struts.web.RoutingFilter.doFilter(RoutingFilter.java:102)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.slim3.struts.web.S3StrutsFilter.doFilter(S3StrutsFilter.java:100)
at org.slim3.struts.web.S3StrutsFilter.doFilter(S3StrutsFilter.java:72)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:54)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:306)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at org.mortbay.jetty.Server.handle(Server.java:313)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:506)
at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:844)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:644)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:381)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:396)
at org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:442)

久しぶりのブログ

2ヶ月間、ずっと放置状態でした。。。
そもそも、最近は忙しさと暇の波が激しすぎです。

2月、3月はオフショア開発をしており、睡眠3時間以内での生活が続いていましたので、ブログを書いている時間が全くなかったです。

4月になると今度は今いる所にほぼ仕事がなく、ひじょーに暇です。毎日ネットサーフィンしながら、夜家でやりたい事を探しています。

最近はやはり クラウド がブームですね。私も業務でプライベートクラウドを導入するという話の提案書を書いています。

しかし、これはあくまでもインフラのお話です。私はプラットフォームで動くアプリを作る人なので、アプリで面白そうな物が、、、と思っていましたら、Google App Engineがありました。

さらに、Pythonだけの対応から、Javaの対応も加わり、Javaが公開された後、色々な人のブログを見ると、どのぐらい動くのかという所を書いたブログがひじょーに多いです。

私もPythonでは既にとあるアプリを作り、焼き直しをJavaで、 かつ slim3 で試してみようと思います、SAStrutsを調べて、少し作ったとき、これはいいなぁ、と思いましたので、早速作っていきます。おまけに、今日JJUGでひがさんがプレゼンをするので、ちょうどよいタイミングかもしれないです。

Entity+Namesの影響はないです。

早速、テストコードを書いてみました。
メソッド名をコメントにしている理由は、まずは普通に実行し、テーブルに値が入るのを確認した後、テーブルに値を入らないようにする為です。

    public void testInsert() throws Exception {
    //public void testInsertTx() throws Exception {
    	SCompany entity = new SCompany();
    	entity.version = 1;
    	entity.name = "スラムダンク";
    	entity.address = "神奈川県だよーん";
    	entity.telephone = "045-9999-0000";
    	Date  date = DateFormat.getDateInstance().parse("2009/02/09");
    	entity.insertDate = date;
    	int expected = sCompanyService.insert(entity);
    	assertEquals(expected, 1);
    }

今までと同様のテストコードをそのまま適応する事ができます。
Entity+Namesのクラスですが、上記のテストを実行した所、Eclipseのプロジェクトに出現しました。。。お化けみたいな表現ですが、Eclipse上にて更新ボタンを押しても、何回もでなかったのですが、テストを実行すると、出てきました。。。


上記の作成したEntityは、Ctrlキーを押しながら、クリックすると、作成したEntityが出てきますが、Entityパッケージ以下をみると、Entity+Namesしかないですね。


前回は、VersionはInteger型を使っておりましたが、実行する前にint型に直すように怒られました。。。ほかのクラスも全てIntegerにしていたので、intに一括置換したいのですが、1つずつテストをしながら、なおしていきます。classes以下には作成したEntityは.classにてあります。


結論から言いますと、今までと同様の事ができますので、さくさく進めていきたいと思います。

久しぶりにS2JDBC-Genを実行

ようやくとある仕事が終わり、SAStrutsS2JDBCS2JDBC-Genを使用したプロジェクトを始めることができるようになりました。
この間、ブログとかも、ほとんどみている時間がありませんでした。。。朝4時に起きて、日が変わった1時に寝ていましたので。もちろん、更新も。。。すいません。


一番大きな事は、1/31に新しいバージョンがリリースされていましたので、早速ダウンロードして、新しいお仕事のプロジェクトで試しました。


もちろん、Entityを一番最初に作成します。


新しいバージョンになり、一番驚いたことは、スピードです。私のマシーンの影響かもしれないですが、今まで5個のEntityで1分かかっていましたが、倍のEntityを作成しても、処理時間は半分以下になっています。実行中、のんびり水を飲んでいる時間がなくなりました。


以前はテーブルを先に作成していましたので、実行後、EntityとEntity+Namesのクラスが作成されていました。プロジェクト作成後、今回初めてEntityを作成し、DDLを作成する手順を実行すると、Entity+Namesのクラスが作成されないですね。
以前はEntityを作成すると、自然にEntity+Namesのクラスが作成されていたので。設定かなぁ?と。
スキーマは1つですので、コメントを毎回書き込める以外はまだ何も編集はしていないです。


Entityから作成してみますと、10個のEntityを作成し、DDLをテーブルに反映するという作業は1時間もあれば、できる作業になります。非常に短時間での実行が可能です。

VAIO TypeP

ついに、TypePを買いました。もちろん、SonyStyleでカスタマイズをして、10万円でした。

・HDDの4200回転はおそすぎてありえない。
 グレードを上げました。
・LANケースブル、モニターの表示はむしろ必須
・CPUはSonyStyleで真ん中のスペックです。

最小構成からみると、2万円アップですが、最小構成では
つかいものにならないので、仕方ないです。

 しかし、ものがくるのは1カ月先です。遅い!!!

忙しさ制御不能

2週間ほど、全くブログが書けない状況でした。。。
この2週間の間にした事を書いてみますと、

・とある案件の調査にて、ひたすらJavaでテストケースを書く
 40ケースは書きましたね。
リファクタリングを行う、エンジニアとして誰もが最後には
 行いますが。

TERASOLUNAの調査、これって使えるの?と。
 バッチ系の案件で、Seasar2系ではなかったので、上記の
 フレームワークを見つけ、調べました。
・とある会社が作成したフレームワークでエラーが発生し、
 エラーの発生原因の調査(もちろん案件の仕様はしりません)

・とある案件でSpryを使って、モックアップの作成
 これは楽しかったです、Spryを評価する事ができましたし、
 面白い動きができ、使える、と思っています。
 このモックはHTMLですが、JSPに変え、SAStruts+S2JDBC+S2JDBCGen
 で開発を来月より進めていきます(明後日から)。。。

 しかし、Spryはブラウザーにより、あまりにも違いすぎです。
 Firefoxの方が良いですが、社内IE統一ですので、仕方なく
 IEに合わせています。

・とある会社より、海外で作成されたツールの日本語化を実施、
 かつ日本語変換後の確認まで含めて

・とあるオフショア会社より、向こうが作成した要件定義・
 スケジュールの確認・レビュー

・とあるオフショア開発に対して、自社で今後使用したい
 ツールの作成を依頼する為、要件定義書をかきました。
 そして、オフショア会社からの質疑応答を行う。

しかし、こうしてみると、一体いくつ仕事をかけているのだろうか?と自分でもビックリです。
が、来月からは、やっとSeasar2プロダクトを使って、開発に専念できそうです、結構大きい案件で、かつ1人で作りますが(笑)。

S2JDBC-Genでの履歴の出力

現在、私の環境では2つのスキーマを用意し、調査をしています。
マイグレーションを実行する時、現在は両方の変更を1箇所にて
管理するという考えでいました。
理由はS2JDBC-Genを実行する時、両方のDDLを出力しているので、
1箇所に履歴が出力されれば問題ないのでは、という事です。

調査を兼ねて、それぞれのスキーマ毎に履歴を出力したいと
思います(予め言いますが、下記の設定を行いましたが、
うまく出力されませんでした)。。。

1つ目のスキーマ

最初に入力を要求するポップアップの画面を表示します。

 <input message="対応した内容を記述してください。1" addproperty="gen-ddl.comment">
 </input>


次に、上記の設定時に入力した値とつなげるコメントを設定します。

 <target name="gen-ddl">
  <gen-ddl
    classpathdir="${classpathdir}"
    rootpackagename="${rootpackagename}"
    entitypackagename="${entitypackagename}"
    env="${env}"
      comment="${gen-ddl.comment}"
      jdbcmanagername="printjdbcManager"
      autogenerateforeignkey="false"
    classpathref="classpath"
  />
 </target>


最後にマイグレーションに出力先を設定します。

 <target name="migrate">
  <migrate
    classpathdir="${classpathdir}"
    rootpackagename="${rootpackagename}"
    entitypackagename="${entitypackagename}"
    applyenvtoversion="${applyenvtoversion}"
    version="${version}"
    env="${env}"
      jdbcmanagername="printjdbcManager"
      ddlinfofile="db/ddl-info.txt"
      migratedir="db/migrate"
    classpathref="classpath"
  />
  <refresh projectName="BusinessFlow"/>
 </target>


2つめのスキーマ情報は以下の通りです。

最初に入力を要求するポップアップの画面を表示します。
ここでは1つめのスキーマと区別する為に、「2」を追加します。

 <input message="対応した内容を記述してください。1" addproperty="gen-ddl2.comment">
 </input>


次に、上記の設定時に入力した値とつなげるコメントを設定します。ここでは1つめのスキーマと区別する為に、「2」を追加します。

 <target name="gen-ddl2">
  <gen-ddl
    classpathdir="${classpathdir}"
    rootpackagename="${rootpackagename}"
    entitypackagename="${entitypackagename}"
    env="${env}"
      comment="${gen-ddl2.comment}"
      jdbcmanagername="screenjdbcManager"
      autogenerateforeignkey="false"
    classpathref="classpath"
  />
 </target>


最後にマイグレーションに出力先を設定します。

 <target name="migrate2">
  <migrate
    classpathdir="${classpathdir}"
    rootpackagename="${rootpackagename}"
    entitypackagename="${entitypackagename}"
    applyenvtoversion="${applyenvtoversion}"
    version="${version}"
    env="${env}"
      jdbcmanagername="screenjdbcManager"
      ddlinfofile="db/ddl-info2.txt"
      migratedir="db/migrate2"
    classpathref="classpath"
  />
  <refresh projectName="BusinessFlow"/>
 </target>


上記の設定を行い、実行します。
実行後、入力を求める画面が2回表示されます。そして、2回共に何かの値を入れます。
実行結果は、1つ目のスキーマの履歴は問題ありませんでしたが、2つ目のスキーマは何も起きていないようでした。

先にディレクトリやファイルが存在しないといけないのでは、と思い、ddlinfofileとmigratedirのファイル・ディレクトリーを作成し、実行しました。
ちなみに、最初に実行した時、上記のファイル・ディレクトリーは作成していません。

実行した結果、何も変わった様子がありませんでした。
ちなみに、DDLは作成してほしいディレクトリーではなく、元のディレクトリーに作成されています。
最初に設定していますPropertyタグの中身を見る限りでは、DDLを出力する上で影響がある所はないのではないか、と思います。

<property name="classpathdir" value="src/main/webapp/WEB-INF/classes"/>
 <property name="rootpackagename" value="jp.globalsystems.businessflow"/>
 <property name="entitypackagename" value="entity"/>
 <property name="entityfilepattern"
value="jp/globalsystems/businessflow/entity/**/*.java"/>
 <property name="javafiledestdir" value="src/main/java"/>
 <property name="testjavafiledestdir" value="src/test/java"/>
 <property name="javafileencoding" value="UTF-8"/>
 <property name="version" value="latest"/>
 <property name="sqlfilepattern" value="META-INF/sql/**/*.sql"/>
 <property name="applyenvtoversion" value="false"/>
 <property name="uses2junit4" value="false"/>
 <property name="env" value="ut"/>


ひょっとすると、ddlinfofileの指定先のテキストファイルが現在はブランクなっている為、値を入れておかないといけないのでは、と思い、1つ目のスキーマの履歴情報をそのままコピーし、再度実行してみましたが、だめでした。。。

migrateタグの所に今はddlinfofileとmigratedirを設定しています。この両方の属性はgen-ddlタグの所にも設定ができますので、こちらに移してみましたが、同様の結果の上、今度は何も履歴に出力されなくなりました。。。

両方に設定できる、という事は恐らく何か意味があるのではないか、と思っています。
実はここでとまってしまい、それぞれではなく一元管理でもいいのではないか、一元管理でも開発は進められる、という判断をし、前日の一元管理の履歴管理になりました。