/*
* Copyright 2004-2015 the Seasar Foundation and the Others.
*
* Licensed 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.
*/
package org.seasar.framework.unit.impl;
import java.lang.reflect.Method;
import java.sql.Types;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.seasar.extension.dataset.ColumnType;
import org.seasar.extension.dataset.DataSet;
import org.seasar.extension.dataset.types.ColumnTypes;
import org.seasar.framework.aop.interceptors.MockInterceptor;
import org.seasar.framework.container.AspectDef;
import org.seasar.framework.container.ComponentDef;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.annotation.tiger.Binding;
import org.seasar.framework.container.annotation.tiger.BindingType;
import org.seasar.framework.container.annotation.tiger.DestroyMethod;
import org.seasar.framework.container.annotation.tiger.InitMethod;
import org.seasar.framework.container.deployer.InstanceDefFactory;
import org.seasar.framework.container.factory.S2ContainerFactory;
import org.seasar.framework.container.factory.TigerAnnotationHandler;
import org.seasar.framework.convention.NamingConvention;
import org.seasar.framework.message.MessageResourceBundleFactory;
import org.seasar.framework.unit.ConfigFileIncluder;
import org.seasar.framework.unit.ExpectedDataReader;
import org.seasar.framework.unit.InternalTestContext;
import org.seasar.framework.unit.PreparationType;
import org.seasar.framework.unit.TestDataPreparer;
import org.seasar.framework.util.ClassUtil;
import org.seasar.framework.util.ResourceUtil;
import org.seasar.framework.util.tiger.CollectionsUtil;
/**
* Servlet、JTA、EJB3のAPIに依存せずにS2JUnit4を実行可能にするシンプルなテストコンテキストです。
*
* @author taedium
*/
public class SimpleInternalTestContext implements InternalTestContext {
/** Tigerのアノテーションハンドラー */
protected final TigerAnnotationHandler handler = new TigerAnnotationHandler();
/** モックインターセプターのリスト */
protected final List<MockInterceptor> mockInterceptors = CollectionsUtil
.newArrayList();
/** ルートのS2コンテナ */
protected S2Container container;
/** 命名規約 */
protected NamingConvention namingConvention;
/** テストクラス */
protected Class<?> testClass;
/** テストメソッド */
protected Method testMethod;
/** 自動インクルードをするかどうかを表すフラグ。デフォルトは<code>true</code> */
protected boolean autoIncluding = true;
/** テストデータを自動準備するかどうかを表すフラグ。デフォルトは<code>true</code> */
protected boolean autoPreparing = true;
/** テストデータの準備方法 */
protected PreparationType preparationType = PreparationType.WRITE;
/** テストデータの文字列に含まれる空白を取り除くかどうかを表すフラグ。デフォルトは<code>true</code> */
protected boolean trimString = true;
/** EJB3を使用するかどうかを表すフラグ。デフォルトは<code>false</code> */
protected boolean ejb3Enabled = false;
/** JTAを使用するかどうかを表すフラグ。デフォルトは<code>false</code> */
protected boolean jtaEnabled = false;
/** S2コンテナが初期化されたかどうかを表すフラグ */
protected boolean containerInitialized;
/** {@link ColumnTypes}から登録除去された{@link ColumnType カラムの型}をクラスをキーにして管理するマップ */
protected Map<Class<?>, ColumnType> deregisteredColumnTypesByClass = new HashMap<Class<?>, ColumnType>();
/** {@link ColumnTypes}から登録除去された{@link ColumnType カラムの型}をSQL型をキーにして管理するマップ */
protected Map<Integer, ColumnType> deregisteredColumnTypesBySqlType = new HashMap<Integer, ColumnType>();
/**
* S2コンテナを設定します。
*
* @param container
* S2コンテナ
*/
@Binding(bindingType = BindingType.MUST)
public void setContainer(final S2Container container) {
this.container = container.getRoot();
}
/**
* EJB3を使用する場合<code>true</code>を設定します。
*
* @param ejb3Enabled
* EJB3を使用する場合<code>true</code>、使用しない場合<code>false</code>
*/
@Binding(bindingType = BindingType.MAY)
public void setEjb3Enabled(boolean ejb3Enabled) {
this.ejb3Enabled = ejb3Enabled;
}
/**
* JTAを使用する場合<code>true</code>を設定します。
*
* @param jtaEnabled
* JTAを使用する場合<code>true</code>、使用しない場合<code>false</code>
*/
@Binding(bindingType = BindingType.MAY)
public void setJtaEnabled(boolean jtaEnabled) {
this.jtaEnabled = jtaEnabled;
}
public void setAutoIncluding(final boolean autoIncluding) {
this.autoIncluding = autoIncluding;
}
public void setAutoPreparing(final boolean autoPreparing) {
this.autoPreparing = autoPreparing;
}
public PreparationType getPreparationType() {
return preparationType;
}
public void setPreparationType(PreparationType preparationType) {
this.preparationType = preparationType;
}
public void setTrimString(final boolean trimString) {
this.trimString = trimString;
}
public boolean isTrimString() {
return trimString;
}
public void setTestClass(final Class<?> testClass) {
this.testClass = testClass;
}
public void setTestMethod(final Method testMethod) {
this.testMethod = testMethod;
}
@Binding(bindingType = BindingType.NONE)
public void setNamingConvention(NamingConvention namingConvention) {
this.namingConvention = namingConvention;
}
/**
* このコンポーネントを初期化します。
*
* @throws Throwable
*/
@InitMethod
public void init() throws Throwable {
}
/**
* このコンポーネントを破棄します。
*/
@DestroyMethod
public void destroy() {
MessageResourceBundleFactory.clear();
}
public void initContainer() {
container.init();
containerInitialized = true;
}
public void destroyContainer() {
container.destroy();
container = null;
containerInitialized = false;
}
public void include() {
if (autoIncluding) {
if (container.hasComponentDef(ConfigFileIncluder.class)) {
final ConfigFileIncluder includer = (ConfigFileIncluder) container
.getComponent(ConfigFileIncluder.class);
includer.include(this);
}
}
}
public void include(final String path) {
final String convertedPath = ResourceUtil.convertPath(path, testClass);
S2ContainerFactory.include(container, convertedPath);
}
public void register(final Class<?> componentClass,
final String componentName) {
final ComponentDef cd = handler.createComponentDef(componentClass,
InstanceDefFactory.SINGLETON);
cd.setComponentName(componentName);
handler.appendDI(cd);
handler.appendAspect(cd);
handler.appendInterType(cd);
handler.appendInitMethod(cd);
handler.appendDestroyMethod(cd);
container.register(cd);
}
public void register(final Class<?> componentClass) {
if (namingConvention == null) {
register(componentClass, null);
} else {
register(componentClass, namingConvention
.fromClassNameToComponentName(componentClass.getName()));
}
}
public void register(final ComponentDef componentDef) {
container.register(componentDef);
}
public void register(final Object component, String componentName) {
container.register(component, componentName);
}
public void register(final Object component) {
container.register(component);
}
public String getTestClassPackagePath() {
return testClass.getName().replace('.', '/')
.replaceFirst("/[^/]+$", "");
}
public String getTestClassShortName() {
return ClassUtil.getShortClassName(testClass);
}
public String getTestMethodName() {
return testMethod.getName();
}
public void prepareTestData() {
if (autoPreparing) {
if (hasComponentDef(TestDataPreparer.class)) {
final TestDataPreparer preparer = getComponent(TestDataPreparer.class);
preparer.prepare(this);
}
}
}
public DataSet getExpected() {
if (hasComponentDef(ExpectedDataReader.class)) {
final ExpectedDataReader reader = getComponent(ExpectedDataReader.class);
final DataSet expected = reader.read(this);
if (expected != null) {
return expected;
}
}
return null;
}
public MockInterceptor getMockInterceptor(final int index) {
return mockInterceptors.get(index);
}
public S2Container getContainer() {
return container;
}
public <T> T getComponent(final Class<? extends T> componentKey) {
return componentKey.cast(container.getComponent(componentKey));
}
public Object getComponent(final Object componentKey) {
return container.getComponent(componentKey);
}
public boolean hasComponentDef(final Object componentKey) {
return container.hasComponentDef(componentKey);
}
public ComponentDef getComponentDef(final int index) {
return container.getComponentDef(index);
}
public ComponentDef getComponentDef(final Object componentKey) {
return container.getComponentDef(componentKey);
}
public void addMockInterceptor(final MockInterceptor mockInterceptor) {
mockInterceptors.add(mockInterceptor);
}
public int getMockInterceptorSize() {
return mockInterceptors.size();
}
public void addAspecDef(final Object componentKey, final AspectDef aspectDef) {
if (containerInitialized) {
throw new IllegalStateException();
}
container.getComponentDef(componentKey).addAspectDef(0, aspectDef);
}
public boolean isEjb3Enabled() {
return ejb3Enabled;
}
public boolean isJtaEnabled() {
return jtaEnabled;
}
public void registerColumnTypes() {
if (!trimString) {
registerColumnType(String.class, ColumnTypes.NOT_TRIM_STRING);
registerColumnType(Types.CHAR, ColumnTypes.NOT_TRIM_STRING);
registerColumnType(Types.LONGVARCHAR, ColumnTypes.NOT_TRIM_STRING);
registerColumnType(Types.VARCHAR, ColumnTypes.NOT_TRIM_STRING);
}
}
/**
* カラムの型を登録します。
*
* @param clazz
* クラス
* @param columnType
* カラムの型
*/
protected void registerColumnType(Class<?> clazz, ColumnType columnType) {
ColumnType original = ColumnTypes.registerColumnType(clazz, columnType);
deregisteredColumnTypesByClass.put(clazz, original);
}
/**
* カラムの型を登録します。
*
* @param sqlType
* SQL型
* @param columnType
* カラムの型
*/
protected void registerColumnType(int sqlType, ColumnType columnType) {
ColumnType original = ColumnTypes.registerColumnType(sqlType,
columnType);
deregisteredColumnTypesBySqlType.put(sqlType, original);
}
public void revertColumnTypes() {
for (Map.Entry<Class<?>, ColumnType> e : deregisteredColumnTypesByClass
.entrySet()) {
ColumnTypes.registerColumnType(e.getKey(), e.getValue());
}
for (Map.Entry<Integer, ColumnType> e : deregisteredColumnTypesBySqlType
.entrySet()) {
ColumnTypes.registerColumnType(e.getKey(), e.getValue());
}
}
}