2012年5月2日水曜日

seasar2 AOP

seasar2を使った、簡単なAOPのサンプルです。
seasar2に用意されているorg.seasar.framework.aop.interceptors.TraceInterceptorをアドバイス(インターセプタ)としてそのまま利用しています。
org.seasar.framework.aop.interceptors.TraceInterceptorは、ポイントカットとなるメソッドの前後にメソッド名や引数、戻り値をコンソールに出力してくれるアドバイス(インターセプタ)です。

今回のサンプルでは、log4jは使用していません。
log4jのjarは、クラスパスに置いていないので、 自動でjava.util.logging.Loggerが使用されます。

org.seasar.framework.aop.interceptors.TraceInterceptorはデバッグレベルでログを出力します。
java.util.logging.LoggerのログレベルはFINEにしておいてください。
参考URL:http://www.alles.or.jp/~torutk/oojava/maneuver/2001/logging/logging.html

(1)パッケージ構成




(2)ソース
Driver.java package org.yama.study.aop.pk1;

import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.SingletonS2ContainerFactory;

public class Driver {
    public static void main(String[] args) {
        SingletonS2ContainerFactory.init();
        S2Container container = SingletonS2ContainerFactory.getContainer();
        ClassAImpl ca = (ClassAImpl) container.getComponent("classA");
        ca.methodA();
        ca.methodB();
    }
}

ClassAImpl.java package org.yama.study.aop.pk1;

public class ClassAImpl {
    public void methodA() {
        System.out.println("Hello Aop from methodA!");
    }
    public void methodB() {
        System.out.println("Hello Aop from methodB!");
    }
}

app.dicon <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components>
    <component name="traceInterceptor"
     class="org.seasar.framework.aop.interceptors.TraceInterceptor" />

    <component name="classA" class="org.yama.study.aop.pk1.ClassAImpl">
      <aspect>traceInterceptor</aspect>
    </component>
</components>

main()を実行すると以下の実行結果が得られます。
実行結果 (以下の出力以外に、seasar2本体のログが出力される場合もありますがテーマに関係ないので削除しました。)

普通: BEGIN org.yama.study.aop.pk1.ClassAImpl#methodA()
Hello Aop from methodA!
5 02, 2012 3:11:35 午後 org.seasar.framework.log.Logger debug
普通: END org.yama.study.aop.pk1.ClassAImpl#methodA() : null
5 02, 2012 3:11:35 午後 org.seasar.framework.log.Logger debug
普通: BEGIN org.yama.study.aop.pk1.ClassAImpl#methodB()
Hello Aop from methodB!
5 02, 2012 3:11:35 午後 org.seasar.framework.log.Logger debug
普通: END org.yama.study.aop.pk1.ClassAImpl#methodB() : null

メソッドの前後にログが出力されています。

続いてapp.diconを以下のように変更してみます。
app.dicon(修正後) <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components>
    <component name="traceInterceptor"
     class="org.seasar.framework.aop.interceptors.TraceInterceptor" />

    <component name="classA" class="org.yama.study.aop.pk1.ClassAImpl">
    <aspect pointcut="methodA">traceInterceptor</aspect>
    </component>
</components>

「<aspect pointcut="methodA">traceInterceptor</aspect>」の部分を修正しています。

すると、methodAの前後にだけアドバイスが織り込まれている(ウィービングされている)ことがわかります。

実行結果 (以下の出力以外に、seasar2本体のログが出力される場合もありますがテーマに関係ないので削除しました。)

5 02, 2012 3:42:14 午後 org.seasar.framework.log.Logger debug
普通: BEGIN org.yama.study.aop.pk1.ClassAImpl#methodA()
Hello Aop from methodA!
5 02, 2012 3:42:14 午後 org.seasar.framework.log.Logger debug
普通: END org.yama.study.aop.pk1.ClassAImpl#methodA() : null
Hello Aop from methodB!


Java Logging API ハマリポイント

