Struts2.5 インターセプタ一覧(2018冬モデル) 第１回

# Struts2の共通処理層 インターセプタ

## インターセプタ(interceptor)とは

Struts2には インターセプタと呼ぶ共通処理層が用意されています。インターセプタの役割は、Struts2のWebアプリケーションを実装するActionクラスの動作の前後に処理を挟み込む（＝インターセプト）ものです。


## インターセプタの組み合わせ

インターセプタは役割に応じてクラスを細分化しています。これは実装するActionクラスに合わせてインターセプタの要・不要を切り替えやすくするためです。

Struts2が用意しているインターセプタは20以上ある[^1]ため、記述量を減らす＆再利用できるよう、インターセプタの組み合わせを定義できます。これをインターセプタ・スタック(interceptor-stack)と呼びます。

[^1]: リクエストやレスポンスを利用しやすくするために最低限必要なものはサーブレットが用意しますが、さらに汎用的かつ実装しやすくするためには、必要な機能がそれだけ存在する…という裏返しでもあります。

特にインターセプタの設定を行わない場合は、Struts2標準のインターセプタ・スタックで動作します。これをデフォルトスタック(default-stack)[^2]と呼びます。

[^2]: デフォルト・スタックは struts2-coreのjarファイルにある struts-default.xml で定義されているインターセプタ・スタックの1つであり、これを利用する定義である `<default-interceptor-ref name="defaultStack"/>` があります。

# インターセプタ一覧

Struts2標準のインターセプタは、一部を除いて[^3]は `com.opensymphony.xwork2.interceptor` パッケージか、`org.apache.struts2.interceptor`パッケージに存在しています。パッケージの違いによる動作の違いや影響はありません。

それぞれのインターセプタの詳細な説明と仕様については第2回に書きます。

[^3]: com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor

|クラス|エイリアス名|役割の概要|
|---|---|---|
|AliasInterceptor|alias|リクエストパラメータを別名のリクエストパラメータ名へ置換する|
|ActionAutowiringInterceptor|autowiring|Spring管理beanをActionクラスから参照可能にする|
|ChainingInterceptor|chain|ResultTypeにActionChainが利用できる。1つのActionから別のActionへフォワードする。|
|StrutsConversionErrorInterceptor|conversionError|自動型変換の失敗をフィールドエラーに格納する|
|CookieInterceptor|cookie|利用可能なCookieの値をActionクラスのフィールドにバインドする|
|CookieProviderInterceptor|cookieProvider|Cookie用のレスポンス出力機能。|
|ClearSessionInterceptor|clearSession|Actionクラスでセッション初期化を命令する|
|CreateSessionInterceptor|createSession|Actionクラスで新規セッション発行を命令する|
|DebuggingInterceptor|debugging|リクエストパラメータやコンテキスト情報などのサーバ側パラメータの一覧を出力する|
|ExecuteAndWaitInterceptor|execAndWait|非同期スレッドを1つ起動しActionクラスの終了までポーリングする|
|ExceptionMappingInterceptor|exception|Actionクラスから発生した例外に対するエラーレスポンスを制御する|
|FileUploadInterceptor|fileUpload|ファイルアップロード用のフォールやマルチパート処理に関して制御する|
|I18nInterceptor|i18n|ロケール切り替えを制御する|
|LoggingInterceptor|logger|実行したActionのNamespace名とAction名を出力する|
|ModelDrivenInterceptor|modelDriven|リクエストパラメータをmodelフィールドへバインドし、レスポンスではプレフィックスが省略できる。|
|ScopedModelDrivenInterceptor|scopedModelDriven|リクエストパラメータをmodelフィールドへバインドし、レスポンスではプレフィックスが省略できる。バインド先にリクエスト属性とセッション属性が利用できる|
|ParametersInterceptor|params|特定のリクエストパラメータをサニタイズする|
|ParameterRemoverInterceptor|paramRemover|特定のリクエストパラメータを削除する。|
|ActionMappingParametersInterceptor|actionMappingParams|Actionクラスのフィールドへリクエストパラメータをマッピングする|
|PrepareInterceptor|prepare|Actionクラスのexecuteメソッドが動作する前に動くメソッドを実行する。|
|StaticParametersInterceptor|staticParams|Actionクラスの静的パラメータの内容を取得し、必要があれば上書きした内容を返す。|
|ScopeInterceptor|scope|複数画面で続けて入力をしていくウィザード形式入力画面の入力値を管理する|
|ServletConfigInterceptor|servletConfig|サーブレット管理の属性をStruts2へ引き渡す|
|TimerInterceptor|timer|インターセプタの開始～終了までにかかった時間をミリ秒で出力|
|TokenInterceptor|token|CSRF防止用のトークンをチェックし、トークン不一致のときはエラーを返す。後述のTokenSessionStoreInterceptorの利用を推奨している。|
|TokenSessionStoreInterceptor|tokenSession|セッション単位のCSRF防止トークンのチェック。トークン不一致のときはエラーを返す。|
|AnnotationValidationInterceptor|validation|入力値検証を検証専用のアノテーションで扱う|
|DefaultWorkflowInterceptor|workflow|Actionクラスのメソッド名からValidationを実施しないかを判定する|
|MessageStoreInterceptor|store|Validationエラーメッセージをセッションへもコピーしておき、別のActionでも過去のエラーメッセージを取り出せる機構|
|CheckboxInterceptor|checkbox|チェックボックス用拡張。項目チェックをtrue/falseで受け取れるよう変換する。|
|DateTextFieldInterceptor|datetime|？リクエストパラメータに時間用パラメータがある場合は変換？|
|ProfilingActivationInterceptor|profiling|デバッグやAction時間経過などの観測On/Offをリクエストパラメータで扱うかを判定|
|RolesInterceptor|roles|ロールベース認証後のユーザに付与されたロールに対して動作を許可・拒否する|
|AnnotationWorkflowInterceptor|annotationWorkflow|アノテーションでActionクラス動作を定義する。|
|AnnotationParameterFilterInterceptor|annotationParameterFilter|アノテーションでActionクラスにバインド許可・拒否するリクエストパラメータを設定する|
|MultiselectInterceptor|multiselect|セレクトボックス入力値の選択・非選択をbooleanで扱う|
|NoOpInterceptor|noop|何もしないインターセプタ。インターセプタを何も選択しないempty stackでのみ利用する|

## 凡例説明

|項目名|説明|
|---|---|
|クラス名|インターセプタのクラス名です。パッケージは省略しています。|
|エイリアス|Struts2の設定ファイル内で扱う別名です。|
|役割の概要|インターセプタの主な役割です。詳細は後述していきます。|

# インターセプタの設定方法

struts.xml ないしは Actionクラスの `@InterceptorRefs` で設定します。

## インターセプタの追加方法

### struts.xml(Actionクラスごとの定義)

```xml
<action name="register" class="org.apache.struts.register.action.Register" method="execute">
    <interceptor-ref name="defaultStack">
        <param name="exception.logEnabled">true</param>
        <param name="exception.logLevel">ERROR</param>
    </interceptor-ref>
    <result name="success">thankyou.jsp</result>
    <result name="input">register.jsp</result>
</action>
```

interceptor-ref 要素で利用するインターセプタならびにインターセプタ・スタックを定義します。
指定したインターセプタ・スタックの中で、特定のインターセプタの設定だけを変えたい場合は、param子要素で個別に指定できます。

指定方法は、インターセプタのエイリアス名.プロパティ名です。

上記の例では、ExceptionInterceptorのlogEnabledをtrueに、logLevelをERRORに設定しています。

### アノテーションでの定義

アノテーションを使った定義は、xmlと同様です。

```java
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.InterceptorRef;
import org.apache.struts2.convention.annotation.InterceptorRefs;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;

import com.opensymphony.xwork2.ActionSupport;

@InterceptorRefs(
	@InterceptorRef(value="defaultStack", params= {"exception.logEnabled","true","exception.logLevel","ERROR"})
)
@Results({
    @Result(name = ActionSupport.SUCCESS, type = "dispatcher", location="sports.jsp")
})
public class SportsAction extends ActionSupport {

}
```

`@InterceptorRefs`は、複数の`@InterceptorRef`を含めます。valueにインターセプタやインターセプタ・スタック名を指定、paramsにカスタマイズするインターセプタのプロパティと値の順に文字列で記載します。

# インターセプタの自作

インターセプタを作るには、全てのActionで動作する AbstractInterceptor と、特定のメソッドだけ動作させる MethodFilterInterceptor が抽象クラス用意されており、用途にあわせてこれを継承します。

## AbstractInterceptor

唯一の拡張ポイントである intercept メソッドを実装します。

```java
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

public class SampleInterceptor extends AbstractInterceptor {

	@Override
	public String intercept(ActionInvocation invocation) throws Exception {

		//
		// Action・後続インターセプタの前処理
		//

		String result = invocation.invoke();

		//
		// Action・後続インターセプタの後処理
		//

		return result;
	}
}
```

invocation.invoke() の戻り値は、Actionクラスからreturnで返す値そのものです。インターセプタはこれを伝搬させていきます。

## MethodFilterInterceptor

MethodFilterInterceptorを継承したクラスは、doIntercept メソッドが拡張ポイントです。それ以外は AbstractInterceptorと一緒です。動作するメソッドの設定はインターセプタを利用するActionクラスやstruts.xmlで行います。

```java
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;

public class SampleMethodInterceptor extends MethodFilterInterceptor {

	@Override
	protected String doIntercept(ActionInvocation invocation) throws Exception {

		//
		// Action・後続インターセプタの前処理
		//

		String result = invocation.invoke();

		//
		// Action・後続インターセプタの後処理
		//

		return result;
	}

}
```

## 除外メソッドの登録方法

MethodFilterInterceptor を実装したクラスは、利用時のパラメータに excludeMethods を指定することで **その名前のメソッドだった場合は実行しません**。メソッド名はカンマ区切りで指定できます。

### 設定例

Struts2-JSONプラグインの例

```xml
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
	"http://struts.apache.org/dtds/struts-2.5.dtd">

<struts>
    <package name="json-default" extends="struts-default">
    ....
        <interceptors>
            <interceptor name="json" class="org.apache.struts2.json.JSONInterceptor"/>
            <interceptor name="jsonValidation" class="org.apache.struts2.json.JSONValidationInterceptor"/>

            <!-- Sample JSON validation stack -->
            <interceptor-stack name="jsonValidationWorkflowStack">
                <interceptor-ref name="basicStack"/>
                <interceptor-ref name="validation">
                    <param name="excludeMethods">input,back,cancel</param>
                </interceptor-ref>
                <interceptor-ref name="jsonValidation"/>
                <interceptor-ref name="workflow"/>
            </interceptor-stack>

        </interceptors>
    </package>
</struts>
```

この例の場合、json-defaultの名前で定義されたパッケージ(アノテーションの場合は `@NameSpace`)を利用したActionクラスでは、validationインターセプタは、input、back、cancelの名前だった場合は実行されません。

## インターセプタで実装できること

メソッドの引数にある ActionInvocation から、インターセプタを経由している最中のアプリケーションコンテキストやリクエスト情報などを取得できます。最も基本的な使い方は、処理しているときのコンテキストを取得する getInvocationContext()から、ActionContextを取得し、このActionContextに格納されている ValueStack や リクエストパラメータを格納している HttpParameters を取得できます。

```java
protected String doIntercept(ActionInvocation invocation) throws Exception {

	ActionContext context = invocation.getInvocationContext();

	ValueStack stack = context.getValueStack();
	HttpParameters parameters = context.getParameters();

	String result = invocation.invoke();
	return result;
}
```

# インターセプタの積み上げ方

基本となるのはstruts-default.xmlに記載されているdefaultStackの後に動作させるか、完全に新しいインターセプタ・スタックを作成します。
なお、インターセプタ・スタックは複数のインターセプタをまとめて設定できるものなので、インターセプタ・スタックを利用せず、インターセプタだけを設定しても動作しますし、インターセプタの積み上げには、インターセプタとインターセプタ・スタックを混ぜても問題ありません。

## 積み方の例

### デフォルト・スタック

デフォルト・スタックは最も標準で、かつ特に何も変更することがないならこのインターセプタ・スタックの利用を推奨しています。
その理由として、例外ハンドリングやパラメータ置換、パラメータの自動型変換の順番はこの順序で行うようStruts2の作りができており、この順序を変えるとStruts2の内部で検出した例外が正しく制御できません。

```xml
<interceptor-stack name="defaultStack">                               
    <interceptor-ref name="exception"/>                               
    <interceptor-ref name="alias"/>                                   
    <interceptor-ref name="servletConfig"/>                           
    <interceptor-ref name="i18n"/>                                    
    <interceptor-ref name="prepare"/>                                 
    <interceptor-ref name="chain"/>                                   
    <interceptor-ref name="scopedModelDriven"/>                       
    <interceptor-ref name="modelDriven"/>                             
    <interceptor-ref name="fileUpload"/>                              
    <interceptor-ref name="checkbox"/>                                
    <interceptor-ref name="datetime"/>                                
    <interceptor-ref name="multiselect"/>                             
    <interceptor-ref name="staticParams"/>                            
    <interceptor-ref name="actionMappingParams"/>                     
    <interceptor-ref name="params"/>                                  
    <interceptor-ref name="conversionError"/>                         
    <interceptor-ref name="validation">                               
        <param name="excludeMethods">input,back,cancel,browse</param> 
    </interceptor-ref>                                                
    <interceptor-ref name="workflow">                                 
        <param name="excludeMethods">input,back,cancel,browse</param> 
    </interceptor-ref>                                                
    <interceptor-ref name="debugging"/>                               
</interceptor-stack>                                                  
```

