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

使い方

  1. Cruise Control 2.3.1 の環境を準備する。
  2. 上から ZIP アーカイブをダウンロードする。
  3. 上のアーカイブから maven2builder-1.0.0.jar を取り出して $CC_HOME/lib にコピーする。
  4. $CC_HOME/cruisecontrol.sh を編集する。
    • JAVA_HOME を設定
    • CRUISE_PATH に $LIBDIR/maven2builder-1.0.0.jar を追加
  5. $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

Posted in Maven | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 29, 2005

[Maven] Maven2 用 Jalopy Plugin

Maven2 から Jalopy(*1) を実行する Plugin を書いてみた。 居るとも思えないけれど、もし欲しい人がいたらどうぞ。 お約束ですが、この Plugin を利用して何らかの不利益を被ったとしても一切補償はできません。 SCM などできちんと管理されたソースコードで試行して品質をご自身で判断してからご利用ください。

*1 Java 用のコードフォーマッタ

ダウンロード

Maven2 用 Jalopy Plugin

使い方

  1. 上から ZIP アーカイブをダウンロードする。
  2. プロジェクトで使用しているリモートリポジトリ内の適切な位置に上記アーカイブを解凍する。
  3. 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

Posted in Maven | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

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 は Servlet にはない以下の機能がある。
  • Portlet 毎の設定情報、ユーザ毎の設定情報にアクセスできる
  • ユーザプロファイル情報にアクセスできる
  • HTML 内のリンクを Portal に適した形に書き換えることができる
  • Portlet Session にアクセスできる。スコープには application-wide, portlet private が選択できる。
Portlet は Servlet が提供している以下の機能を利用できない。
  • レスポンスの文字エンコーディングを指定できない
  • レスポンスの HTTP ヘッダを変更できない
  • リクエストの URL を参照できない
Portlet と Servlet の関係は、
  • 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

Posted in JSR | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

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
※JSR 162 と JSR 167 が一つに統合されて JSR 168 となった(なので、JSR 162、JSR 167 は取り下げられた)。

Apache Pluto 1.0.1 インストールメモ

  1. Pluto をここからダウンロードする。面倒がないように Tomcat 入りのフルセットを落とす。
  2. Pluto をインストールする。適当な場所にアーカイブを解凍
  3. <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%)
  4. Pluto を起動する。%PLUTO_HOME%\bin\startup.bat を実行
  5. Pluto の起動確認をする。http://localhost:8080/ にアクセス
  6. Pluto Test Driver を実行する。http://localhost:8080/pluto/portal にアクセス

[PLUTO の TOP 画面] [テストドライバの TOP 画面] [テストドライバ画面(1)] [テストドライバ画面(2)] [テストドライバ画面(3)] [PLUTO の管理画面]

Posted in JSR | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 24, 2005

[Maven] Maven2 Plugin の作り方

Maven2 Plugin 開発手順

  1. org.apache.maven.plugin.AbstractMojo を継承したクラスを作成する。
  2. 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/

Posted in Maven | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

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>

Posted in Maven | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 22, 2005

[Maven] Maven2 まとめ

Maven2 が正式リリースされたので、まとめ。

関連サイト

公式サイト
http://maven.apache.org/maven2/
デフォルトのリモートリポジトリ
http://repo1.maven.org/maven2
プラグイン一覧
http://maven.apache.org/maven2/plugins/index.html

インストール

  1. ここから Maven2 をダウンロードする
  2. アーカイブを適当な位置(ex. /opt/maven-2.0/)に解凍
  3. 環境変数 MAVEN_HOME を設定(ex. export MAVEN_HOME=/opt/maven-2.0)
  4. 環境変数 PATH を設定(ex. export PATH=$MAVEN_HOME/bin:$PATH)
  5. 起動確認 "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

プロジェクトの作成

  1. groupId, artifactId を考える
  2. archetype プラグインを実行(ex. mvn:create -DgroupId=in-vitro -DartifactId=sample)
  3. 生成されたプロジェクトを確認。カレントディレクトリ内に指定した 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] -------------------------------------------------------------------------
---

$

Posted in Maven | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

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 の実行環境構築

  1. Mustang をインストールすれば万事 OK

サンプルコード

↓は以下の処理を行うサンプルコード。

  1. ハードコーディングされているソースコードをコンパイル
  2. コンパイルで生成されたバイトコードをオンメモリのまま ClassLoader でローディング
  3. ClassLoader から Class を取得して main メソッドを実行
たったこれだけなのに、結構なコーディングが必要だった。 まだ Mustang が開発中だから仕方がないか。 今後に期待!!

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)

Posted in Mustang | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

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
Mustang が関連する JSR はこちら↓。
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

Posted in Mustang | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

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。

Posted in JSR | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 09, 2005

[Library] JCIFS の概要

JCIFS のクラス図

JCIFS 1.2.6 の「イイカゲン」なクラス図を作ってみた。

[JCIFS 1.2.6 のクラス図]

Posted in Library | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 08, 2005

[Library] JCIFS にチャレンジ

JCIFS とは

JCIFS は CIFS/SMB の Java 用ライブラリ。 要するに Java から Windows のファイルシステムにアクセスできる。

JCIFS
http://jcifs.samba.org/

JCIFS の実行環境構築

  1. 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);
        }
    }
}

Posted in Library | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 06, 2005

[Book] Domain Driven Design

書籍情報


Domain Driven Design

レビュー

Posted in Book | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Oct 03, 2005

[Book] Object Design

書籍情報


Object Design

レビュー

Posted in Book | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |