2008年9月9日火曜日

wicket-seam連携をjetty上で!(暫定版)

前回のwicket-seam関連エントリで書いた手順は忘れて下さい、無かったことにして下さい

あの方法ではSeam自体は起動しているモノの、WicketのWebPage等がSeamの管理下に入っていません。そのあたりを見ていて、自分なりにわかってきた事をまず書き留めておくとします。
  • SeamがWicketのComponentを自動登録する際には、「WEB-INF/wicket」直下の*.classをscanする。パス固定。めっちゃ固定。ちなみに、この「WEB-INF/wicket」については「org.jboss.seam.wicket.ioc.JavassistInstrumentor」で「public static String DEFAULT_WICKET_COMPONENT_DIRECTORY_PATH = "WEB-INF/wicket";」というカンジで定義されている。
  • 起動がめっちゃ遅いJBossASを使わずとも、Eclipse+run-Jetty-run pluginでイケる。
  • つまり、Eclipse+WTPを使う必要はなく、Eclipse for JEEでなくても良い。上記と会わせたこの2点で相当軽量化した環境で開発できる。

JBossASとEclipseWTP+αで満足な人

上に書いたように、Wicket用のPageクラス等の出力先をWEB-INF/wicketにしておけば、すんなり動作すると思います。ここから下は見る必要がありません。ややこしぃだけなので、むしろ見てはいけません。

なんとか動かしてみた

