[CONTAINER-175] SAX サポートクラスの final を外し,OGNL の処理中にクラスを読み込むのを Class#forName() から ClassLoader#loadClass() に変更しました. Created: 11/Mar/08  Updated: 01/Apr/08  Resolved: 12/Mar/08

Status: Resolved
Project: S2Container
Component/s: S2Container
Affects Version/s: 2.4.23
Fix Version/s: 2.4.24

Type: Improvement Priority: Major
Reporter: Feng Dihai Assignee: koichik
Resolution: Fixed Votes: 0
Labels: None
Environment:

Windows Vista
JDK1.5.0_14



 Description   

提案
javaではimport句を使えば、いちいち「パッケージ名.クラス名」ではなく、ショット・クラス名のみで引用できます。

しかしdiconファイルを記述する時、componentのclass属性またはOGNL式の中にjava.langパッケージ以外はすべてフル・クラス名で記入しなければなりません。場合によって開発者に大きな負担になりかねません。javaのimport句のように明示的にパッケージとクラスのインポート機能をS2Containerに追加することを提案いたします。

実現方法の説明
S2Containerのソースを分析した結果、インポート機能は実現できて社内プロジェクトに適用されています。S2Containerが提供する公開APIだけではきれいに実装できないところがありますので、できればS2Containerの公式サポートを強く望んでおります。

宣言及び引用方法
XMLドキュメントのprocessing instructionを利用します。記述例:

 <?xml version="1.0" encoding="UTF-8" ?>
 <?java-import
          java.util.*;
          com.mydomain.commons.*;
          com.mydomain.util.DebugUtil;
  ?>
 <components>
      <component name="foo" class="DebugUtil">
           <property name="map">
                 #@TreeMap@{"key1" : "value1", "key2" : "value2"}
           </property>
      </component>
 </components>

実装クラス

  • EnhancedXmlS2ContainerBuilder extends XmlS2ContainerBuilder
    • <?java-import ?>を認識できる拡張コンテナー・ビルダー
    • 以下EnhancedSaxHandlerParserおよびSmartComponentTagHandlerを引用します
  • EnhancedSaxHandlerParser
    • XMLパーサ、org.seasar.framework.xml.SaxHandlerParserはfinalクラスのため、新規用意
    • 以下EnhancedSaxHandlerを引用います
  • EnhancedSaxHandler extends DefaultHandler
    • <?java-import ?>を解析するハンドラ
    • 解析結果はClassImporterのインスタンスにいれます
  • SmartComponentTagHandler extends ComponentTagHandler
    • componentのclass属性をショット・クラス名を認識できるタグ・ハンドラ
    • ショット・クラス名の解決はClassImporterに委託します
  • ClassImporter
    • インポートしたパッケージ及びクラスのリストを管理します
    • ショット・クラス名をインポート済みリストと突き合わせて、クラス・ローダーにクラスをロードさせます
    • クラスを見つからない場合は、ルート・クラス・インポート(存在すれば)を使ってさらに検索します
  • SmartClassLoader extends ClassLoader
    • 親クラスロードおよびClassImporterオブジェクトを持つクラス・ローダー
    • ショット・クラス名の解決はClassImporterに任せます、クラスは親クラスによってロードされます
    • EnhancedXmlS2ContainerBuilder#parse(parent, path)処理の中で、生成したS2コンテナーにセットされます

使用方法
s2container.diconに名前は「dicon」の「EnhancedXmlS2ContainerBuilder」コンポーネントを追加します:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" 
	"http://www.seasar.org/dtd/components24.dtd">
<components>
    <include condition="#ENV == 'ut'" path="warmdeploy.dicon"/>
    <include condition="#ENV == 'ct'" path="hotdeploy.dicon"/>
    <include condition="#ENV != 'ut' and #ENV != 'ct'" path="cooldeploy.dicon"/>
    
     <component name="dicon" class="org.seasar.framework.container.patch.EnhancedXmlS2ContainerBuilder"/>

</components>

以上、ご検討をお願いいたします。



 Comments   
Comment by Feng Dihai [ 11/Mar/08 ]

実装のソース・ファイルはこちらからダウンロードできます:
http://fengdh.googlepages.com/s2container_patch_src.jar

by Feng Dihai

Comment by koichik [ 11/Mar/08 ]

Seasar プロジェクトしては dicon ファイルの入力を補完する Eclipse Plugin "Kijimuna" を用意しています.