#### デフォルト・スタックで実現していること

デフォルト・スタックは「必ず使う機能」以外にも「おそらく使われると推測される」機能も導入されています。必須機能以外のインターセプタは余計な機能でもあるので、例えばcheckboxやmultiselect、uploadの機能を使う予定がなければ、新たに解除したインターセプタ・スタックを作って利用するのも良いでしょう。

### インターセプタ・スタックとインターセプタの混成

前述した Struts2-JSONプラグインのように、混成もできます。

```xml
<interceptor-stack name="jsonValidationWorkflowStack">
  <interceptor-ref name="basicStack"/>
  <interceptor-ref name="validation">
    <param name="excludeMethods">input,back,cancel</param>
  </interceptor-ref>
  <interceptor-ref name="jsonValidation"/>
  <interceptor-ref name="workflow"/>
</interceptor-stack>
```

basicStackはstruts-default.xmlに記載されているインターセプタ・スタックの1つです。

```xml
<!-- Basic stack -->
<interceptor-stack name="basicStack">
  <interceptor-ref name="exception"/>
  <interceptor-ref name="servletConfig"/>
  <interceptor-ref name="prepare"/>
  <interceptor-ref name="checkbox"/>
  <interceptor-ref name="datetime"/>
  <interceptor-ref name="multiselect"/>
  <interceptor-ref name="actionMappingParams"/>
  <interceptor-ref name="params"/>
  <interceptor-ref name="conversionError"/>
</interceptor-stack>
```

そのため、jsonValidationWorkflowStack は 次の宣言と同じになります。

```xml
<interceptor-stack name="jsonValidationWorkflowStack">
  <interceptor-ref name="exception"/>
  <interceptor-ref name="servletConfig"/>
  <interceptor-ref name="prepare"/>
  <interceptor-ref name="checkbox"/>
  <interceptor-ref name="datetime"/>
  <interceptor-ref name="multiselect"/>
  <interceptor-ref name="actionMappingParams"/>
  <interceptor-ref name="params"/>
  <interceptor-ref name="conversionError"/>
  <interceptor-ref name="validation">
    <param name="excludeMethods">input,back,cancel</param>
  </interceptor-ref>
  <interceptor-ref name="jsonValidation"/>
  <interceptor-ref name="workflow"/>
</interceptor-stack>
```

# Appendix

## 参考文献