Java Logging APIを使用して、はまった箇所の備忘録

Java Logging APIの基本的な使い方は、他のページを参照
・http://www.alles.or.jp/~torutk/oojava/maneuver/2001/logging/logging.html
・http://struts.wasureppoi.com/util/04_javalog.html


ロギングの簡単な操作を覚えるために簡単なサンプルを作成した。
Driver.java package org.yama.study;

import java.util.logging.Logger;

public class Driver {
    private final Logger logger = Logger
            .getLogger("driver");

    public static void main(String[] args) {
        Driver dv = new Driver();
        dv.prccess();
    }

    private void prccess() {
        logger.finest("finest");
        logger.fine("fine");
        logger.config("config");
        logger.info("info");
        logger.warning("warning");
        logger.severe("severe");
    }
}

設定ファイル※1の内容(デフォルトのままいじらず)
logging.properties ############################################################
#   Default Logging Configuration File
#
# You can use a different file by specifying a filename
# with the java.util.logging.config.file system property.
# For example java -Djava.util.logging.config.file=myfile
############################################################

############################################################
#   Global properties
############################################################

# "handlers" specifies a comma separated list of log Handler
# classes.  These handlers will be installed during VM startup.
# Note that these classes must be on the system classpath.
# By default we only configure a ConsoleHandler, which will only
# show messages at the INFO and above levels.
handlers= java.util.logging.ConsoleHandler

# To also add the FileHandler, use the following line instead.
#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler

# Default global logging level.
# This specifies which kinds of events are logged across
# all loggers.  For any given facility this global level
# can be overriden by a facility specific level
# Note that the ConsoleHandler also has a separate level
# setting to limit messages printed to the console.
.level= INFO

############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################

# default file output is in user's home directory.
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

# Example to customize the SimpleFormatter output format
# to print one-line log message like this:
#     <level>: <log message> [<date/time>]
#
# java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n

############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################

# For example, set the com.xyz.foo logger to only log SEVERE
# messages:
com.xyz.foo.level = SEVERE


出力結果
出力結果 5 02, 2012 12:24:51 午後 org.yama.study.Driver prccess
情報: info
5 02, 2012 12:24:51 午後 org.yama.study.Driver prccess
警告: warning
5 02, 2012 12:24:51 午後 org.yama.study.Driver prccess
重大: severe

さて、ログレベルを変えてやってみるかと、設定ファイルを変更した。
logging.properties(抜粋) #java.util.logging.ConsoleHandler.level = INFO コメントアウト
java.util.logging.ConsoleHandler.level = FINEST

が、これでは、出力結果が変わらない!?


調査した結果、こっち↓も変えないといけなかった。
logging.properties(抜粋) #.level= INFO コメントアウト
.level= FINEST

無事に出力できました。
出力結果 5 02, 2012 12:31:17 午後 org.yama.study.Driver prccess最も詳細: finest5 02, 2012 12:31:17 午後 org.yama.study.Driver prccess普通: fine5 02, 2012 12:31:17 午後 org.yama.study.Driver prccess構成: config5 02, 2012 12:31:17 午後 org.yama.study.Driver prccess情報: info5 02, 2012 12:31:17 午後 org.yama.study.Driver prccess警告: warning5 02, 2012 12:31:17 午後 org.yama.study.Driver prccess重大: severe

結局、グローバルログレベルでログ出力を制限し、さらにコンソールハンドラレベルでそれ以上に絞りたいのであれば絞ることができる。
したがって、コンソールハンドラレベルにおいて、グローバルログレベル以上のログを出力しようとしても無理なことが判明した。
(設定ファイル※1のコメントに「グローバルログレベルのほかに、コンソールハンドラでもレベルを設定できるから注意しろよ!」と英語で書いてあった。)


