Oct 31, 2005
[Maven] Cruise Control と Maven2 を連携させたい
Maven2 で管理しているプロジェクトを Cruise Control と連携させたいのだが、残念なことに最新の Cruise Control 2.3.1 でも未だ Maven2 には対応していないみたい。
仕方がないので、Cruise Control 用の Maven2Builder Plugin を作ってみた。 作ってみたと言っても、Maven 1.x 用の Builder をちょっと変えただけなのだけれども。
またもやお約束ですが、この Plugin を利用して何らかの不利益を被ったとしても一切補償はできません。 SCM などできちんと管理されたソースコードで試行して品質をご自身で判断してからご利用ください。
ダウンロード
Cruise Control 用 Maven2Builder Plugin
使い方
- Cruise Control 2.3.1 の環境を準備する。
- 上から ZIP アーカイブをダウンロードする。
- 上のアーカイブから maven2builder-1.0.0.jar を取り出して $CC_HOME/lib にコピーする。
- $CC_HOME/cruisecontrol.sh を編集する。
- JAVA_HOME を設定
- CRUISE_PATH に $LIBDIR/maven2builder-1.0.0.jar を追加
- $CC_HOME/config.xmlを編集する。
- plugin に jp.in_vitro.cruisecontrol_plugin.maven2builder.Maven2Builder を登録。name は "maven2"
- builder に maven2 を指定
<cruisecontrol>
<plugin name="maven2"
classname="jp.in_vitro.cruisecontrol_plugin.maven2builder.Maven2Builder"/>
<project name="Gadgets">
<listeners>
<currentbuildstatuslistener file="/home/cruisecontrol/logs/Gadgets/status.txt" />
</listeners>
<bootstrappers>
<svnbootstrapper localWorkingCopy="/home/cruisecontrol/projects/Gadgets" />
</bootstrappers>
<modificationset quietperiod="30" >
<svn localWorkingCopy="/home/cruisecontrol/projects/Gadgets"/>
</modificationset>
<schedule interval="300" >
<maven2 mavenscript="/opt/maven2/bin/mvn"
pom="/home/cruisecontrol/projects/Gadgets/pom.xml"
goal="test"/>
</schedule>
<log>
<merge dir="/home/cruisecontrol/projects/Gadgets/target/surefire-reports"/>
</log>
</project>
</cruisecontrol>
トラブルシューティング
- Q. Cruise Control の設定方法が分かりません。
- A. Cruise Control のマニュアルをご覧ください。
- Q. 動きません。
- A. 管理者の必要最低限の機能しか実装していません。あきらめてください。
参考サイト
- Cruise Control
- http://cruisecontrol.sourceforge.net/
- Cruise Control への Plugin 登録方法
- http://cruisecontrol.sourceforge.net/main/plugins.html#registration
Oct 29, 2005
[Maven] Maven2 用 Jalopy Plugin
Maven2 から Jalopy(*1) を実行する Plugin を書いてみた。 居るとも思えないけれど、もし欲しい人がいたらどうぞ。 お約束ですが、この Plugin を利用して何らかの不利益を被ったとしても一切補償はできません。 SCM などできちんと管理されたソースコードで試行して品質をご自身で判断してからご利用ください。
*1 Java 用のコードフォーマッタ
ダウンロード
使い方
- 上から ZIP アーカイブをダウンロードする。
- プロジェクトで使用しているリモートリポジトリ内の適切な位置に上記アーカイブを解凍する。
- pom.xml を編集してビルドライフサイクルを変更する。
<model>
<build>
</plugins>
<plugin>
<groupId>in-vitro</groupId>
<artifactId>maven-jalopy-plugin</artifactId>
<configuration>
<convention>${basedir}/jalopy-rule.xml</convention>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>format</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</model>
トラブルシューティング
- Q. ダウンロードできません
- A. あきらめてください。管理者が配布を中止しているかもしれません。
- Q. 上手く動作しません
- A. あきらめてください。こんなアヤシゲな Plugin を無理に利用する必要はありません ;-)
参考サイト
- Maven2 の Plugin 設定方法
- http://maven.apache.org/maven2/guides/plugin/guide-java-plugin-development.html
- Jalopy 公式サイト
- http://jalopy.sourceforge.net/
- Jalopy マニュアル
- http://jalopy.sourceforge.net/manual.html
Oct 26, 2005
[JSR] JSR 168 Portlet Specification ダイジェスト
Portlet Specification をざっと眺めたときのメモ。
JSR 168 Portlet Specification
オリジナルの入手はこちら → JSR 168
PLT.1 Preface
JSR 168 に関連する仕様は、
- Java 2 Platform, Enterprise Edigion, v1.3
- Java Servlet, v2.3
- JavaServer Pages, v1.2
PLT.2 Overview
- Portal とは
- 情報システムのプレゼンテーション層に相当する機能で、一般的に personalization、single sign on、content aggregation などを提供する Web アプリケーションのこと。
- Portlet とは
- Java を利用して構築された Web Component。Portal から呼び出され、リクエストに応じて動的に画面生成を行う。Portlet Container に管理される。
- Portlet Container とは
- Portlet を管理し、Portlet の実行環境を提供するコンテナ。Portlet のライフサイクル管理、永続情報管理を行う。
PLT.3 Relationship with the Servlet Specification
Servlet と Portlet の違い。
- Portlet は画面の一部のみを生成する。
- Portlet は URL と直接的な関連を持たない
- Web ブラウザは直接 Portlet を呼び出すことはできない。(必ず Portal 経由)
- Portlet は Servlet よりリクエストハンドリングなどに関して細かく定義されている
- Portlet の状態を表す Portlet Mode や Window State などが予め定義されている
- Portlet は Potal ページ内に複数存在することができる
- Portlet 毎の設定情報、ユーザ毎の設定情報にアクセスできる
- ユーザプロファイル情報にアクセスできる
- HTML 内のリンクを Portal に適した形に書き換えることができる
- Portlet Session にアクセスできる。スコープには application-wide, portlet private が選択できる。
- レスポンスの文字エンコーディングを指定できない
- レスポンスの HTTP ヘッダを変更できない
- リクエストの URL を参照できない
- Portlet は Servlet や JSP を呼び出すことができる。
- Portlet Container は Servlet Container の拡張。
PLT.4 Concepts
Web ブラウザが Portal にアクセスすると、Portal は Portlet Container を呼び出す。 Portlet Container は、内部で管理している Portlet を呼び出す(必要な場合は複数の Portlet を呼び出す)。
┏━━┓ ┏━━┓ ┏━━━━━━━━━━┓ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃┌────────┐┃ ┃ ┃ ┃ ┃→┃│Portlet1│┃ ┃ ┃ ┃ ┃ ┃└────────┘┃ ┃ ┃ ┃ ┃ ┃┌────────┐┃ ┃ ┃→┃ ┃→┃│Portlet2│┃ ┃ ┃ ┃ ┃ ┃└────────┘┃ ┃ ┃ ┃ ┃ ┃┌────────┐┃ ┃ ┃ ┃ ┃→┃│Portlet3│┃ ┃ ┃ ┃ ┃ ┃└────────┘┃ ┃ ┃ ┃ ┃ ┃ ┃ ┗━━┛ ┗━━┛ ┗━━━━━━━━━━┛ Brower Portal Portlet Container ↓ 生成された画面は・・・ ┏━━━━━━━━━━┓ ┃┌────────┐┃ ┃│Title │┃ ┃├────────┤┃ ┃│ 1│┃ ┃│Content │┃ ┃│ │┃ ┃└────────┘┃ ┃┌───┐┌───┐┃ ┃├───┤├───┤┃ ┃│ 2││ 3│┃ ┃└───┘└───┘┃ ┗━━━━━━━━━━┛Portlet はそれぞれ画面の一部分となる HTML を返すので、Web ブラウザには複数の子ウィンドウが開いたような画面が表示される。
PLT.5 The Portlet Interface
┌─────────────┐ │<<interface>>│ │ Portlet │ ├─────────────┤ ├─────────────┤ └─────────────┘ △ | ┌──────────────┐ │ <<abstract>> │ │GenericPortlet│ ├──────────────┤ ← Portlet はこのクラスを継承する。 ├──────────────┤ └──────────────┘
- Portlet のインスタンスは VM 毎に1つずつ(なので、分散環境でない場合は1つ)
- Portlet のライフサイクルは Porlet#init → Porlet#processAction → Porlet#render → Porlet#destroy
- Portlet Container は Servlet Container が Portlet アプリケーションの実行時に利用している ClassLoader と同一の ClassLoader を利用して Portlet をロードしなければならない
- Portlet 実行時(Portlet#processAction) には PortletException, PortletSecurityException, UnavailableException が throw される可能性がある
- PorletException・・・Porlet 実行中に何らかのエラーが発生した場合
- PorletSecurityException・・・ユーザが Porlet の利用権限を持っていない場合
- UnavailableException・・・Portlet が一時的もしくは永続的に利用不可能な場合
- Portlet に渡されるリクエスト/レスポンスのインスタンスは Thread Safe ではない。
PLT.6 Portlet Config
- Portlet Deployment Descriptor には title, short-title, keywords などの情報を記述できる
- PortletConfig のインスタンスが Portlet Deployment Descriptor の情報を保持している
PLT.7 Portlet URLs
- Portlet に指示を行うために、Portlet へのコマンドを含んだ URL を使用する。この URL を Porlet URL と呼ぶ。
- Portlet URL を表す PortletURL インターフェースが定義されている。PortletURL#createActionURL, PorletURL#createRenderURL を使用して PortletURL のオブジェクトを生成できる。
- 特定の Portlet Container 実装が内部情報を URL のクエリに含めている可能性があるので、Porlet を開発する際には HTTP の GET メソッドを使用した Form を利用すべきではない。
- Porlet 毎の情報を PorletURL#setParameter を利用することで Portlet URL 内に組み込むことができる。
- PortletURL#setSecure を使用することで、Portlet URL の転送時に SSL を使用しなければならないか否かを指定することができる。
PLT.8 Portlet Modes
- Portlet Mode は Portlet が現在実行中の機能を表す。
- 標準で定義されている Portlet Mode は、VIEW、EDIT、HELP。
- VIEW・・・Portlet の現在状態を表示するモード。GenericPortlet#doView が対応する。
- EDIT・・・Portlet の状態を変更する方法を提供するモード。GenericPortlet#doEdit が対応する。
- HELP・・・Portlet に関するヘルプ情報を表示するモード。GenericPortlet#doHelp が対応する。
- Deployment Descriptor の custom-portlet-mode を使用することでカスタムの Portlet Mode を定義できる。
PLT.9 Window States
- Window State はレンダリングの際に Portlet がどの程度の情報を出力するかを表す。
- 標準で定義されている Window State は、NORMAL、MAXIMIZED、MINIMIZED。
- NORMAL・・・Portlet が他の Porlet とページをシェアしている状態を表す。
- MAXIMIZED・・・Portlet がページ内のスペースを占有できる状態を表す。
- MINIMIZED・・・Portlet は最小限の情報しか出力できない状態を表す。
- Deployment Descriptor の custom-window-state を使用することでカスタムの Window State を定義できる。
PLT.10 Portlet Context
- PortletContext のインスタンスは Portlet Application 毎に一つ(正確には VM 単位で)。
- PortletContext は、初期化パラメータ、アトリビュート、リソースなどを管理する。
- Portlet は PortletContext から RequestDispatcher を取得することで、Servlet や JSP を呼び出すことができる。
- Portlet は ServletContext にもアクセスできる。この ServletContext は PortletContext と同一のデータを保持している。
PLT.11 Portlet Requests
PLT.12 Portlet Responses
PLT.13 Portal Context
PLT.14 Portlet Preferences
PLT.15 Sessions
PLT.16 Dispatching Requests to Servlets and JSPs
PLT.17 User Information
PLT.18 Caching
PLT.19 Portlet Applications
PLT.20 Security
PLT.21 Packaging and Deployment Descriptor
PLT.22 Portlet Tag Library
PLT.23 Technology Conpatibility Kit Requirements
Oct 25, 2005
[JSR] JSR 168 Portlet Specification について調査
関連サイト
- JSR 168: Portlet Specification
- http://www.jcp.org/en/jsr/detail?id=168
- JSR 162: Portlet API
- http://www.jcp.org/en/jsr/detail?id=162
- JSR 167: Java Portlet Specification
- http://www.jcp.org/en/jsr/detail?id=167
- Apache Portals Project
- http://portals.apache.org/
- Apache Pluto
- http://portals.apache.org/pluto/
- Jetspeed 1
- http://portals.apache.org/jetspeed-1/
- Jetspeed 2
- http://portals.apache.org/jetspeed-2/
- JBoss Portal
- http://www.jboss.com/products/jbossportal
Apache Pluto 1.0.1 インストールメモ
- Pluto をここからダウンロードする。面倒がないように Tomcat 入りのフルセットを落とす。
- Pluto をインストールする。適当な場所にアーカイブを解凍
- <PLUTO のインストール先>\bin\setenv.bat を作成。
- 環境変数 JAVA_HOME を設定。ここで指定する JAVA_HOME は JDK5.0 のパス
- 環境変数 PLUTO_HOME を設定。(ex. set PLUTO_HOME=c:\opt\pluto)
- 環境変数 CATALINA_HOME を設定。PLUTO_HOME と同じパスが CATALINA_HOME になる。(ex. set CATALINA_HOME=%PLUTO_HOME%)
- Pluto を起動する。%PLUTO_HOME%\bin\startup.bat を実行
- Pluto の起動確認をする。http://localhost:8080/ にアクセス
- Pluto Test Driver を実行する。http://localhost:8080/pluto/portal にアクセス
Oct 24, 2005
[Maven] Maven2 Plugin の作り方
Maven2 Plugin 開発手順
- org.apache.maven.plugin.AbstractMojo を継承したクラスを作成する。
- pom.xml を作成する。
ディレクトリ構成
PROJECT_HOME ├src │ ├main │ │ └java │ │ └jp │ │ └in_vitro │ │ └hoge_plugin │ │ └HogeMojo.java ・・・ plugin 本体 │ └test │ └java └pom.xml ・・・ plugin ビルド用 pom
pom.xml
<model>
<modelVersion>4.0.0</modelVersion>
<groupId>in-vitro</groupId>
<artifactId>maven-hoge-plugin</artifactId>
<packaging>maven-plugin</packaging>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-tools-api</artifactId>
<version>2.0</version>
</dependency>
</dependencies>
</model>
HogeMojo.java
package jp.in_vitro.hoge_plugin;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
/**
* @goal goalname
* @description do something
*/
public class HogeMojo extends AbstractMojo {
/**
* プロジェクトのベースディレクトリ。
*
* @parameter expression="${basedir}"
* @required
*/
private File basedir;
/**
* {@link HogeMojo HogeMojo} を生成する。
*/
public HogeMojo() {
super();
}
/**
* このプラグインを実行する。
* このメソッドは Maven から呼び出される。
*
* @throws MojoExecutionException プラグイン実行中にエラーが発生した場合。
*/
public void execute() throws MojoExecutionException {
// do something.
}
}
参考サイト
- Guide to Developing Java Plugins
- http://maven.apache.org/maven2/guides/plugin/guide-java-plugin-development.html
- Maven 標準 Plugin のソースコード
- http://svn.apache.org/viewcvs.cgi/maven/components/trunk/maven-plugins/
Oct 23, 2005
[Maven] Build Task の自動化
プロジェクトの Build Task を自動化する方法を考えてみる。 Build Task は、プロジェクト毎に大同小異なのでベースは固まっていて且つカスタマイズ性が高い、というのがベスト。
Maven2 では、プロジェクトのライフサイクルが規定されている。 ライフサイクルは複数のフェーズから成っていて、それぞれのフェーズに任意の Goal を割り当てることができる。そのため、上記の要件をきちんと満たしてくれている。
デフォルト状態で規定されているライフサイクルは以下の通り。(maven-core-2.0.jar$META-INF/plexus/components.xml から抜粋)
<lifecycles>
<lifecycle>
<id>default</id>
<phases>
<phase>validate</phase>
<phase>initialize</phase>
<phase>generate-sources</phase>
<phase>process-sources</phase>
<phase>generate-resources</phase>
<phase>process-resources</phase>
<phase>compile</phase>
<phase>process-classes</phase>
<phase>generate-test-sources</phase>
<phase>process-test-sources</phase>
<phase>generate-test-resources</phase>
<phase>process-test-resources</phase>
<phase>test-compile</phase>
<phase>test</phase>
<phase>package</phase>
<phase>integration-test</phase>
<phase>verify</phase>
<phase>install</phase>
<phase>deploy</phase>
</phases>
</phases>
</lifecycle>
それぞれのフェーズの用途は Introduction to the Build Lifecycle で解説されている。
ここを適当にカスタマイズして Build Task を組み立てることができそう。
また、↓の様に独自のライフサイクルとフェーズを定義することもできる。
<lifecycle>
<id>clean</id>
<phases>
<phase>pre-clean</phase>
<phase>clean</phase>
<phase>post-clean</phase>
</phases>
<default-phases>
<clean>org.apache.maven.plugins:maven-clean-plugin:clean</clean>
</default-phases>
</lifecycle>
Oct 22, 2005
[Maven] Maven2 まとめ
Maven2 が正式リリースされたので、まとめ。
関連サイト
- 公式サイト
- http://maven.apache.org/maven2/
- デフォルトのリモートリポジトリ
- http://repo1.maven.org/maven2
- プラグイン一覧
- http://maven.apache.org/maven2/plugins/index.html
インストール
- ここから Maven2 をダウンロードする
- アーカイブを適当な位置(ex. /opt/maven-2.0/)に解凍
- 環境変数 MAVEN_HOME を設定(ex. export MAVEN_HOME=/opt/maven-2.0)
- 環境変数 PATH を設定(ex. export PATH=$MAVEN_HOME/bin:$PATH)
- 起動確認 "mvn --version"
$ tar zxvf ./maven-2.0-bin.tar.gz $ export MAVEN_HOME=/opt/maven-2.0 $ export PATH=$MAVEN_HOME/bin:$PATH $ mvn --version Maven version: 2.0
※公式なインストール方法(?)はこちら→Installation Instructions
プロジェクトの作成
- groupId, artifactId を考える
- archetype プラグインを実行(ex. mvn:create -DgroupId=in-vitro -DartifactId=sample)
- 生成されたプロジェクトを確認。カレントディレクトリ内に指定した artifactId と同名のプロジェクトディレクトリが生成されている。
archetype プラグイン実行時に指定可能なパラメータはこちら → archetype:create
※artifactId はプロジェクト成果物となるモジュール(?)のID。groupId は artifactId をグルーピングする際のID。
$ mvn archetype:create -DgroupId=in-vitro -DartifactId=sample [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'archetype'. [INFO] artifact org.apache.maven.plugins:maven-archetype-plugin: checking for up dates from central Downloading: http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-archet ype-plugin/1.0-alpha-3/maven-archetype-plugin-1.0-alpha-3.pom 1K downloaded Downloading: http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-archet ype-plugin/1.0-alpha-3/maven-archetype-plugin-1.0-alpha-3.jar 6K downloaded [INFO] ------------------------------------------------------------------------- --- [INFO] Building Maven Default Project [INFO] task-segment: [archetype:create] (aggregator-style) [INFO] ------------------------------------------------------------------------- --- Downloading: http://repo1.maven.org/maven2/org/apache/maven/maven-archetype-core /1.0-alpha-3/maven-archetype-core-1.0-alpha-3.pom 1K downloaded Downloading: http://repo1.maven.org/maven2/org/apache/maven/maven-archetype/1.0- alpha-3/maven-archetype-1.0-alpha-3.pom 661b downloaded ...snip... [INFO] ------------------------------------------------------------------------- --- [INFO] Using following parameters for creating Archetype: maven-archetype-quicks tart:RELEASE [INFO] ------------------------------------------------------------------------- --- [INFO] Parameter: groupId, Value: in-vitro [INFO] Parameter: outputDirectory, Value: C:\_workspace\sample [INFO] Parameter: packageName, Value: in-vitro [INFO] Parameter: package, Value: in-vitro [INFO] Parameter: version, Value: 1.0-SNAPSHOT [INFO] Parameter: artifactId, Value: sample [INFO] ResourceManager : found archetype-resources/pom.xml with loader org.codeh aus.plexus.velocity.ContextClassLoaderResourceLoader [INFO] ********************* End of debug info from resources from generated POM *********************** [INFO] ResourceManager : found archetype-resources/src/main/java/App.java with l oader org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader [INFO] ResourceManager : found archetype-resources/src/test/java/AppTest.java wi th loader org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader [INFO] Archetype created in dir: C:\_workspace\sample [INFO] ------------------------------------------------------------------------- --- [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------- --- [INFO] Total time: 1 minute 35 seconds [INFO] Finished at: Sat Oct 29 10:40:08 JST 2005 [INFO] Final Memory: 4M/7M [INFO] ------------------------------------------------------------------------- --- $
pom.xml を眺めてみる
archetype プラグインが生成したプロジェクトディレクトリ(上の例では in-vitro )の直下に pom.xml ファイルが生成されている。 pom.xml はプロジェクトに関する各種設定を記述するファイルで Project Descriptor と呼ばれる。
pom.xml のフォーマットはこちら → Project Descriptor
<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>in-vitro</groupId>
<artifactId>sample</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>Maven Quick Start Archetype</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
プロジェクトをビルドしてみる
Maven2 ではビルドライフサイクルという概念が定義されている。 Maven2 実行時に規定されたビルドライフサイクルを指定することで、予め定義された順序でプラグインが逐次実行される。 ビルドライフサイクルには compile, package, install, deploy などが規定されている。
プロジェクトのビルドする場合、"mvn compile" といった様に Maven2 にビルドライフサイクルを指定する。
ビルドライフサイクルに関する詳細はこちら → Introduction to the Build Lifecycle
$mvn compile [INFO] Scanning for projects... [INFO] ------------------------------------------------------------------------- --- [INFO] Building Maven Quick Start Archetype [INFO] task-segment: [compile] [INFO] ------------------------------------------------------------------------- --- [WARNING] POM for: 'commons-io:commons-io:pom:1.0' does not appear to be valid. Its will be ignored for artifact resolution. Reason: Failed to validate POM [INFO] [resources:resources] [INFO] Using default encoding to copy filtered resources. [INFO] [compiler:compile] Compiling 1 source file to /home/in-vitro/projects/sample/target/classes [INFO] ------------------------------------------------------------------------- --- [ERROR] BUILD FAILURE [INFO] ------------------------------------------------------------------------- --- [INFO] Compilation failure /home/in-vitro/projects/sample/src/main/java/in-vitro/App.java:[1,10] ';' があり ません。 [INFO] ------------------------------------------------------------------------- --- [INFO] For more information, run Maven with the -e switch [INFO] ------------------------------------------------------------------------- --- [INFO] Total time: 2 seconds [INFO] Finished at: Sat Oct 29 11:00:58 JST 2005 [INFO] Final Memory: 3M/5M [INFO] ------------------------------------------------------------------------- --- $
Oct 17, 2005
[Mustang] Java Compiler API にチャレンジ
Java Compiler API とは
クラスライブラリからソースコードをコンパイルしてバイトコード化できる API。 仕様は JCP で JSR199 として策定中。
本当は Tiger で JDK に導入されるはずだったのだが、いつの間にやら Mustang に延期されていた。 現在の Mustang の snapshot には動作するコードが入っているので、Mustang でのお披露目は大丈夫そう。 Code Generator のランタイム実行、Rule Engine の高速化などなど色々な用途がありそうなので正式リリースが待ち遠しい。
- JSR199 Java Compiler API
- http://jcp.org/en/jsr/detail?id=199
Java Compiler API の実行環境構築
- Mustang をインストールすれば万事 OK
サンプルコード
↓は以下の処理を行うサンプルコード。
- ハードコーディングされているソースコードをコンパイル
- コンパイルで生成されたバイトコードをオンメモリのまま ClassLoader でローディング
- ClassLoader から Class を取得して main メソッドを実行
Codelet.java
package jp.in_vitro.codelets.mustang.compilerapi;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.tools.DiagnosticMessage;
import javax.tools.JavaCompilerTool;
import javax.tools.JavaFileObject;
import javax.tools.ToolProvider;
import javax.tools.JavaCompilerTool.CompilationTask;
public class Codelet {
public Codelet() {
super();
}
public static void main(final String[] args) {
Codelet me = new Codelet();
me.execute();
}
protected void execute() {
this.execute01();
this.execute02();
this.execute03();
}
protected void execute01() {
// HelloWorld
JavaCompilerTool compiler = this.prepareJavaCompilerTool();
JavaFileManagerImpl fileManager = this
.prepareJavaFileManagerImpl(compiler);
String sourceCode = "public class HelloWorld {" +
"public static void main(String[] args){" +
"System.out.println(\"Hello, World!\");}}";
String className = "HelloWorld";
JavaSourceFileObject sourceObject = new JavaSourceFileObject(className,
sourceCode);
this.compile(compiler, fileManager, sourceObject);
this.executeMain(fileManager, "HelloWorld", new String[0]);
}
protected void execute02() {
// 複数クラスのコンパイル
JavaCompilerTool compiler = this.prepareJavaCompilerTool();
JavaFileManagerImpl fileManager = this
.prepareJavaFileManagerImpl(compiler);
// Main
String mainSourceCode = "public class Main {" +
"public static void main(String[] args){" +
"Sub sub = new Sub(); sub.execute();}}";
String mainClassName = "Main";
JavaSourceFileObject mainSourceObject = new JavaSourceFileObject(
mainClassName, mainSourceCode);
// Sub
String subSourceCode = "public class Sub {" +
"public void execute(){" +
"System.out.println(\"Sub was executed!!\");}}";
String subClassName = "Sub";
JavaSourceFileObject subSourceObject = new JavaSourceFileObject(
subClassName, subSourceCode);
this.compile(compiler, fileManager, mainSourceObject, subSourceObject);
this.executeMain(fileManager, "Main", new String[0]);
}
protected void execute03() {
// コンパイルエラー
JavaCompilerTool compiler = this.prepareJavaCompilerTool();
JavaFileManagerImpl fileManager = this
.prepareJavaFileManagerImpl(compiler);
String sourceCode = "public class Uncompilable {" +
"public static void main(String[] args){" +
"executeAbEsseMethod();}}";
String className = "Uncompilable";
JavaSourceFileObject sourceObject = new JavaSourceFileObject(className,
sourceCode);
this.compile(compiler, fileManager, sourceObject);
this.executeMain(fileManager, "Uncompilable", new String[0]);
}
protected void compile(final JavaCompilerTool compiler,
final JavaFileManagerImpl fileManager,
final JavaSourceFileObject... sourceObjects) {
CompilationTask task = compiler.run(null,
(JavaFileObject[]) sourceObjects);
if (task.getResult()) {
System.out.println();
System.out
.println("************************************************");
System.out.println("* Compilation souce(s) completed!!");
System.out
.println("************************************************");
for (JavaSourceFileObject sourceObject : sourceObjects) {
System.out.println("" + sourceObject.getName());
}
} else {
System.out.println();
System.out
.println("************************************************");
System.out.println("* Compilation souce(s) failed!!");
System.out
.println("************************************************");
for (DiagnosticMessage message : task.getDiagnostics()) {
System.out.println("" + message);
}
throw new IllegalStateException();
}
}
protected void executeMain(final JavaFileManagerImpl fileManager,
final String className, final String[] args) {
System.out.println();
System.out.println("************************************************");
System.out.println("* Execute " + className);
System.out.println("************************************************");
ClassLoader loader = this.prepareClassLoader(fileManager);
try {
Class testClass = loader.loadClass(className);
Method mainMethod = testClass.getMethod("main",
new Class[] { String[].class });
mainMethod.invoke(null, new Object[] { args });
} catch (Exception e) {
e.printStackTrace();
}
}
protected JavaCompilerTool prepareJavaCompilerTool() {
JavaCompilerTool compiler = ToolProvider.defaultJavaCompiler();
compiler.setExtendedOption("-Xlint:all");
return compiler;
}
protected JavaFileManagerImpl prepareJavaFileManagerImpl(
final JavaCompilerTool compiler) {
JavaFileManagerImpl fileManager = new JavaFileManagerImpl(compiler
.getStandardFileManager());
compiler.setFileManager(fileManager);
return fileManager;
}
protected ClassLoader prepareClassLoader(
final JavaFileManagerImpl fileManager) {
ClassLoaderImpl loader = new ClassLoaderImpl();
for (String className : fileManager.getClassNames()) {
loader.addClass(className, fileManager.getClass(className)
.getCode());
}
return loader;
}
}
AbstractJavaFileObject.java
package jp.in_vitro.codelets.mustang.compilerapi;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.nio.CharBuffer;
import javax.tools.JavaFileObject;
public abstract class AbstractJavaFileObject implements JavaFileObject {
private Kind kind;
private String name;
public AbstractJavaFileObject(final String name, final Kind kind) {
super();
this.name = name;
this.kind = kind;
}
public Kind getKind() {
return this.kind;
}
public boolean delete() {
return false;
}
public String getNameWithoutExtension() {
return this.name;
}
public String getName() {
return this.name;
}
public String getPath() {
return this.name;
}
public long lastModified() {
return 0L;
}
public long lengthInBytes() {
return -1L;
}
public boolean matches(final String simpleName, final Kind kind) {
return this.kind.equals(kind) && name.equals(simpleName);
}
public CharBuffer getCharContent(boolean ignoreEncodingErrors) {
throw new UnsupportedOperationException();
}
public InputStream openInputStream() {
throw new UnsupportedOperationException();
}
public OutputStream openOutputStream() {
throw new UnsupportedOperationException();
}
public Reader openReader() {
throw new UnsupportedOperationException();
}
public Writer openWriter() {
throw new UnsupportedOperationException();
}
}
JavaSourceFileObject.java
package jp.in_vitro.codelets.mustang.compilerapi;
import java.io.Reader;
import java.io.StringReader;
import java.nio.CharBuffer;
public class JavaSourceFileObject extends AbstractJavaFileObject {
private String code;
public JavaSourceFileObject(final String name, final String code) {
super(name, Kind.SOURCE);
this.code = code;
}
@Override
public CharBuffer getCharContent(boolean ignoreEncodingErrors) {
return CharBuffer.wrap(code);
}
@Override
public Reader openReader() {
return new StringReader(code);
}
@Override
public String getName() {
return getNameWithoutExtension() + ".java";
}
}
JavaClassFileObject.java
package jp.in_vitro.codelets.mustang.compilerapi;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class JavaClassFileObject extends AbstractJavaFileObject {
private byte[] code;
public JavaClassFileObject(final String name) {
super(name, Kind.CLASS);
}
@Override
public OutputStream openOutputStream() {
return new ClassOutputStream();
}
public class ClassOutputStream extends ByteArrayOutputStream {
public void close() throws IOException {
super.close();
JavaClassFileObject.this.code = super.toByteArray();
}
}
public byte[] getCode() {
return code;
}
}
JavaFileManagerImpl.java
package jp.in_vitro.codelets.mustang.compilerapi;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
public class JavaFileManagerImpl implements JavaFileManager {
private Map classes = new HashMap();
protected final JavaFileManager parentFileManager;
public JavaFileManagerImpl(final JavaFileManager parentFileManager) {
super();
this.parentFileManager = parentFileManager;
}
public JavaClassFileObject getClass(final String name) {
return this.classes.get(name);
}
public Set getClassNames() {
return Collections.unmodifiableSet(this.classes.keySet());
}
public JavaFileObject getFileForOutput(final String name, final Kind kind,
final JavaFileObject originatingSource) {
if (originatingSource instanceof JavaSourceFileObject) {
JavaClassFileObject classObject = new JavaClassFileObject(name);
this.classes.put(name, classObject);
return classObject;
} else {
throw new UnsupportedOperationException();
}
}
public void close() throws IOException {
this.parentFileManager.close();
}
public void flush() throws IOException {
this.parentFileManager.flush();
}
public void setLocation(final String location, final String path) {
this.parentFileManager.setLocation(location, path);
}
public Iterable list(final String packageName,
final Set kinds) throws IOException {
return this.parentFileManager.list(packageName, kinds);
}
public JavaFileObject getFileForInput(final String name) {
throw new UnsupportedOperationException();
}
public JavaFileObject getFileForOutput(final String filename,
final String location, final String pkg) throws IOException {
throw new UnsupportedOperationException();
}
}
ClassLoaderImpl.java
package jp.in_vitro.codelets.mustang.compilerapi;
import java.util.HashMap;
import java.util.Map;
public class ClassLoaderImpl extends ClassLoader {
private Map classes = new HashMap();
public ClassLoaderImpl() {
super();
}
public ClassLoaderImpl(final ClassLoader parent) {
super(parent);
}
public void addClass(final String name, final byte[] bytecode) {
this.classes.put(name, bytecode);
}
public void addClasses(final Map classes) {
this.classes.putAll(classes);
}
@Override
public Class< ? > loadClass(final String name)
throws ClassNotFoundException {
try {
return super.loadClass(name);
} catch (ClassNotFoundException e) {
byte[] classData = classes.get(name);
return defineClass(name, classData, 0, classData.length);
}
}
}
サンプルの実行結果
↑の Codelet#main を実行した結果は↓
************************************************ * Compilation souce(s) completed!! ************************************************ HelloWorld.java ************************************************ * Execute HelloWorld ************************************************ Hello, World! ************************************************ * Compilation souce(s) completed!! ************************************************ Main.java Sub.java ************************************************ * Execute Main ************************************************ Sub was executed!! ************************************************ * Compilation souce(s) failed!! ************************************************ Uncompilable:1: シンボルを見つけられません。 シンボル: メソッド executeAbEsseMethod() 場所 : Uncompilable の クラス Exception in thread "main" java.lang.IllegalStateException at jp.in_vitro.codelets.mustang.compilerapi.Codelet.compile(Codelet.java:113) at jp.in_vitro.codelets.mustang.compilerapi.Codelet.execute03(Codelet.java:81) at jp.in_vitro.codelets.mustang.compilerapi.Codelet.execute(Codelet.java:27) at jp.in_vitro.codelets.mustang.compilerapi.Codelet.main(Codelet.java:20)
Oct 16, 2005
[Mustang] Mustang メモ
そろそろ Mustang も視野にいれておかないと、ということで一通りメモ。
- Mustang
- http://mustang.dev.java.net/
- JDK 6 Documentation
- http://download.java.net/jdk6/docs/
- Java SE 6, Platform Name and Version Numbers
- http://download.java.net/jdk6/docs/relnotes/version-6.html
- JSR270 JavaTM SE 6 ("Mustang")
- http://www.jcp.org/en/jsr/detail?id=270
- JSR105 XML Digital Signature
- http://jcp.org/en/jsr/detail?id=105
- JSR199 Java Compiler API
- http://jcp.org/en/jsr/detail?id=199
- JSR202 JavaTM Class File Specification Update
- http://jcp.org/en/jsr/detail?id=202
- JSR221 JDBC 4.0
- http://jcp.org/en/jsr/detail?id=221
- JSR222 JAXB 2.0
- http://jcp.org/en/jsr/detail?id=222
- JSR223 Scripting for the JavaTM Platform
- http://jcp.org/en/jsr/detail?id=223
- JSR224 JAX-RPC 2.0
- http://jcp.org/en/jsr/detail?id=224
- JSR260 Javadoc Tag Update
- http://jcp.org/en/jsr/detail?id=260
- JSR268 Java Smart Card I/O API
- http://jcp.org/en/jsr/detail?id=268
- JSR269 Pluggable Annotation Processing API
- http://jcp.org/en/jsr/detail?id=269
Oct 14, 2005
[JSR] JSR 250 Common Annotations for the Java Platform ダイジェスト
Common Annotations for the Java Platform の仕様をざっと眺めたときのメモ。
JSR 250 Common Annotations for the Java Platform
オリジナルの入手はこちら → JSR 250
General Guidelines for Inheritance of Annotations
annotation が付加されたメソッドがサブクラスでオーバーライドされた場合、 どのように扱われるのかが曖昧。そのため、そのような場合におけるガイドラインを 以下の様に定義する。
- クラスレベル annotation は自分自身のメンバー(メソッド、フィールド)のみを対象とする。
- クラスレベル annotation よりメンバーレベル annotation の方が優先される。
- インターフェースは実装されているクラス(メンバーを含む)に影響を与えない。
- オーバーライドもしくは隠蔽されていないメンバーは子クラスにおいても親クラスの annotation を引き継ぐ。
- オーバーライドもしくは隠蔽されているメンバーは子クラスにおいて親クラスの annotation の影響を受けない。
javax.annotation.Generated
自動生成されたコードを表す。 自動生成ツールの名称を必ず指定しなければならない。 自動生成された時刻を記述可能。時刻は ISO 8601 のフォーマットに従わなければならない。 ターゲットは ANNOTATION_TYPE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE。
javax.annotation.Resource
DataSource などを自動でクラスにインジェクションするために利用される。 JNDI 名を指定することで、コンテナが JNDI から適切なリソースを取得しフィールドインジェクションもしくはメソッドインジェクションで対象オブジェクトに引き渡す。 ターゲットは TYPE, METHOD, Field。
javax.annotation.Resources
複数のリソースを必要とする場合、Resources を利用して複数の Resource をまとめる。 同一 annotation の複数回指定が認められていないため。 ターゲットは TYPE。
javax.annotation.PostConstruct
インジェクション終了直後に実行されるメソッドを表す。 オブジェクト生成→インジェクション→PostConstruct指定されたメソッド実行、というライフサイクルになる。 ターゲットは METHOD。 この annotation を付加されるメソッドには以下の制限がある。
- パラメータは指定できない(但し、EJB interceptor における InvocationContext のみ可能)
- 戻り値は void のみ。
- チェック例外は throw できない。
- アクセス識別子は public, protected, package private, private を指定可能。
- static にできない。
- final を指定可能。
- 非チェック例外を throw した場合は、そのオブジェクトを利用してはいけない。
javax.annotation.PreDestroy
コンテナがオブジェクトを破棄する際に実行されるメソッドを表す。 ターゲットは METHOD。 この annotation を付加されるメソッドには以下の制限がある。
- パラメータは指定できない(但し、EJB interceptor における InvocationContext のみ可能)
- 戻り値は void のみ。
- チェック例外は throw できない。
- アクセス識別子は public, protected, package private, private を指定可能。
- static にできない。
- final を指定可能。
- 非チェック例外を throw した場合、その例外は無視される。
javax.annotation.security.RunAs
クラスのロールを表す。 Java EE コンテナでクラスが実行される際、RunAs でクラスのロールを割り当てることができる。 ターゲットは TYPE。
javax.annotation.security.RolesAllowed
クラス、メソッドの実行権限を持つロールを指定する。 ターゲットは TYPE, METHOD。
javax.annotation.security.PermitAll
全てのロールが実行権限を持つことを表す。 PermitAll が指定されたクラス、メソッドは権限に関して未チェックで実行される。 ターゲットは TYPE, METHOD。
javax.annotation.security.DenyAll
全てのロールが実行権限を持たないことを表す。 DenyAll が指定されたクラス、メソッドは Java EE コンテナ上では実行できない。 ターゲットは METHOD。
PermitAll, DenyAll and RolesAllowed interactions
- PermitAll, DenyAll, RolesAllowed は特定のクラスもしくはメソッドに同時に指定することはできない。
- DenyAll がクラスレベルで指定されている場合、メソッドに PermitAll, RolesAllowed が指定されると PermitAll, RolesAllowed が優先される。
- RolesAllowed がクラスレベルで指定されている場合、メソッドに DenyAll, PermitAll が指定されると DenyAll, PermitAll が優先される。
謎) DenyAll のターゲットは METHOD のみなのに、ここではクラスレベルで指定できると書かれている。どちらが正しいの??
javax.annotation.security.DeclareRoles
テスト等で使用するためのロールを定義する。 ターゲットは TYPE。
Oct 09, 2005
Oct 08, 2005
[Library] JCIFS にチャレンジ
JCIFS とは
JCIFS は CIFS/SMB の Java 用ライブラリ。 要するに Java から Windows のファイルシステムにアクセスできる。
- JCIFS
- http://jcifs.samba.org/
JCIFS の実行環境構築
- JCIFS(jcifs-1.2.6.jar) をクラスパスに追加
サンプルコード
package jp.in_vitro.codelets.jcifs;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Date;
import java.util.Properties;
import jcifs.Config;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
import jcifs.smb.SmbFileInputStream;
public class Codelet {
public Codelet() {
super();
}
public static void main(final String[] args) throws Exception {
Codelet me = new Codelet();
me.initializeJcifs();
me.printFileList("smb://myclient/c$/");
me.printFile("smb://myclient/SharedDocs/tmp.txt");
}
protected void initializeJcifs() {
Config.setProperties(this.prepareSystemConfiguration());
}
protected Properties prepareSystemConfiguration() {
Properties props = new Properties();
props.setProperty("jcifs.netbios.wins", "192.168.1.1");
props.setProperty("jcifs.smb.client.username", "myname");
props.setProperty("jcifs.smb.client.password", "mypassword");
return props;
}
public void printFileList(final String target)
throws MalformedURLException, SmbException {
SmbFile dir = new SmbFile(target);
if (!dir.isDirectory()) {
return;
}
SmbFile[] children = dir.listFiles();
for (SmbFile child : children) {
if (child.isDirectory()) {
System.out.print("[DIR]");
}
System.out.print(" ");
System.out.print("" + child.getCanonicalPath());
System.out.print(" ");
System.out.print("" + new Date(child.getDate()));
System.out.println();
}
}
public void printFile(final String target) throws IOException {
SmbFileInputStream in = new SmbFileInputStream(target);
int ch = 0;
while ((ch = in.read()) >= 0) {
System.out.print("" + (char) ch);
}
}
}

![[PLUTO の TOP 画面]](/blog/entries/JSR/20051025_01/pluto_top.png)
![[テストドライバの TOP 画面]](/blog/entries/JSR/20051025_01/pluto_testdriver_top.png)
![[テストドライバ画面(1)]](/blog/entries/JSR/20051025_01/pluto_testdriver_test01.png)
![[テストドライバ画面(2)]](/blog/entries/JSR/20051025_01/pluto_testdriver_test02.png)
![[テストドライバ画面(3)]](/blog/entries/JSR/20051025_01/pluto_testdriver_test03.png)
![[PLUTO の管理画面]](/blog/entries/JSR/20051025_01/pluto_testdriver_admin.png)
![[JCIFS 1.2.6 のクラス図]](/blog/entries/Library/20051009_01/jcifs-1.2.6.png)


