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 }