#contents *はじめに [#md7e46f2] あるサービスがどのように処理されるかを調べる場合、様々な設定がどのような値になっているかを調べる必要があります。そこで、コンテナのmainメソッドから読み進めることでどこでどのような値が設定されるのかを読解することにします。 なお、今回対象としたバージョンは4.0.0です。 *org.globus.wsrf.container.ServiceContainer [#z5d42db6] globus-start-containerにより起動されるクラスはorg.globus.wsrf.container.ServiceContainerです。というわけでServiceContainerのmainメソッドを見ていきましょう。簡単のため、セキュアコンテナではない(引数として-nosecを指定)とします。同クラスのcreateContainerメソッドを呼び出し、ServiceContainerオブジェクトを作成しているようです。 createContainerメソッドに進む前にmainメソッドの続きを見てみると、 container.waitForInit(); container.waitForStop(); となっており、それぞれ、ServiceDispatcherオブジェクトの同名メソッドに処理が委譲されています。このことから、コンテナのメイン処理はServiceDispatcherオブジェクトが行っていると推測されます。 createContainerメソッドでは渡されたプロパティからどのクラスをServiceContainerオブジェクトとして生成するかを取得((セキュアコンテナの場合、org.globus.wsrf.container.GSIServiceContainerが設定されます))し、オブジェクトの生成を行っています。デフォルトではServiceContainerクラスのインスタンスが生成されるようです。コンストラクタではstartメソッドを呼び出しているので、startメソッドの読解に進みましょう。 startメソッドではServiceDispatcherオブジェクトの生成、初期化、起動が行われています。リファレンスカウントを増やしたり、ServiceContainerをCollectionやHashtableに登録したりしていますが通常はServiceContainerは一つだと思われるので無視していいでしょう。それでは読解対象をServiceDispatcherクラスに移します。 *org.globus.wsrf.container.ServiceDispatcher [#pdfa4814] コンストラクタにて、まず設定ファイル名を決定していますがプロパティは設定されていないはずなのでデフォルトのserver-config.wsddでしょう。次に設定ファイルのベースディレクトリ($GLOBUS_LOCATION/etc)を設定してAxisServerを生成しています。AxisServer(のスーパークラスのAxisEngine)のコンストラクタ(が呼び出しているinitメソッド)では引数として渡されたEngineConfiguration(今回のケースではDirProvider)にコールバックしています。DirProviderオブジェクトはベースディレクトリ以下の個々のディレクトリ(GT4ではサービスの設定はサービスごとにディレクトリに分けられて置かれています)についてserver-config.wsddの読み込み、デプロイを行っているようです。個々のサービスの読み込みについては素直にaxisそのままなようです。 さて、次にinitメソッドを眺めてみましょう。いろいろやっていますが重要そうなのはServiceManager.startメソッドのようです。ServiceDispatcher.startメソッドを先に見てみるとなんとなく予想できるようにスレッドを作成してソケットの待ち受けを開始しています。リクエストがどう処理されるかは[[GT4のリクエスト処理方法を読む>GT4/リクエスト処理方法を読む]]で読むことにして注目をServiceManagerクラスに移しましょう。 *org.globus.wsrf.container.ServiceManager [#le1e0187] startメソッドを見るとstartメソッドでは次の2つの処理を行っていることがわかります。 +JNDIの初期化 +loadOnStartup=trueとなっているサービスの初期化 ではJNDIの初期化を見ていきましょう。 *org.globus.wsrf.jndi.JNDIUtils.initializeDir [#k9ae1710] JNDIの初期化はorg.globus.wsrf.jndi.JNDIUtils.initializeDirメソッドで行われています。まず、同クラスのinitJNDIメソッドが呼び出されています。 JNDIの設定はされていないはずですのでSystem.getProperty()の結果はnullだとします。initJNDIメソッドではURL_PKG_PREFIXESをorg.apache.namingに、INITIAL_CONTEXT_FACTORYをorg.apache.naming.java.javaURLContextFactoryに設定するようです。JNDIのlookupは再帰的過ぎて迷子になってしまったのですが・・・、最終的にorg.apache.naming.NamingContextが使われるということでいいんでしょうか? 次に各サービスについてjndi-config.xml(デフォルト値)を処理しているようです。メソッド呼び出しをたどるとparseJNDIConfigメソッドでDigesterを使ってXMLからオブジェクトを作成しています。Contextという名前はJNDIなのかGT4なのか紛らわしいのでもう少し気の利いた名前にして欲しかったですね:-)。一つのserviceタグが終わるとNamingContext.addSubContextメソッドが呼ばれるようです。 *org.globus.wsrf.jndi.NamingContext.addService [#hf92fc0b] NamingContext.addContextメソッドはaddServiceメソッドを呼んでいるだけです。addServiceメソッドではまず、JNDIUtils.createSubcontextsメソッドを呼び出してサービスに対するJNDIパスを作成しています。これで例えば、 java:comp/env/services/examples/core/first/MathService のようなJNDIパスが構築されます。 次に、environmentの使い方はわからないので飛ばして、serviceタグ以下の各resourceについてaddServiceResourceメソッドが呼び出されています。addServiceResourceメソッドではServiceRefオブジェクトを作成し、個々のparameterタグの内容を登録後、resource#nameにbindしています。これで、 java:comp/env/services/examples/core/first/MathService/home のようなJNDIパスに値(この場合、Reference)が設定されます。 *ServiceManager.initializeService [#o69d9b1e] それではサービスの初期化を見ていきます。個々の(loadOnStartup=trueな)サービスについてinitializeServiceメソッドが呼び出されています。余談ですが、MessageContext.serviceHandlerっていつの間に設定されたんだ!?と調べたらsetTargetServiceメソッドを呼び出すと設定されるんですね。 セキュア機能は使っていないのでsubjectはnullとなるはずです。ServiceManager.InitPrivilegedAction.initializeメソッドを読むと // forces the resource home to be initialized ResourceContext.getResourceContext(ctx); rctx.getResourceHome(); というようにJNDIからサービスに対するResourceHomeオブジェクトを取得しています。JNDIにはReferenceとして登録しているため、bindの時点ではResourceHomeオブジェクトはまだ作られておらず初めて取得した時点で構築されるようです。 ResourceContext.getResourceContextメソッドを見るとorg.globus.wsrf.impl.ResourceContextImplが作成されるがわかります。プロパティとかでResourceContext実装を切り替えられるわけでもないのになんでgetResourceHomeを抽象メソッドにしているのでしょう?将来は切り替えられるようにするのでしょうか? *org.globus.wsrf.impl.ResourceContextImpl [#we2c8822] さて次にResourceContextImpl.getResourceHomeですが、まず、getResourceHomeLocationメソッドを呼び出しています。getResourceHomeLocationメソッドでは、 this.homeLocation = Constants.JNDI_SERVICES_BASE_NAME + getService() + Constants.HOME_NAME; としています。Constantsクラスの定数をデリファレンスすると、 this.homeLocation = "java:comp/env/" + "/services/" + getService() + "/home"; となります。次に、getServiceメソッドはgetService(SOAPMessageContext ctx)に処理を委譲しており、 org.apache.axis.MessageContext msgCtx = (org.apache.axis.MessageContext)ctx; return msgCtx.getTargetService(); となっています。targetServiceは"examples/core/first/MathService"のような値が設定されているので、homeLocationとして、 java:comp/env/services/examples/core/factory/MathFactoryService/home という文字列が得られます。この文字列を使ってJNDIからResourceHomeオブジェクトをlookupしています。 lookupのContextとしてはorg.apache.naming.NamingContextが使われるはずなのでlookupメソッドを見てみるとReferenceの場合はjavax.naming.spi.NamingManager.getObjectInstanceメソッドを使ってオブジェクトを作成していることがわかります。 getObjectInstanceメソッドではfactoryパラメータで指定されたObjectFactoryを用いてResourceHomeオブジェクトが構築される・・・と思うのですがfactoryClass(factoryパラメータとは別)は設定されていないはずでソースを読んでもそれっぽい処理が見あたりません。読解に誤りがあるのでしょうか?まあ作成されると信じて:-)org.globus.wsrf.jndi.BeanFactory.getObjectInstanceメソッドに進みましょう。 *org.globus.wsrf.jndi.BeanFactory [#a6511a85] いろいろセキュリティ設定がされているようですが無視して、スーパークラスのBasicBeanFactory.getObjectInstanceメソッドに移ります。BasicBeanFactoryはorg.apache.naming.factory.BeanFactory(紛らわしい)のサブクラスでオブジェクトの構築自体はスーパークラスが行っています。resource/resourceParams/parameterの各内容がオブジェクトに設定されるようです。 *おわりに [#r4291665] 今回ソースを読む際にEclipseのシンボル宣言位置検索機能を利用してみました。なかなか便利ですが個々のjarについてソースがどこにあるか指定しないといけません。今回の読解範囲では、 :wsrf_core.jar|メイン :wsrf_tools.jar|jndi-config.xml解析部分 :axis.jar|axis のソースを設定する必要がありました。 読解の感想としてはGT4本体ではないのですが、JNDIはプロパティや外部から設定されるオブジェクトを考慮してどの処理を通るかを考えないといけないため、静的に読み進めるのは困難だと思いました(ResourceHomeを作成するファクトリークラスがどうやって決定されるかが追いきれませんでした)。かと言ってサーバプログラムなのでEclipseで追うこともできません。徹底的にconfigurableなのも微妙だなぁと言ったところです。それではみなさんもよいコードリーディングを。 読解の感想としてはGT4本体ではないのですが、JNDIはプロパティや外部から設定されるオブジェクトを考慮してどの処理を通るかを考えないといけないため、静的に読み進めるのは困難だと思いました(ResourceHomeを作成するファクトリークラスがどうやって決定されるかが追いきれませんでした)。徹底的にconfigurableなのも微妙だなぁと言ったところです。それではみなさんもよいコードリーディングを。