このため,本提案を取り込む必要性はあまりありません.
むしろ Kijimuna との連携がうまくできなくなるというデメリットがあります.

また,Seasar2 に対する機能追加は基本的に終了しています.

以上の点から,本提案のパッチを取り込むよりも,このような拡張がしやすいように改善するということでいかがでしょうか?

具体的には,以下の 2 点に対応すれば,「きれいに実装できないところ」がなくなるように思われます.

  • SaxHandlerParser クラスの final を外す.
  • OgnlUtil で Class#forName() を ClassLoader#loadClass() に変更する.
Comment by Feng Dihai [ 12/Mar/08 ]

具体的には,以下の 2 点に対応すれば,「きれいに実装できないところ」がなくなるように思われます.

  • SaxHandlerParser クラスの final を外す.
  • OgnlUtil で Class#forName() を ClassLoader#loadClass() に変更する.

この2点でも対応していただければ、大変助かります。そうすればおしゃったとおり、Seasar2本体ではなく拡張機能が勝手に作られるようになります。

よろしいければ、対応の予定を教えていただきませんか?

Comment by koichik [ 12/Mar/08 ]

修正しました.
http://svn.seasar.org/browse/?view=rev&root=s2container&revision=3530

Comment by koichik [ 12/Mar/08 ]

SNAPSHOT をデプロイしたのでご確認ください.

Comment by koichik [ 12/Mar/08 ]

この拡張では import の定義に PI が使われていますが,要素を使うことも可能です.

  • <import> 要素を定義した DTD を作成してクラスパス上に配置 (Jar に含めるなど).
  • 追加した要素を扱う AbstractTagHandler のサブクラス (ImportTagHandler) を作成.
  • s2container.dicon に以下のような定義を追加.
    <component name="defaultBuilder" class="org.seasar.framework.container.factory.XmlS2ContainerBuilder">
      <property name="rule">
        <component class="org.seasar.framework.container.factory.S2ContainerTagHandlerRule">
          <initMethod name="addTagHandler">
            <arg>"import"</arg>
            <arg>
              <component class="org.seasar.framework.container.patch.ImportTagHandler"/>
            </arg>
          </initMethod>
        </component>
      </property>
      <initMethod name="addDtd">
        <arg>"-//SEASAR//DTD S2Container 2.4 Import Extension//EN"</arg>
        <arg>"components24ex.dtd"</arg>
      </initMethod>
    </component>
    

また,SmartClassLoader を使うために XmlS2ContainerBuilder を拡張する必要はありません.s2container.dicon に以下のように設定するだけで,そのクラスローダが使われます.

<component class="org.seasar.framework.container.patch.SmartClassLoader"/>
Comment by Feng Dihai [ 01/Apr/08 ]

2.4.24のリリースを待っているので、返事が遅れて申し訳ございません。

ご返答の中では、

また,SmartClassLoader を使うために XmlS2ContainerBuilder を拡張する必要はありません.s2container.dicon に以下のように設定するだけで,そのクラスローダが使われます.

<component class="org.seasar.framework.container.patch.SmartClassLoader"/>

実際importは個別diconファイルをスコープとし、インクルードより構築されたS2コンテナの階層と関係はありません。よってS2コンテナのインスタンスごとにSmartClassLoaderは必要です。上記のコンポーネント定義に、「 instance="prototype" 」を追加するすてきです:

<component class="org.seasar.framework.container.patch.SmartClassLoader" instance="prototype" />

PIの使用に関して賛否両論に分かれているみたい(http://www.advogato.org/article/522.html)だけど、<?xml-stylesheet ..?>のような日常的にも使われています。
<import>要素を定義するのに比べて、PIなら別途DTDを拡張しなくても済むメリットもあります。また、PIはあくまでオプションなので、処理プログラムはただ無視してもいいです。

私はクラス・インポートの拡張機能を<?java-import ..?>ベースに実装するつもりです。CONTAINER-181対応の様子を見て、後日パッチを用意いたします。

Comment by koichik [ 01/Apr/08 ]

リリース後に問題が解消していないことが分かっても手遅れなので,対応後の確認および報告はリリースの前にお願いします.
インポート機能を Seasar2 に取り込む予定はないのでパッチを提供していただく必要はありません.

Generated at Tue Oct 22 04:51:26 JST 2019 using JIRA 7.9.2#79002-sha1:3bb15b68ecd99a30eb364c4c1a393359bcad6278.