しかし、上記に書いた問題をなんとかクリアすればSeamによるWicket用Componentの読み込み等の動作も確認できました。SeamビルトインのComponentのInjectも正しく動作します。
まずはwicket-archetype-quickstartでprojectを作成
ここはいつも通り。
pom.xml
一気に以下に書き換える。Jettyで実行するので、JavaEE系を追加するためJBossのモジュールを借りまくる。この例の場合はjetty-maven-pluginのclassesDirectory,webAppSourceDirectoryをtarget/classesに向けている。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.shin1o</groupId>
  <artifactId>com.shin1o.wicketSeam01</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>wicketSeam01</name>
  <description></description>
  <licenses>
    <license>
      <name>The Apache Software License, Version 2.0</name>
      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
      <distribution>repo</distribution>
    </license>
  </licenses>
  <dependencies>
    <!--  WICKET DEPENDENCIES -->
    <dependency>
      <groupId>org.apache.wicket</groupId>
      <artifactId>wicket</artifactId>
      <version>${wicket.version}</version>
    </dependency>

    <!-- LOGGING DEPENDENCIES - LOG4J -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.4.2</version>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.14</version>
    </dependency>

    <!--  JUNIT DEPENDENCY FOR TESTING -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.2</version>
      <scope>test</scope>
    </dependency>

    <!--  JETTY DEPENDENCIES FOR TESTING  -->
    <dependency>
      <groupId>org.mortbay.jetty</groupId>
      <artifactId>jetty</artifactId>
      <version>${jetty.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.mortbay.jetty</groupId>
      <artifactId>jetty-util</artifactId>
      <version>${jetty.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.mortbay.jetty</groupId>
      <artifactId>jetty-management</artifactId>
      <version>${jetty.version}</version>
      <scope>provided</scope>
    </dependency>

    <!-- seam-wicket -->
    <dependency>
      <groupId>org.jboss.seam</groupId>
      <artifactId>jboss-seam</artifactId>
      <version>2.1.0.BETA1</version>
    </dependency>
    <dependency>
      <groupId>org.jboss.seam</groupId>
      <artifactId>jboss-seam-wicket</artifactId>
      <version>2.1.0.BETA1</version>
    </dependency>
    <dependency>
      <groupId>org.jboss.seam</groupId>
      <artifactId>jboss-seam-debug</artifactId>
      <version>2.1.0.BETA1</version>
    </dependency>
    <dependency>
      <groupId>org.jboss.seam</groupId>
      <artifactId>jboss-seam-ioc</artifactId>
      <version>2.1.0.BETA1</version>
    </dependency>
    <!-- JSF(使わないけどSeamの起動に必要) -->
    <dependency>
      <groupId>javax.faces</groupId>
      <artifactId>jsf-api</artifactId>
      <version>1.2_02</version>
    </dependency>
    <!-- EJB3 -->
    <dependency>
      <groupId>javax.ejb</groupId>
      <artifactId>ejb-api</artifactId>
      <version>3.0</version>
    </dependency>
    <!-- JPA -->
    <dependency>
      <groupId>javax.persistence</groupId>
      <artifactId>persistence-api</artifactId>
      <version>1.0</version>
    </dependency>
    <!-- JTA -->
    <dependency>
      <groupId>javax.transaction</groupId>
      <artifactId>jta</artifactId>
      <version>1.0.1B</version>
    </dependency>
    <!-- hibernate validator(使わないけどSeamの起動に必要?) -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>3.0.0.ga</version>
    </dependency>
  </dependencies>
  <build>
    <resources>
      <resource>
        <filtering>false</filtering>
        <directory>src/main/resources</directory>
      </resource>
      <resource>
        <filtering>false</filtering>
        <directory>src/main/java</directory>
        <includes>
          <include>**</include>
        </includes>
        <excludes>
          <exclude>**/*.java</exclude>
        </excludes>
      </resource>
    </resources>
    <testResources>
      <testResource>
        <filtering>false</filtering>
        <directory>src/test/java</directory>
        <includes>
          <include>**</include>
        </includes>
        <excludes>
          <exclude>**/*.java</exclude>
        </excludes>
      </testResource>
    </testResources>
    <plugins>
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>maven-jetty-plugin</artifactId>
        <configuration>
          <classesDirectory>${project.build.directory}/classes</classesDirectory>
          <webAppSourceDirectory>${project.build.directory}/classes</webAppSourceDirectory>
          <contextPath>/${artifactId}</contextPath>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-eclipse-plugin</artifactId>
        <configuration>
          <downloadSources>true</downloadSources>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <properties>
    <wicket.version>1.3.4</wicket.version>
    <jetty.version>6.1.4</jetty.version>
  </properties>
  <repositories>
    <repository>
      <id>repository.jboss.org</id>
      <name>JBoss Repository</name>
      <url>http://repository.jboss.org/maven2</url>
    </repository>
  </repositories>
</project>
Seam用の各種xmlの準備と「WEB-INF/wicket」の問題
単純に考えると、みっつの解決策があります。
  1. 素直に、src/main/webapp/WEB-INF/wicketを出力フォルダにする。
  2. Seamが起動するよりも速いタイミングで、org.jboss.seam.wicket.ioc.JavassistInstrumentor#DEFAULT_WICKET_COMPONENT_DIRECTORY_PATHの値を書き換える。
  3. 最も美しく無いなやり方だが、とりあえず簡単な方法が、org.jboss.seam.wicket.ioc.JavassistInstrumentorをコピーして自分のソースとして配置。DEFAULT_WICKET_COMPONENT_DIRECTORY_PATHの値を"target/classes"にしてしまう。
自分の場合は、出力フォルダはtarget配下じゃないとイヤだし、最も早いタイミング=ServletContextListenerを実装して登録する?くらいしか思いつかないし、余計なもんも作りたく無い。なので、とりあえず最後の方法で動作させています。それに伴い「WEB-INF」フォルダは「src/main/webapp」から「src/main/resources」の下に移動する必要があります(後の手順でrun-jetty-runプラグインのwebapp dirでtarget/classesを指定するため、その直下にWEB-INFが配置される必要がある)。
WEB-INF/web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app id="WebApp_ID" 
  version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
 <display-name>
 com.shin1o.wicketSeam01</display-name>
 <listener>
  <listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
 </listener>
 <filter>
  <filter-name>Seam Filter</filter-name>
  <filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>
 </filter>
 <filter-mapping>
  <filter-name>Seam Filter</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>
</web-app>
component.xml
WEB-INFフォルダ直下に以下のようなcomponent.xmlを作成しておく必要があります。
<?xml version="1.0" encoding="UTF-8"?>
<components xmlns="http://jboss.com/products/seam/components"
            xmlns:wicket="http://jboss.com/products/seam/wicket"
            xmlns:core="http://jboss.com/products/seam/core"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation=
                "http://jboss.com/products/seam/core http://jboss.com/products/seam/core-2.1.xsd
                 http://jboss.com/products/seam/wicket http://jboss.com/products/seam/wicket-2.1.xsd
                 http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.1.xsd">
 <core:init jndi-pattern="#{ejbName}/local" debug="true" />
    <wicket:web-application application-class="com.shin1o.WicketApplication" />
</components>
Eclipseのプロジェクトを作成、インポート
mvn eclipse:eclipse -DdownloadSources=trueで。私と同じ対応の場合はJavassistInstrumentorをコピーして上書きしちゃうので、ソースは必須です。project生成後はEclipseからインポート。
JavassistInstrumentorを書き換え
ソースフォルダに「org.jboss.seam.wicket.ioc」パッケージを作成し、JavassistInstrumentorをjboss-seam-wicket-2.1.0-BETA.jarに関連づけられたソースからコピーします。で、私の場合はDEFAULT_WICKET_COMPONENT_DIRECTORY_PATHの値を""、つまり空文字=webappとして認識するフォルダのルート、としました。
run-jetty-runによる実行の構成
自分の場合は実行の構成で指定する「webapp dir」をデフォルトの"src/main/webapp"から"target/classes"にしました。
実行
run-jetty-runから実行させても良いし、mvn jetty:runしてもおk。上にある手順やpom.xmlは全て「target/classes」をwebappのフォルダ&SeamのWicket用Component読み込みフォルダ、とした場合の話です。このあたりのフォルダの構成を変えるのであれば色々触る必要があります。
ビルトインのComponentをInjectしてみる
HomePage.java等に、以下のようなコードを書いてみる。
  @In
  private Identity identity;

  @Logger
  private Log log;
コンストラクタあたりでこいつらの値を参照すると、ちゃんとSeamからInjectされるのが確認できるはずです。

さらなる課題

  • 現状は、ビルトインのComponentは利用できているが、WicketのWebPageやWebPanel(Wicket用Componentと総称する)ではない自前のComponent(Logic用Componentと総称する)は、Wicket用Componentとは別の出力フォルダに出力されてくれないと困る。これら2種類をごっちゃに出力していると、SeamがなんでもかんでもWicket用Componentとしてドンドン登録してしまうよぅな動作に見える。
    • Wicket用ComponentとLogic用Componentでソースフォルダ、出力フォルダを分ける?mavenでそんな事できるっけ?(特にmaven-jetty-pluginの動作が気になる)
    • Wicket用ComponentとLogic用Componentでプロジェクトを分ける?その場合はSeamがどんな動作をするだろぅか?
    これはどーしたもんかなぁ?
そんなこんなで、この手順も暫定版です。だから、後で「無かった事に…」とするかもしれませぬ。

コメントを投稿