View Javadoc

1   /*
2    *
3    * The Seasar Software License, Version 1.1
4    *
5    * Copyright (c) 2003-2004 The Seasar Project. All rights reserved.
6    *
7    * Redistribution and use in source and binary forms, with or
8    * without modification, are permitted provided that the following
9    * conditions are met:
10   *
11   * 1. Redistributions of source code must retain the above
12   *    copyright notice, this list of conditions and the following
13   *    disclaimer.
14   *
15   * 2. Redistributions in binary form must reproduce the above
16   *    copyright notice, this list of conditions and the following
17   *    disclaimer in the documentation and/or other materials provided
18   *    with the distribution.
19   *
20   * 3. The end-user documentation included with the redistribution,
21   *    if any, must include the following acknowledgement:
22   *    "This product includes software developed by the
23   *    Seasar Project (http://www.seasar.org/)."
24   *    Alternately, this acknowledgement may appear in the software
25   *    itself, if and wherever such third-party acknowledgements
26   *    normally appear.
27   *
28   * 4. Neither the name "The Seasar Project" nor the names of its
29   *    contributors may be used to endorse or promote products derived
30   *    from this software without specific prior written permission of
31   *    the Seasar Project.
32   *
33   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR
34   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
35   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
36   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE SEASAR PROJECT
37   * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
38   * INCIDENTAL,SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
41   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
42   * WHETHER IN CONTRACT, STRICT LIABILITY,OR TORT (INCLUDING
43   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
44   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45   */
46  package org.seasar.remoting.axis.deployer;
47  
48  import java.util.ArrayList;
49  import java.util.List;
50  import java.util.regex.Matcher;
51  import java.util.regex.Pattern;
52  
53  import javax.servlet.ServletContext;
54  
55  import org.apache.axis.AxisEngine;
56  import org.apache.axis.WSDDEngineConfiguration;
57  import org.apache.axis.client.Service;
58  import org.apache.axis.deployment.wsdd.WSDDDeployment;
59  import org.seasar.framework.container.ComponentDef;
60  import org.seasar.framework.container.MetaDef;
61  import org.seasar.framework.container.MetaDefAware;
62  import org.seasar.framework.container.S2Container;
63  import org.seasar.framework.message.MessageFormatter;
64  import org.seasar.remoting.axis.DeployFailedException;
65  import org.seasar.remoting.axis.S2AxisConstants;
66  import org.seasar.remoting.common.deployer.Deployer;
67  
68  /***
69   * diconファイル中に記述されたコンポーネントをAxisにデプロイします。
70   * 
71   * @author koichik
72   */
73  public class AxisDeployer implements Deployer {
74      //class fields
75      /***
76       * <code>&lt;meta&gt;</code> 要素の <code>name</code>
77       * 属性に指定される名前を取得するための正規表現です。 <br>
78       * S2Axis-V1.0.0-RC2以降は接頭辞 <code>axis-</code> の後にローカル名が続きます。 <br>
79       * S2Axis-V1.0.0-RC1以前との互換性のため、接頭辞 <code>s2-axis:</code> も使えるようにしています。
80       */
81      protected static final Pattern META_NAME_PATTERN = Pattern.compile("(?:s2-axis:|axis-)(.+)");
82  
83      //instance fields
84      protected S2Container container;
85      protected ServletContext servletContext;
86  
87      protected ItemDeployer serviceDeployer = new ServiceDeployer(this);
88      protected ItemDeployer handlerDeployer = new HandlerDeployer(this);
89      protected ItemDeployer wsddDeployer = new WSDDDeployer(this);
90  
91      /***
92       * S2コンテナを設定します。
93       * 
94       * @param container
95       *            S2コンテナ
96       */
97      public void setContainer(final S2Container container) {
98          this.container = container;
99      }
100 
101     /***
102      * サーブレットコンテキストを設定します。
103      * 
104      * @param servletContext
105      *            サーブレットコンテキスト
106      */
107     public void setServletContext(final ServletContext servletContext) {
108         this.servletContext = servletContext;
109     }
110 
111     /***
112      * コンテナに登録されているサービスやハンドラをデプロイします。
113      */
114     public void deploy() {
115         forEach(container.getRoot());
116     }
117 
118     /***
119      * コンテナの階層をたどって全てのコンテナとコンポーネント定義を走査します。 <br>
120      * 走査する順序は次の通りです。
121      * <ol>
122      * <li>コンテナ自身</li>
123      * <li>子のコンポーネント定義</li>
124      * <li>子のコンテナを再起的に</li>
125      * </ol>
126      * 
127      * @param container
128      *            起点となるコンテナ
129      */
130     protected void forEach(final S2Container container) {
131         process(container);
132 
133         final int componentDefSize = container.getComponentDefSize();
134         for (int i = 0; i < componentDefSize; ++i) {
135             process(container.getComponentDef(i));
136         }
137 
138         final int childContainerSize = container.getChildSize();
139         for (int i = 0; i < childContainerSize; ++i) {
140             forEach(container.getChild(i));
141         }
142     }
143 
144     /***
145      * S2コンテナにS2Axisのメタデータ <code>&lt;meta name="axis-deploy"&gt;</code>
146      * が指定されていれば、そのWSDDをAxisにデプロイします。
147      * 
148      * @param container
149      *            S2コンテナ
150      */
151     protected void process(final S2Container container) {
152         final MetaDef[] metaDefs = getMetaDefs(container, S2AxisConstants.META_DEPLOY);
153         for (int i = 0; metaDefs != null && i < metaDefs.length; ++i) {
154             wsddDeployer.deploy(null, metaDefs[i]);
155         }
156     }
157 
158     /***
159      * コンポーネント定義にS2Axisのメタデータ <code>&lt;meta name="axis-service"&gt;</code>
160      * または <code>&lt;meta name="axis-handler"&gt;</code>
161      * が指定されていれば、そのコンポーネントをサービスまたはハンドラとしてAxisにデプロイします。
162      * 
163      * @param componentDef
164      *            コンポーネント定義
165      */
166     protected void process(final ComponentDef componentDef) {
167         final MetaDef serviceMetaDef = getMetaDef(componentDef, S2AxisConstants.META_SERVICE);
168         if (serviceMetaDef != null) {
169             serviceDeployer.deploy(componentDef, serviceMetaDef);
170         }
171 
172         final MetaDef handlerMetaDef = getMetaDef(componentDef, S2AxisConstants.META_HANDLER);
173         if (handlerMetaDef != null) {
174             handlerDeployer.deploy(componentDef, handlerMetaDef);
175         }
176     }
177 
178     /***
179      * WSDDデプロイメントを返します。
180      * 
181      * @param container
182      *            コンテナ
183      * @return WSDDデプロイメント
184      */
185     protected WSDDDeployment getDeployment(final S2Container container) {
186         return ((WSDDEngineConfiguration) getEngine(container).getConfig()).getDeployment();
187     }
188 
189     /***
190      * Axisエンジンを返します。 <br>
191      * Axisエンジンは、コンテナに名前 <code>axis-engine</code> を持つ
192      * <code>&lt;meta&gt;</code> 要素が指定されていれば、その内容文字列から次のように決定されます。
193      * <dl>
194      * <dt>未定義の場合</dt>
195      * <dd><code>"default"</code> が指定されたものとしてAxisエンジンを決定します。</dd>
196      * <dt><code>"default"</code></dt>
197      * <dd>コンテナにサーブレットコンテキストが設定されていれば <code>"default-server"</code> 、そうでなければ
198      * <code>"default-client"</code> が指定されたものとしてAxisエンジンを決定します。</dd>
199      * <dt><code>"default-client"</code></dt>
200      * <dd>コンテナから <code>javax.xml.rpc.Service</code>
201      * を実装したコンポーネントを取得し、そのエンジンを使用します。</dd>
202      * <dt><code>"default-server"</code></dt>
203      * <dd>サーブレットコンテキストに設定されているAxisエンジンを使用します。 <br>
204      * 最初に {@link S2AxisConstants#AXIS_SERVLET}と
205      * {@link S2AxisConstants#ATTR_AXIS_ENGINE}を連結した文字列をキーとして
206      * サーブレットコンテキストからAxisエンジンを取得します。 <br>
207      * 見つからなかった場合は{S2AxisConstants#ATTR_AXIS_ENGINE}を
208      * キーとしてサーブレットコンテキストから取得したAxisエンジンを取得します。 <br>
209      * </dd>
210      * <dt><code>"servlet:"</code> で始まる文字列</dt>
211      * <dd><code>"servlet:"</code> の後ろの文字列をキーとしてサーブレットコンテキストから
212      * 取得したAxisエンジンを使用します。
213      * <dd>
214      * <dt><code>"s2:"</code> で始まる文字列</dt>
215      * <dd><code>"s2:"</code> の後ろの文字列をキーとしてS2コンテナから
216      * 取得したコンポーネントをAxisエンジンを使用します。</dd>
217      * <dt>その他</dt>
218      * <dd>キーとしてS2コンテナから取得したコンポーネントをAxisエンジンとして使用します。</dd>
219      * </dl>
220      * 
221      * @param container
222      *            コンテナ
223      * @return Axisエンジン
224      */
225     protected AxisEngine getEngine(final S2Container container) {
226         String engineName = S2AxisConstants.ENGINE_DEFAULT;
227 
228         final MetaDef metadata = getMetaDef(container, S2AxisConstants.META_ENGINE);
229         if (metadata != null) {
230             engineName = (String) metadata.getValue();
231         }
232 
233         if (S2AxisConstants.ENGINE_DEFAULT.equals(engineName)) {
234             if (servletContext == null) {
235                 engineName = S2AxisConstants.ENGINE_DEFAULT_CLIENT;
236             }
237             else {
238                 engineName = S2AxisConstants.ENGINE_DEFAULT_SERVER;
239             }
240         }
241 
242         AxisEngine engine = null;
243         if (S2AxisConstants.ENGINE_DEFAULT_CLIENT.equals(engineName)) {
244             final Service service = (Service) container.getComponent(javax.xml.rpc.Service.class);
245             engine = service.getEngine();
246         }
247         else if (S2AxisConstants.ENGINE_DEFAULT_SERVER.equals(engineName)) {
248             engine = (AxisEngine) servletContext.getAttribute(S2AxisConstants.AXIS_SERVLET
249                     + S2AxisConstants.ATTR_AXIS_ENGINE);
250             if (engine == null) {
251                 engine = (AxisEngine) servletContext.getAttribute(S2AxisConstants.ATTR_AXIS_ENGINE);
252             }
253         }
254         else if (engineName.startsWith(S2AxisConstants.ENGINE_FROM_SERVLET)) {
255             final String servletName = engineName.substring(S2AxisConstants.ENGINE_FROM_SERVLET
256                     .length());
257             engine = (AxisEngine) servletContext.getAttribute(servletName
258                     + S2AxisConstants.ATTR_AXIS_ENGINE);
259         }
260         else if (engineName.startsWith(S2AxisConstants.ENGINE_FROM_S2CONTAINER)) {
261             final String componentName = engineName
262                     .substring(S2AxisConstants.ENGINE_FROM_S2CONTAINER.length());
263             engine = (AxisEngine) container.getComponent(componentName);
264         }
265         else {
266             engine = (AxisEngine) container.getComponent(engineName);
267         }
268 
269         if (engine == null) {
270             throw new DeployFailedException(MessageFormatter.getSimpleMessage("EAXS0007", null));
271         }
272         return engine;
273     }
274 
275     /***
276      * <code>S2Container</code> または <code>ComponentDef</code> が名前
277      * <code>"axis-<var>localName</var></code> の <code>&lt;meta&gt;</code>
278      * 要素を持っていれば、その <code>MetaDef</code> を返します。 <br>
279      * <code>S2Container</code> または <code>ComponentDef</code> に該当する
280      * メタデータが複数定義されている場合は最初に見つかったメタデータを返します。
281      * 
282      * @param metaDefSupport
283      *            <code>S2Container</code> または <code>ComponentDef</code>
284      * @param localName
285      *            接頭辞 <code>axis-</code> に続くメタデータの名前
286      * @return 指定された名前を持つ <code>MetaDef</code> 。存在しない場合は <code>null</code>
287      */
288     protected MetaDef getMetaDef(final MetaDefAware metaDefSupport, final String localName) {
289         for (int i = 0; i < metaDefSupport.getMetaDefSize(); ++i) {
290             final MetaDef metaDef = metaDefSupport.getMetaDef(i);
291             if (localName.equals(getLocalName(metaDef))) {
292                 return metaDef;
293             }
294         }
295         return null;
296     }
297 
298     /***
299      * <code>S2Container</code> または <code>ComponentDef</code> が名前
300      * <code>"axis-<var>localName</var></code> の <code>&lt;meta&gt;</code>
301      * 要素を持っていれば、その <code>MetaDef</code> を全て返します。 <br>
302      * 
303      * @param metaDefSupport
304      *            <code>S2Container</code> または <code>ComponentDef</code>
305      * @param localName
306      *            接頭辞 <code>axis-</code> に続くメタデータの名前
307      * @return 指定された名前を持つ <code>MetaDef</code> の配列
308      */
309     protected MetaDef[] getMetaDefs(final MetaDefAware metaDefSupport, final String localName) {
310         final List result = new ArrayList();
311         for (int i = 0; i < metaDefSupport.getMetaDefSize(); ++i) {
312             final MetaDef metaDef = metaDefSupport.getMetaDef(i);
313             if (localName.equals(getLocalName(metaDef))) {
314                 result.add(metaDef);
315             }
316         }
317         return (MetaDef[]) result.toArray(new MetaDef[result.size()]);
318     }
319 
320     /***
321      * メタデータの名前がS2Axisで使用する接頭辞で始まっていれば、接頭辞の後ろのローカル名を返します。
322      * 
323      * @param metaDef
324      *            メタデータ定義
325      * @return ローカル名
326      */
327     protected String getLocalName(final MetaDef metaDef) {
328         final Matcher matcher = META_NAME_PATTERN.matcher(metaDef.getName());
329         return matcher.matches() ? matcher.group(1) : null;
330     }
331 }