[https://struts.apache.org/getting-started/introducing-interceptors.html](https://struts.apache.org/getting-started/introducing-interceptors.html)

## struts-default.xml

```xml:struts-default.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!--
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
-->

<!--
    When declaring beans in this file you must either use name="struts" or don't name the bean at all.

    The name="struts" must be used when alias was defined in {@link org.apache.struts2.config.DefaultBeanSelectionProvider} -
    it is then the default bean's name and {@link org.apache.struts2.config.DefaultBeanSelectionProvider} links name "struts"
    with "default" (aliasing it)

    If name won't be defined then the "default" value will be used {@link com.opensymphony.xwork2.inject.Container#DEFAULT_NAME}
    and {@link com.opensymphony.xwork2.inject.Inject}
-->
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
    "http://struts.apache.org/dtds/struts-2.5.dtd">

<struts>

    <constant name="struts.excludedClasses"
              value="
                java.lang.Object,
                java.lang.Runtime,
                java.lang.System,
                java.lang.Class,
                java.lang.ClassLoader,
                java.lang.Shutdown,
                java.lang.ProcessBuilder,
                com.opensymphony.xwork2.ActionContext" />

    <!-- this must be valid regex, each '.' in package name must be escaped! -->
    <!-- it's more flexible but slower than simple string comparison -->
    <!-- constant name="struts.excludedPackageNamePatterns" value="^java\.lang\..*,^ognl.*,^(?!javax\.servlet\..+)(javax\..+)" / -->

    <!-- this is simpler version of the above used with string comparison -->
    <constant name="struts.excludedPackageNames"
              value="
                ognl.,
                javax.,
                freemarker.core.,
                freemarker.template.,
                freemarker.ext.rhino.,
                sun.reflect.,
                javassist.,
                com.opensymphony.xwork2.ognl.,
                com.opensymphony.xwork2.security.,
                com.opensymphony.xwork2.util." />

    <bean class="com.opensymphony.xwork2.ObjectFactory" name="struts"/>
    <bean type="com.opensymphony.xwork2.factory.ResultFactory" name="struts" class="org.apache.struts2.factory.StrutsResultFactory" />
    <bean type="com.opensymphony.xwork2.factory.ActionFactory" name="struts" class="com.opensymphony.xwork2.factory.DefaultActionFactory" />
    <bean type="com.opensymphony.xwork2.factory.ConverterFactory" name="struts" class="com.opensymphony.xwork2.factory.DefaultConverterFactory" />
    <bean type="com.opensymphony.xwork2.factory.InterceptorFactory" name="struts" class="com.opensymphony.xwork2.factory.DefaultInterceptorFactory" />
    <bean type="com.opensymphony.xwork2.factory.ValidatorFactory" name="struts" class="com.opensymphony.xwork2.factory.DefaultValidatorFactory" />
    <bean type="com.opensymphony.xwork2.factory.UnknownHandlerFactory" name="struts" class="com.opensymphony.xwork2.factory.DefaultUnknownHandlerFactory" />

    <bean type="com.opensymphony.xwork2.FileManager" class="com.opensymphony.xwork2.util.fs.DefaultFileManager" name="system" scope="singleton"/>
    <bean type="com.opensymphony.xwork2.FileManagerFactory" class="com.opensymphony.xwork2.util.fs.DefaultFileManagerFactory" name="struts" scope="singleton"/>

    <bean type="com.opensymphony.xwork2.ActionProxyFactory" name="struts" class="org.apache.struts2.factory.StrutsActionProxyFactory"/>
    <bean type="com.opensymphony.xwork2.ActionProxyFactory" name="prefix" class="org.apache.struts2.factory.PrefixBasedActionProxyFactory"/>

    <bean type="com.opensymphony.xwork2.conversion.ObjectTypeDeterminer" name="struts" class="com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer"/>

    <bean type="com.opensymphony.xwork2.util.PatternMatcher" name="struts" class="com.opensymphony.xwork2.util.WildcardHelper" />
    <bean type="com.opensymphony.xwork2.util.PatternMatcher" name="namedVariable" class="com.opensymphony.xwork2.util.NamedVariablePatternMatcher"/>
    <bean type="com.opensymphony.xwork2.util.PatternMatcher" name="regex" class="org.apache.struts2.util.RegexPatternMatcher"/>

    <bean type="org.apache.struts2.util.ContentTypeMatcher" name="struts" class="org.apache.struts2.util.DefaultContentTypeMatcher"/>

    <bean type="org.apache.struts2.dispatcher.mapper.ActionMapper" name="struts" class="org.apache.struts2.dispatcher.mapper.DefaultActionMapper" />
    <bean type="org.apache.struts2.dispatcher.mapper.ActionMapper" name="composite" class="org.apache.struts2.dispatcher.mapper.CompositeActionMapper" />
    <bean type="org.apache.struts2.dispatcher.mapper.ActionMapper" name="restful" class="org.apache.struts2.dispatcher.mapper.RestfulActionMapper" />
    <bean type="org.apache.struts2.dispatcher.mapper.ActionMapper" name="restful2" class="org.apache.struts2.dispatcher.mapper.Restful2ActionMapper" />

    <bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="jakarta" class="org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest" scope="prototype"/>
    <bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="jakarta-stream" class="org.apache.struts2.dispatcher.multipart.JakartaStreamMultiPartRequest" scope="prototype"/>

    <bean type="org.apache.struts2.views.TagLibraryDirectiveProvider" name="s" class="org.apache.struts2.views.DefaultTagLibrary" />
    <bean type="org.apache.struts2.views.TagLibraryModelProvider" name="s" class="org.apache.struts2.views.DefaultTagLibrary" />

    <bean class="org.apache.struts2.views.freemarker.FreemarkerThemeTemplateLoader" />
    <bean class="org.apache.struts2.views.freemarker.FreemarkerManager" name="struts" />
    <bean class="org.apache.struts2.views.velocity.VelocityManager" name="struts" optional="true" />

    <bean class="org.apache.struts2.components.template.TemplateEngineManager" />
    <bean type="org.apache.struts2.components.template.TemplateEngine" name="ftl" class="org.apache.struts2.components.template.FreemarkerTemplateEngine" />
    <bean type="org.apache.struts2.components.template.TemplateEngine" name="vm" class="org.apache.struts2.components.template.VelocityTemplateEngine" />
    <bean type="org.apache.struts2.components.template.TemplateEngine" name="jsp" class="org.apache.struts2.components.template.JspTemplateEngine" />

    <bean type="com.opensymphony.xwork2.conversion.impl.XWorkConverter" name="struts" class="com.opensymphony.xwork2.conversion.impl.XWorkConverter" />

    <bean type="com.opensymphony.xwork2.conversion.ConversionPropertiesProcessor" name="struts" class="com.opensymphony.xwork2.conversion.impl.DefaultConversionPropertiesProcessor" />
    <bean type="com.opensymphony.xwork2.conversion.ConversionFileProcessor" name="struts" class="com.opensymphony.xwork2.conversion.impl.DefaultConversionFileProcessor" />
    <bean type="com.opensymphony.xwork2.conversion.ConversionAnnotationProcessor" name="struts" class="com.opensymphony.xwork2.conversion.impl.DefaultConversionAnnotationProcessor" />
    <bean type="com.opensymphony.xwork2.conversion.TypeConverterCreator" name="struts" class="com.opensymphony.xwork2.conversion.impl.DefaultTypeConverterCreator" />
    <bean type="com.opensymphony.xwork2.conversion.TypeConverterHolder" name="struts" class="com.opensymphony.xwork2.conversion.impl.DefaultTypeConverterHolder" />

    <bean class="com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter" />

    <bean type="com.opensymphony.xwork2.conversion.impl.CollectionConverter" name="struts" class="com.opensymphony.xwork2.conversion.impl.CollectionConverter" scope="singleton"/>
    <bean type="com.opensymphony.xwork2.conversion.impl.ArrayConverter" name="struts" class="com.opensymphony.xwork2.conversion.impl.ArrayConverter" scope="singleton"/>
    <bean type="com.opensymphony.xwork2.conversion.impl.DateConverter" name="struts" class="com.opensymphony.xwork2.conversion.impl.DateConverter" scope="singleton"/>
    <bean type="com.opensymphony.xwork2.conversion.impl.NumberConverter" name="struts" class="com.opensymphony.xwork2.conversion.impl.NumberConverter" scope="singleton"/>
    <bean type="com.opensymphony.xwork2.conversion.impl.StringConverter" name="struts" class="com.opensymphony.xwork2.conversion.impl.StringConverter" scope="singleton"/>

    <bean type="com.opensymphony.xwork2.LocalizedTextProvider" name="global-only" class="com.opensymphony.xwork2.util.GlobalLocalizedTextProvider" scope="singleton" />
    <bean type="com.opensymphony.xwork2.LocalizedTextProvider" name="struts" class="com.opensymphony.xwork2.util.StrutsLocalizedTextProvider" scope="singleton" />

    <bean type="com.opensymphony.xwork2.TextProvider" name="system" class="com.opensymphony.xwork2.DefaultTextProvider" scope="singleton" />
    <bean type="com.opensymphony.xwork2.TextProviderFactory" name="struts" class="com.opensymphony.xwork2.StrutsTextProviderFactory" scope="singleton" />
    <bean type="com.opensymphony.xwork2.LocaleProviderFactory" name="struts" class="com.opensymphony.xwork2.DefaultLocaleProviderFactory" scope="singleton" />

    <bean type="org.apache.struts2.components.UrlRenderer" name="struts" class="org.apache.struts2.components.ServletUrlRenderer"/>
    <bean type="org.apache.struts2.views.util.UrlHelper" name="struts" class="org.apache.struts2.views.util.DefaultUrlHelper"/>

    <bean type="com.opensymphony.xwork2.util.ValueStackFactory" name="struts" class="com.opensymphony.xwork2.ognl.OgnlValueStackFactory" />
    <bean type="com.opensymphony.xwork2.util.reflection.ReflectionProvider" name="struts" class="com.opensymphony.xwork2.ognl.OgnlReflectionProvider" />
    <bean type="com.opensymphony.xwork2.util.reflection.ReflectionContextFactory" name="struts" class="com.opensymphony.xwork2.ognl.OgnlReflectionContextFactory" />

    <bean type="com.opensymphony.xwork2.conversion.NullHandler" name="java.lang.Object" class="com.opensymphony.xwork2.conversion.impl.InstantiatingNullHandler" />

    <bean type="com.opensymphony.xwork2.validator.ActionValidatorManager" name="struts" class="com.opensymphony.xwork2.validator.AnnotationActionValidatorManager" />
    <bean type="com.opensymphony.xwork2.validator.ActionValidatorManager" name="no-annotations" class="com.opensymphony.xwork2.validator.DefaultActionValidatorManager" />

    <bean type="com.opensymphony.xwork2.validator.ValidatorFactory" class="com.opensymphony.xwork2.validator.DefaultValidatorFactory"/>
    <bean type="com.opensymphony.xwork2.validator.ValidatorFileParser" class="com.opensymphony.xwork2.validator.DefaultValidatorFileParser" />

    <bean class="com.opensymphony.xwork2.ognl.OgnlUtil" />

    <bean type="com.opensymphony.xwork2.util.TextParser" name="struts" class="com.opensymphony.xwork2.util.OgnlTextParser" scope="singleton"/>

    <bean type="ognl.PropertyAccessor" name="com.opensymphony.xwork2.util.CompoundRoot" class="com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor" />
    <bean type="ognl.PropertyAccessor" name="java.lang.Object" class="com.opensymphony.xwork2.ognl.accessor.ObjectAccessor" />
    <bean type="ognl.PropertyAccessor" name="java.util.Iterator" class="com.opensymphony.xwork2.ognl.accessor.XWorkIteratorPropertyAccessor" />
    <bean type="ognl.PropertyAccessor" name="java.util.Enumeration" class="com.opensymphony.xwork2.ognl.accessor.XWorkEnumerationAccessor" />
    <bean type="ognl.PropertyAccessor" name="java.util.List" class="com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor" />
    <bean type="ognl.PropertyAccessor" name="java.util.Set" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
    <bean type="ognl.PropertyAccessor" name="java.util.Map" class="com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor" />
    <bean type="ognl.PropertyAccessor" name="java.util.Collection" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
    <bean type="ognl.PropertyAccessor" name="com.opensymphony.xwork2.ognl.ObjectProxy" class="com.opensymphony.xwork2.ognl.accessor.ObjectProxyPropertyAccessor" />
    <bean type="ognl.PropertyAccessor" name="org.apache.struts2.dispatcher.HttpParameters" class="com.opensymphony.xwork2.ognl.accessor.HttpParametersPropertyAccessor" />
    <bean type="ognl.PropertyAccessor" name="org.apache.struts2.dispatcher.Parameter" class="com.opensymphony.xwork2.ognl.accessor.ParameterPropertyAccessor" />

    <bean type="ognl.MethodAccessor" name="java.lang.Object" class="com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor" />
    <bean type="ognl.MethodAccessor" name="com.opensymphony.xwork2.util.CompoundRoot" class="com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor" />

    <bean class="org.apache.struts2.views.jsp.ui.OgnlTool" />

    <bean type="org.apache.struts2.dispatcher.StaticContentLoader" class="org.apache.struts2.dispatcher.DefaultStaticContentLoader" name="struts" />
    <bean type="com.opensymphony.xwork2.UnknownHandlerManager" class="com.opensymphony.xwork2.DefaultUnknownHandlerManager" name="struts" />

    <bean type="org.apache.struts2.dispatcher.DispatcherErrorHandler" name="struts" class="org.apache.struts2.dispatcher.DefaultDispatcherErrorHandler" />
    
    <constant name="struts.dispatcher.errorHandler" value="struts" />

    <!--  Silly workarounds for OGNL since there is currently no way to flush its internal caches -->
    <bean type="ognl.PropertyAccessor" name="java.util.ArrayList" class="com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor" />
    <bean type="ognl.PropertyAccessor" name="java.util.HashSet" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
    <bean type="ognl.PropertyAccessor" name="java.util.HashMap" class="com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor" />

    <bean type="com.opensymphony.xwork2.security.ExcludedPatternsChecker" name="struts" class="com.opensymphony.xwork2.security.DefaultExcludedPatternsChecker" scope="prototype" />
    <bean type="com.opensymphony.xwork2.security.AcceptedPatternsChecker" name="struts" class="com.opensymphony.xwork2.security.DefaultAcceptedPatternsChecker" scope="prototype" />

    <bean type="com.opensymphony.xwork2.config.providers.ValueSubstitutor" class="com.opensymphony.xwork2.config.providers.EnvsValueSubstitutor" scope="singleton"/>

    <package name="struts-default" abstract="true" strict-method-invocation="true">
        <result-types>
            <result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
            <result-type name="dispatcher" class="org.apache.struts2.result.ServletDispatcherResult" default="true"/>
            <result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/>
            <result-type name="httpheader" class="org.apache.struts2.result.HttpHeaderResult"/>
            <result-type name="redirect" class="org.apache.struts2.result.ServletRedirectResult"/>
            <result-type name="redirectAction" class="org.apache.struts2.result.ServletActionRedirectResult"/>
            <result-type name="stream" class="org.apache.struts2.result.StreamResult"/>
            <result-type name="velocity" class="org.apache.struts2.result.VelocityResult"/>
            <result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/>
            <result-type name="plainText" class="org.apache.struts2.result.PlainTextResult" />
            <result-type name="postback" class="org.apache.struts2.result.PostbackResult" />
        </result-types>

        <interceptors>
            <interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
            <interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
            <interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
            <interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
            <interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/>
            <interceptor name="cookieProvider" class="org.apache.struts2.interceptor.CookieProviderInterceptor"/>
            <interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />
            <interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
            <interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
            <interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
            <interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
            <interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
            <interceptor name="i18n" class="org.apache.struts2.interceptor.I18nInterceptor"/>
            <interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
            <interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
            <interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>
            <interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
            <interceptor name="paramRemover" class="com.opensymphony.xwork2.interceptor.ParameterRemoverInterceptor"/>
            <interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInterceptor"/>
            <interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
            <interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>
            <interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>
            <interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
            <interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>
            <interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
            <interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>
            <interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
            <interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
            <interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" />
            <interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
            <interceptor name="datetime" class="org.apache.struts2.interceptor.DateTextFieldInterceptor" />
            <interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
            <interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />
            <interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" />
            <interceptor name="annotationParameterFilter" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationParameterFilterInterceptor" />
            <interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" />
            <interceptor name="noop" class="org.apache.struts2.interceptor.NoOpInterceptor" />

            <!-- Empty stack - performs no operations -->
            <interceptor-stack name="emptyStack">
                <interceptor-ref name="noop"/>
            </interceptor-stack>

            <!-- Basic stack -->
            <interceptor-stack name="basicStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="datetime"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params"/>
                <interceptor-ref name="conversionError"/>
            </interceptor-stack>

            <!-- Sample validation and workflow stack -->
            <interceptor-stack name="validationWorkflowStack">
                <interceptor-ref name="basicStack"/>
                <interceptor-ref name="validation"/>
                <interceptor-ref name="workflow"/>
            </interceptor-stack>

            <!-- Sample file upload stack -->
            <interceptor-stack name="fileUploadStack">
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="basicStack"/>
            </interceptor-stack>

            <!-- Sample model-driven stack  -->
            <interceptor-stack name="modelDrivenStack">
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="basicStack"/>
            </interceptor-stack>

            <!-- Sample action chaining stack -->
            <interceptor-stack name="chainStack">
                <interceptor-ref name="chain"/>
                <interceptor-ref name="basicStack"/>
            </interceptor-stack>

            <!-- Sample i18n stack -->
            <interceptor-stack name="i18nStack">
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="basicStack"/>
            </interceptor-stack>

            <!-- An example of the paramsPrepareParams trick. This stack
                 is exactly the same as the defaultStack, except that it
                 includes one extra interceptor before the prepare interceptor:
                 the params interceptor.

                 This is useful for when you wish to apply parameters directly
                 to an object that you wish to load externally (such as a DAO
                 or database or service layer), but can't load that object
                 until at least the ID parameter has been loaded. By loading
                 the parameters twice, you can retrieve the object in the
                 prepare() method, allowing the second params interceptor to
                 apply the values on the object. -->
            <interceptor-stack name="paramsPrepareParamsStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="alias"/>
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="datetime"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="params"/>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="chain"/>
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="staticParams"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params"/>
                <interceptor-ref name="conversionError"/>
                <interceptor-ref name="validation">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="workflow">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
            </interceptor-stack>

            <!-- A complete stack with all the common interceptors in place.
                 Generally, this stack should be the one you use, though it
                 may do more than you need. Also, the ordering can be
                 switched around (ex: if you wish to have your servlet-related
                 objects applied before prepare() is called, you'd need to move
                 servletConfig interceptor up.

                 This stack also excludes from the normal validation and workflow
                 the method names input, back, and cancel. These typically are
                 associated with requests that should not be validated.
                 -->
            <interceptor-stack name="defaultStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="alias"/>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="chain"/>
                <interceptor-ref name="scopedModelDriven"/>
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="datetime"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="staticParams"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params"/>
                <interceptor-ref name="conversionError"/>
                <interceptor-ref name="validation">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="workflow">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="debugging"/>
            </interceptor-stack>

            <!-- The completeStack is here for backwards compatibility for
                 applications that still refer to the defaultStack by the
                 old name -->
            <interceptor-stack name="completeStack">
                <interceptor-ref name="defaultStack"/>
            </interceptor-stack>

            <!-- Sample execute and wait stack.
                 Note: execAndWait should always be the *last* interceptor. -->
            <interceptor-stack name="executeAndWaitStack">
                <interceptor-ref name="execAndWait">
                    <param name="excludeMethods">input,back,cancel</param>
                </interceptor-ref>
                <interceptor-ref name="defaultStack"/>
                <interceptor-ref name="execAndWait">
                    <param name="excludeMethods">input,back,cancel</param>
                </interceptor-ref>
            </interceptor-stack>

       </interceptors>

        <default-interceptor-ref name="defaultStack"/>

        <default-class-ref class="com.opensymphony.xwork2.ActionSupport" />

        <global-allowed-methods>execute,input,back,cancel,browse,save,delete,list,index</global-allowed-methods>

    </package>

</struts>

```