※1 JDKインストールディレクトリ以下の「~\lib\logging.properties」もしくは、JREインストールディレクトリ以下の「~\lib\logging.properties」。
このファイルは、すべてのアプリに対して影響するので、普通は編集しません。正しくは、アプリ固有の設定ファイルを準備し、そのファイルを参照しにいくようVMの起動パラメータを指定する必要があります。

2012年4月30日月曜日

seasar2 コンポーネント自動登録

seasar2のコンポーネント自動登録の基本

初めて使ったときに悩んだのでメモ。

コンポーネントの自動登録を理解するために、最もシンプルにしたプロジェクトでサンプルを提示します。

1.自動登録を使用しない場合(プロジェクト名:ComponentManualRegisterSample1)

(1)パッケージ構成


(2)各ソース

ClassAImpl.java
package org.yama.study.pk1;

public class ClassAImpl {
public void say() {
System.out.println("Hello Manual Registar!");
}
}

Driver.java
package org.yama.study.pk1;

import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.SingletonS2ContainerFactory;

public class Driver {
public static void main(String[] args) {
SingletonS2ContainerFactory.init();
S2Container container = SingletonS2ContainerFactory.getContainer();
ClassAImpl ca = (ClassAImpl) container.getComponent("classA");
ca.say();
  }
}

app.dicon
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components>
    <component name="classA" class="org.yama.study.pk1.ClassAImpl">
    </component>
</components>

mainを実行した結果
Hello Manual Registar!


2.自動登録を使用した場合(プロジェクト名:ComponentAutoRegisterSample1)

(1)パッケージ構成
さっきと一緒


(2)各ソース
ClassAImpl.java
package org.yama.study.pk1;

public class ClassAImpl {
public void say() {
// ↓↓↓ 出力の文言を変えただけ。コンポーネントの自動登録には影響しない ↓↓↓
System.out.println("Hello Auto Registar!");
}
}

Driver.java
(さっきと一緒)

app.dicon
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components>
    <component         class="org.seasar.framework.container.autoregister.FileSystemComponentAutoRegister">
        <property name="autoNaming">
            <component class="org.seasar.framework.container.autoregister.DefaultAutoNaming"/>
        </property>
        <initMethod name="addClassPattern">
            <arg>"org.yama.study.pk1"</arg>
            <arg>".*Impl"</arg>
        </initMethod>
    </component>
</components>

mainを実行した結果
Hello Auto Registar!


3.いくつか解説

■自動登録する場合のapp.diconについて


app.dicon(抜粋)
        <initMethod name="addClassPattern">
            <arg>"org.yama.study.pk1"</arg>
            <arg>".*Impl"</arg>
        </initMethod>

1番目の引数は見てわかるとおり、自動登録するクラスのパッケージを指定しているが、
子供のパッケージも再帰的に検索するので、

        <initMethod name="addClassPattern">
            <arg>"org.yama.study"</arg>
            <arg>".*Impl"</arg>
        </initMethod>
や、

        <initMethod name="addClassPattern">
            <arg>"org"</arg>
            <arg>".*Impl"</arg>
        </initMethod>


でも、同様の動きとなった。

ただし、これはだめだった。

        <initMethod name="addClassPattern">
            <arg>""</arg>
            <arg>".*Impl"</arg>
        </initMethod>
デフォルトパッケージに自動登録したいクラスがあった場合、どうすればいいんだろう?
暇なときソースを追いかけてみるか。。。




■DefaultAutoNamingクラスの役割について

Driver.java(抜粋)
ClassAImpl ca = (ClassAImpl) container.getComponent("classA");

コンポーネントの自動登録をしない場合は、app.diconで明示的に「classA」という名前をコンポーネント名に設定している。一方、自動登録する場合には、「classA」というコンポーネント名は、どこにも設定していない。
にもかかわらず、「classA」というコンポーネント名が利用できるのは、app.diconで指定したDefaultAutoNamingクラスが、

app.dicon(抜粋)
        <property name="autoNaming">
            <component class="org.seasar.framework.container.autoregister.DefaultAutoNaming"/>
        </property>

自動でクラス名からコンポーネント名を導き出し、設定してるから。
サンプルの場合、以下のとおり。

・クラス名「org.yama.study.pk1.ClassAImpl」からパッケージ部分を除去し「ClassAImpl」という文字列を作成
    ↓

・「ClassAImpl」のImplを取り除き「ClassA」という文字列を作成

    ↓

・「ClassA」の先頭を小文字に変換し「classA」の出来上がり

この、変換ルールは、DefaultAutoNamingクラスのプロパティやメソッドで、ある程度変更可能。



2011年7月23日土曜日

ApacheモジュールをWindows環境で開発⑤

今回は「mod_hoge.so」というモジュールを作ります。
/hoge/にアクセスがあった場合、「The sample page from mod_hoge.c」というメッセージをだす
簡単なものです。

適当なフォルダ(C:\work\module のような感じ)で以下のコマンドを打ちます。
apxs -g -n hoge

作ったぞ!的なメッセージがでます。
Use of assignment to $[ is deprecated at C:\ApacheSoftware\Apache2.2\bin/apxs.bat line 120.
Creating [DIR]  hoge
Creating [FILE] hoge/Makefile
Creating [FILE] hoge/mod_hoge.c
Creating [FILE] hoge/.deps

ディレクトリが作成され、
3つのファイルが作成されました。

C:\work\module>tree /f hoge
フォルダ パスの一覧
ボリューム シリアル番号は XXXX-9035 です
C:\WORK\MODULE\HOGE
    .deps
    Makefile
    mod_hoge.c


次はコンパイルです。(ソースファイルもいじらず、このままいきます。)
自動で作成されたhogeディレクトリに移動してください。
詳しい人ならmakeでビルドできるようにMakefileを修正するでしょうが、
私にはできないので、gccコマンドで堅実にコンパイルしていきます。

gcc -mwindows -I C:\ApacheSoftware\Apache2.2\include -L C:\ApacheSoftware\Apache2.2\lib -c mod_hoge.c

※includeディレクトリとlibディレクトリはご自分の環境に合わせて変更してください。

エラーです....
----------------------------------------
C:\work\module\hoge>gcc -mwindows -I C:\ApacheSoftware\Apache2.2\include -L C:\A
pacheSoftware\Apache2.2\lib -c mod_hoge.c
In file included from C:/ApacheSoftware/Apache2.2/include/ap_config.h:25,
                 from C:/ApacheSoftware/Apache2.2/include/httpd.h:43,
                 from mod_hoge.c:40:
C:/ApacheSoftware/Apache2.2/include/apr.h:618:1: warning: "IN6_IS_ADDR_V4MAPPED"
 redefined
In file included from C:/ApacheSoftware/Apache2.2/include/apr.h:101,
                 from C:/ApacheSoftware/Apache2.2/include/ap_config.h:25,
                 from C:/ApacheSoftware/Apache2.2/include/httpd.h:43,
                 from mod_hoge.c:40:
C:/Perl/site/lib/auto/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/ws2
tcpip.h:236:1: warning: this is the location of the previous definition
In file included from C:/ApacheSoftware/Apache2.2/include/httpd.h:43,
                 from mod_hoge.c:40:
C:/ApacheSoftware/Apache2.2/include/ap_config.h:234:28: ap_config_auto.h: No suc
h file or directory
C:/ApacheSoftware/Apache2.2/include/ap_config.h:235:30: ap_config_layout.h: No s
uch file or directory
----------------------------------------

ワーニング2つはあえて無視(笑)したとして、
ヘッダファイルが2つ(ap_config_auto.hとap_config_layout.h)ありませんと出ています。
そんなファイル確かにないし、、、
いろいろ調べたり、試したりしましたが、結論としてこの2つはインクルードしないことにしました。
(いいのかどうかは不明です。たぶんダメだと思います。情報お待ちしております。)
ap_config.hの中で上記2ファイルをインクルードしようとしている箇所をコメントアウトし、
再度コンパイルします。

成功するとmod_hoge.oができます。

続いて、.soファイルをつくります。以下のようなgccを実行してください。
gcc -mwindows -I C:\ApacheSoftware\Apache2.2\include -L C:\ApacheSoftware\Apache2.2\lib -shared -o mod_hoge.so mod_hoge.o -llibhttpd

成功するとmod_hoge.soができます。

あとはapacheの設定です。
①できたmod_hoge.soファイルをモジュールのフォルダに移動してください。(私の場合、C:\ApacheSoftware\Apache2.2\modules)
②httpd.confに以下の行を追加(LoadModule が並んでいるところの最後尾)
LoadModule hoge_module modules/mod_hoge.so
③もう1つhttpd.conf の下のほうに
<Location /hoge>
SetHandler hoge
</Location>

Apacheを起動してhttp://localhost/hogeと、入力してください。

The sample page from mod_hoge.c とブラウザに表示されれば成功です。

2011年7月10日日曜日

ApacheモジュールをWindows環境で開発④

④apxsをインストール

http://www.apachelounge.com/download/から、apxs_win32.zipをダウンロードします。

解凍して、任意のフォルダに保存してください。

私の場合は、Apacheのディレクトリに入れました。(C:\ApacheSoftware\Apache2.2\apxs)

⑤Apache再インストール

私の場合、Apacheの再インストールが必要でした。
なぜなら、Apacheをインストールするときに標準(Typical)インストールに
した場合、ビルドヘッダー(includeフォルダ等)やライブラリのインストールは割愛されてしまうからです。

apxsを利用して、モジュールを作成するには、これらが必要になります。
したがって、再インストールが必要でした。
インストールする際のポイントだけ、紹介します。


カスタムインストールを選択してください。





Build Headers and Librariesがデフォルトでは
インストール対象から外れているので、
インストール対象に含めてください。



















 続く

2011年7月8日金曜日

ApacheモジュールをWindows環境で開発③

②dmakeをインストール

PerlPackageManagerを利用してdmakeをインストールします。
MinGWのインストールと同様なのですごく簡単に説明します。

まず、検索ボックスに「dmake」と入力してリターン。
検索結果に表示されている「dmake」を右クリック。
「Install dmake ・・・・」を選択。


「dmake」の箇所に緑色の+マークが出たら、
下の赤枠の矢印をクリック。

確認のダイアログが出てくるので「OK」と言いつつ
ボタンを押します。

コンソールにずらずらメッセージが出てきてインストール完了です。

最後に動作確認をします。
コマンドプロンプトで「dmake -V」(※注意 Vは大文字です)と入力し、
バージョン情報が表示されたらOKです。

では続く・・・

2011年7月4日月曜日

ApacheモジュールをWindows環境で開発②

②MinGWをインストール

gcc(C言語のコンパイラ)を利用するにはMinGWなるものをインストールする必要があります。
前の記事の記事でインストールしたActivePerlの機能を使用します。

PerlPackageManagerを利用する方法です。
(使い方の詳細は知りませんのでとりあえずMinGWをインストールする方法を説明します。)


起動したら、赤枠のボタンを選択




















検索BOXにMinGWと入力&リターン
 




















表示されたものを右クリックすると「install MinGW なんたらかんたら」と
メニューが出るのでそれを選択。すると緑の+マークがでます。
 



















そしたら下の赤枠の箇所のボタンをクリック。




















インストールしますか?と聞いてくる。



コンソールにいろいろと出てきて、インストールが完了します。


コマンドプロンプトを立ち上げて「gcc -dumpversion」と打ってみてください。
(パスは通ってるるはずです。)
バージョン情報が表示されたらインストールOK

では次回はdmakeのインストール方法へ。。。

そういえばこのシリーズの最終目標はWindowsでApacheのモジュールを開発するでしたねw。
長い道のりになりそうです。