All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dbflute.utflute.seasar.SeasarTestCase Maven / Gradle / Ivy

There is a newer version: 0.9.8
Show newest version
/*
 * Copyright 2014-2017 the original author or authors.
 *
 * 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.dbflute.utflute.seasar;

import java.lang.annotation.Annotation;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.transaction.NotSupportedException;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;

import org.dbflute.utflute.core.InjectionTestCase;
import org.dbflute.utflute.core.binding.BindingAnnotationRule;
import org.dbflute.utflute.core.binding.ComponentBinder;
import org.dbflute.utflute.core.binding.NonBindingDeterminer;
import org.dbflute.utflute.core.transaction.TransactionFailureException;
import org.dbflute.utflute.core.transaction.TransactionResource;
import org.dbflute.utflute.mocklet.MockletHttpServletRequest;
import org.dbflute.utflute.mocklet.MockletHttpServletRequestImpl;
import org.dbflute.utflute.mocklet.MockletHttpServletResponse;
import org.dbflute.utflute.mocklet.MockletHttpServletResponseImpl;
import org.dbflute.utflute.mocklet.MockletHttpSession;
import org.dbflute.utflute.mocklet.MockletServletConfig;
import org.dbflute.utflute.mocklet.MockletServletConfigImpl;
import org.dbflute.utflute.mocklet.MockletServletContext;
import org.dbflute.utflute.mocklet.MockletServletContextImpl;
import org.dbflute.util.Srl;
import org.seasar.framework.container.ComponentNotFoundRuntimeException;
import org.seasar.framework.container.ExternalContext;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.SingletonS2Container;
import org.seasar.framework.container.TooManyRegistrationRuntimeException;
import org.seasar.framework.container.annotation.tiger.Binding;
import org.seasar.framework.container.annotation.tiger.BindingType;
import org.seasar.framework.container.factory.SingletonS2ContainerFactory;
import org.seasar.framework.container.servlet.S2ContainerServlet;
import org.seasar.framework.convention.NamingConvention;
import org.seasar.framework.env.Env;

/**
 * @author jflute
 * @since 0.1.0 (2011/07/24 Sunday)
 */
public abstract class SeasarTestCase extends InjectionTestCase {

    // ===================================================================================
    //                                                                           Attribute
    //                                                                           =========
    // -----------------------------------------------------
    //                                         Static Cached
    //                                         -------------
    /** The cached configuration file of DI container. (NullAllowed: null means beginning or ending) */
    private static String _xcachedConfigFile;

    /** The cached determination of suppressing web mock. (NullAllowed: null means beginning or ending) */
    private static Boolean _xcachedSuppressWebMock;

    /** The cached configuration of servlet. (NullAllowed: when no web mock or beginning or ending) */
    private static MockletServletConfig _xcachedServletConfig;

    // -----------------------------------------------------
    //                                              Web Mock
    //                                              --------
    /** The mock request of the test case execution. (NullAllowed: when no web mock or beginning or ending) */
    private MockletHttpServletRequest _xmockRequest;

    /** The mock response of the test case execution. (NullAllowed: when no web mock or beginning or ending) */
    private MockletHttpServletResponse _xmockResponse;

    // ===================================================================================
    //                                                                            Settings
    //                                                                            ========
    // -----------------------------------------------------
    //                                      Before Container
    //                                      ----------------
    @Override
    protected void xsetupBeforeContainer() {
        super.xsetupBeforeContainer();
        xprepareUnitTestEnv();
    }

    // -----------------------------------------------------
    //                                     Prepare Container
    //                                     -----------------
    @Override
    protected void xprepareTestCaseContainer() {
        final String configFile = xdoPrepareTestCaseContainer();
        xsaveCachedInstance(configFile);
        xdoPrepareWebMockContext();
    }

    protected String xdoPrepareTestCaseContainer() {
        if (isUseOneTimeContainer()) {
            xdestroyContainer();
        }
        final String configFile = prepareConfigFile();
        if (xisInitializedContainer()) {
            if (xcanRecycleContainer(configFile)) {
                log("...Recycling seasar: " + configFile);
                xrecycleContainerInstance(configFile);
                return configFile; // no need to initialize
            } else { // changed
                xdestroyContainer(); // to re-initialize
            }
        }
        xinitializeContainer(configFile);
        return configFile;
    }

    protected boolean xcanRecycleContainer(String configFile) {
        return xconfigCanAcceptContainerRecycle(configFile) && xwebMockCanAcceptContainerRecycle();
    }

    protected boolean xconfigCanAcceptContainerRecycle(String configFile) {
        return configFile.equals(_xcachedConfigFile); // no change
    }

    protected void xrecycleContainerInstance(String configFile) {
        // managed as singleton so caching is unneeded here
    }

    protected boolean xwebMockCanAcceptContainerRecycle() {
        // no mark or no change
        return _xcachedSuppressWebMock == null || _xcachedSuppressWebMock.equals(isSuppressWebMock());
    }

    protected void xsaveCachedInstance(String configFile) {
        _xcachedConfigFile = configFile;
        _xcachedSuppressWebMock = isSuppressWebMock();
    }

    /**
     * Does it suppress web mock? e.g. HttpServletRequest, HttpSession
     * @return The determination, true or false.
     */
    protected boolean isSuppressWebMock() {
        return false;
    }

    protected void xdoPrepareWebMockContext() {
        if (_xcachedServletConfig != null) {
            // the servletConfig has been already created when container initialization
            xregisterWebMockContext(_xcachedServletConfig);
        }
    }

    /**
     * {@inheritDoc}
     */
    protected boolean isUseOneTimeContainer() {
        return false;
    }

    /**
     * Prepare configuration file as root for Seasar.
     * @return The pure file name of root dicon. (NotNull)
     */
    protected String prepareConfigFile() { // customize point
        return "app.dicon"; // as default
    }

    @Override
    protected void xclearCachedContainer() {
        _xcachedConfigFile = null;
    }

    @Override
    public void tearDown() throws Exception {
        _xmockRequest = null;
        _xmockResponse = null;
        super.tearDown();
    }

    // ===================================================================================
    //                                                                         Transaction
    //                                                                         ===========
    /**
     * {@inheritDoc}
     */
    @Override
    protected TransactionResource beginNewTransaction() { // user method
        final Class managerType = TransactionManager.class;
        if (!hasComponent(managerType)) {
            return null;
        }
        final TransactionManager manager = getComponent(managerType);
        final Transaction suspendedTx;
        try {
            if (manager.getStatus() != Status.STATUS_NO_TRANSACTION) {
                suspendedTx = manager.suspend(); // because Seasar's DBCP doesn't support nested transaction
            } else {
                suspendedTx = null;
            }
        } catch (SystemException e) {
            throw new TransactionFailureException("Failed to suspend current", e);
        }
        TransactionResource resource = null;
        try {
            manager.begin();
            resource = new TransactionResource() {
                public void commit() {
                    try {
                        manager.commit();
                    } catch (Exception e) {
                        throw new TransactionFailureException("Failed to commit the transaction.", e);
                    } finally {
                        xresumeSuspendedTxQuietly(manager, suspendedTx);
                    }
                }

                public void rollback() {
                    try {
                        manager.rollback();
                    } catch (Exception e) {
                        throw new TransactionFailureException("Failed to roll-back the transaction.", e);
                    } finally {
                        xresumeSuspendedTxQuietly(manager, suspendedTx);
                    }
                }
            }; // for thread-fire's transaction or manual transaction
        } catch (NotSupportedException e) {
            throw new TransactionFailureException("Failed to begin new transaction.", e);
        } catch (SystemException e) {
            throw new TransactionFailureException("Failed to begin new transaction.", e);
        }
        return resource;
    }

    protected void xresumeSuspendedTxQuietly(TransactionManager manager, Transaction suspendedTx) {
        try {
            if (suspendedTx != null) {
                manager.resume(suspendedTx);
            }
        } catch (Exception e) {
            log(e.getMessage());
        }
    }

    // ===================================================================================
    //                                                                   Component Binding
    //                                                                   =================
    @Override
    protected ComponentBinder createOuterComponentBinder(Object bean) {
        final ComponentBinder binder = super.createOuterComponentBinder(bean);
        binder.byTypeInterfaceOnly();
        return binder;
    }

    @Override
    protected Map, BindingAnnotationRule> xprovideBindingAnnotationRuleMap() {
        final Map, BindingAnnotationRule> ruleMap = newHashMap();
        ruleMap.put(Resource.class, new BindingAnnotationRule());
        ruleMap.put(Binding.class, new BindingAnnotationRule().determineNonBinding(new NonBindingDeterminer() {
            public boolean isNonBinding(Annotation bindingAnno) {
                return BindingType.NONE.equals(((Binding) bindingAnno).bindingType());
            }
        }));
        return ruleMap;
    }

    @Override
    protected String xfilterByBindingNamingRule(String propertyName, Class propertyType) {
        if (propertyType.getSimpleName().contains("_")) { // e.g. (org.dbflute.maihama.) Foo_BarLogic
            return null; // simple name that contains '_' is unsupported
        }
        // e.g. [root].logic.foo.bar.QuxLogic
        final NamingConvention convention = getComponent(NamingConvention.class);
        final String componentName;
        try {
            // e.g. foo_bar_quxLogic -> foo_bar_quxLogic ends with [property name] -> returns foo_bar_quxLogic
            componentName = convention.fromClassNameToComponentName(propertyType.getName());
        } catch (RuntimeException ignored) { // just in case e.g. org.dbflute.maihama.foo
            return null;
        }
        if (xcanUseComponentNameByBindingNamingRule(componentName, propertyName)) {
            return componentName;
        }
        // not smart deploy component or name wrong e.g. (foo_bar_) quxLogic does not equal quxService
        return null;
    }

    protected boolean xcanUseComponentNameByBindingNamingRule(String componentName, String propertyName) {
        if (componentName.contains("_")) { // means smart deploy component
            if (componentName.endsWith(propertyName)) {
                final String front = Srl.substringLastFront(componentName, propertyName); // e.g. foo_bar_
                if (front.equals("") || front.endsWith("_")) {
                    // e.g.
                    //  foo_bar_quxLogic ends with foo_bar_quxLogic
                    //  foo_bar_quxLogic ends with quxLogic
                    //  foo_bar_quxLogic ends with bar_quxLogic
                    return true;
                }
                // e.g. foo_bar_quxLogic ends with ar_quxLogic
            }
        }
        return false;
    }

    // ===================================================================================
    //                                                                     Seasar Handling
    //                                                                     ===============
    protected void xprepareUnitTestEnv() {
        Env.setFilePath("env_ut.txt");
        Env.setValueIfAbsent("ut");
    }

    // -----------------------------------------------------
    //                                            Initialize
    //                                            ----------
    protected boolean xisInitializedContainer() {
        return SingletonS2ContainerFactory.hasContainer();
    }

    protected void xinitializeContainer(String configFile) {
        if (isSuppressWebMock()) { // library
            log("...Initializing seasar as library: " + configFile);
            xdoInitializeContainerAsLibrary(configFile);
        } else { // web (Seasar contains web components as default)
            log("...Initializing seasar as web: " + configFile);
            xdoInitializeContainerAsWeb(configFile);
        }
    }

    protected void xdoInitializeContainerAsLibrary(String configFile) {
        SingletonS2ContainerFactory.setConfigPath(configFile);
        SingletonS2ContainerFactory.init();
    }

    protected void xdoInitializeContainerAsWeb(String configFile) {
        final ServletConfig servletConfig = xprepareMockServletConfig(configFile);
        final S2ContainerServlet containerServlet = xcreateS2ContainerServlet();
        try {
            containerServlet.init(servletConfig);
        } catch (ServletException e) {
            String msg = "Failed to initialize servlet config to servlet: " + servletConfig;
            throw new IllegalStateException(msg, e.getRootCause());
        }
    }

    // -----------------------------------------------------
    //                                              Web Mock
    //                                              --------
    protected ServletConfig xprepareMockServletConfig(String configFile) {
        _xcachedServletConfig = createMockletServletConfig(); // cache for request mocks
        _xcachedServletConfig.setServletContext(createMockletServletContext());
        _xcachedServletConfig.setInitParameter(S2ContainerServlet.CONFIG_PATH_KEY, configFile);
        return _xcachedServletConfig;
    }

    protected S2ContainerServlet xcreateS2ContainerServlet() {
        return new S2ContainerServlet();
    }

    protected void xregisterWebMockContext(MockletServletConfig servletConfig) { // like S2ContainerFilter
        final S2Container container = SingletonS2ContainerFactory.getContainer();
        final ExternalContext externalContext = container.getExternalContext();
        final MockletHttpServletRequest request = createMockletHttpServletRequest(servletConfig.getServletContext());
        final MockletHttpServletResponse response = createMockletHttpServletResponse(request);
        externalContext.setRequest(request);
        externalContext.setResponse(response);
        xkeepMockRequestInstance(request, response); // for web mock handling methods
    }

    protected MockletServletConfig createMockletServletConfig() {
        return new MockletServletConfigImpl();
    }

    protected MockletServletContext createMockletServletContext() {
        return new MockletServletContextImpl("utservlet");
    }

    protected MockletHttpServletRequest createMockletHttpServletRequest(ServletContext servletContext) {
        return new MockletHttpServletRequestImpl(servletContext, prepareServletPath());
    }

    protected MockletHttpServletResponse createMockletHttpServletResponse(HttpServletRequest request) {
        return new MockletHttpServletResponseImpl(request);
    }

    protected String prepareServletPath() { // customize point
        return "/utflute";
    }

    protected void xkeepMockRequestInstance(MockletHttpServletRequest request, MockletHttpServletResponse response) {
        _xmockRequest = request;
        _xmockResponse = response;
    }

    // -----------------------------------------------------
    //                                               Destroy
    //                                               -------
    protected void xdestroyContainer() {
        SingletonS2ContainerFactory.destroy();
        SingletonS2ContainerFactory.setExternalContext(null); // destroy() does not contain this
        _xcachedServletConfig = null;
    }

    // -----------------------------------------------------
    //                                             Component
    //                                             ---------
    /**
     * {@inheritDoc}
     */
    protected  COMPONENT getComponent(Class type) { // user method
        return SingletonS2Container.getComponent(type);
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    protected  COMPONENT getComponent(String name) { // user method
        return (COMPONENT) SingletonS2Container.getComponent(name);
    }

    /**
     * {@inheritDoc}
     */
    protected boolean hasComponent(Class type) { // user method
        try {
            SingletonS2Container.getComponent(type);
            return true;
        } catch (ComponentNotFoundRuntimeException e) {
            return false;
        } catch (TooManyRegistrationRuntimeException e) {
            return false;
        }
    }

    /**
     * {@inheritDoc}
     */
    protected boolean hasComponent(String name) { // user method
        try {
            SingletonS2Container.getComponent(name);
            return true;
        } catch (ComponentNotFoundRuntimeException e) {
            return false;
        }
    }

    // ===================================================================================
    //                                                                   Web Mock Handling
    //                                                                   =================
    // -----------------------------------------------------
    //                                               Request
    //                                               -------
    protected MockletHttpServletRequest getMockRequest() {
        return (MockletHttpServletRequest) _xmockRequest;
    }

    protected void addMockRequestHeader(String name, String value) {
        final MockletHttpServletRequest request = getMockRequest();
        if (request != null) {
            request.addHeader(name, value);
        }
    }

    @SuppressWarnings("unchecked")
    protected  ATTRIBUTE getMockRequestParameter(String name) {
        final MockletHttpServletRequest request = getMockRequest();
        return request != null ? (ATTRIBUTE) request.getParameter(name) : null;
    }

    protected void addMockRequestParameter(String name, String value) {
        final MockletHttpServletRequest request = getMockRequest();
        if (request != null) {
            request.addParameter(name, value);
        }
    }

    @SuppressWarnings("unchecked")
    protected  ATTRIBUTE getMockRequestAttribute(String name) {
        final MockletHttpServletRequest request = getMockRequest();
        return request != null ? (ATTRIBUTE) request.getAttribute(name) : null;
    }

    protected void setMockRequestAttribute(String name, Object value) {
        final MockletHttpServletRequest request = getMockRequest();
        if (request != null) {
            request.setAttribute(name, value);
        }
    }

    // -----------------------------------------------------
    //                                              Response
    //                                              --------
    protected MockletHttpServletResponse getMockResponse() {
        return (MockletHttpServletResponse) _xmockResponse;
    }

    protected Cookie[] getMockResponseCookies() {
        final MockletHttpServletResponse response = getMockResponse();
        return response != null ? response.getCookies() : null;
    }

    protected int getMockResponseStatus() {
        final MockletHttpServletResponse response = getMockResponse();
        return response != null ? response.getStatus() : 0;
    }

    protected String getMockResponseString() {
        final MockletHttpServletResponse response = getMockResponse();
        return response != null ? response.getResponseString() : null;
    }

    // -----------------------------------------------------
    //                                               Session
    //                                               -------
    /**
     * @return The instance of mock session. (NotNull: if no session, new-created)
     */
    protected MockletHttpSession getMockSession() {
        return _xmockRequest != null ? (MockletHttpSession) _xmockRequest.getSession(true) : null;
    }

    protected void invalidateMockSession() {
        final MockletHttpSession session = getMockSession();
        if (session != null) {
            session.invalidate();
        }
    }

    @SuppressWarnings("unchecked")
    protected  ATTRIBUTE getMockSessionAttribute(String name) {
        final MockletHttpSession session = getMockSession();
        return session != null ? (ATTRIBUTE) session.getAttribute(name) : null;
    }

    protected void setMockSessionAttribute(String name, Object value) {
        final MockletHttpSession session = getMockSession();
        if (session != null) {
            session.setAttribute(name, value);
        }
    }

    // ===================================================================================
    //                                                                            Accessor
    //                                                                            ========
    protected static String xgetCachedConfigFile() {
        return _xcachedConfigFile;
    }

    protected static void xsetCachedConfigFile(String xcachedConfigFile) {
        _xcachedConfigFile = xcachedConfigFile;
    }

    protected static Boolean xgetCachedSuppressWebMock() {
        return _xcachedSuppressWebMock;
    }

    protected static void xsetCachedSuppressWebMock(Boolean xcachedSuppressWebMock) {
        _xcachedSuppressWebMock = xcachedSuppressWebMock;
    }

    protected static MockletServletConfig xgetCachedServletConfig() {
        return _xcachedServletConfig;
    }

    protected static void xsetCachedServletConfig(MockletServletConfig xcachedServletConfig) {
        _xcachedServletConfig = xcachedServletConfig;
    }

    protected MockletHttpServletRequest xgetMockRequest() {
        return _xmockRequest;
    }

    protected void xsetMockRequest(MockletHttpServletRequest xmockRequest) {
        _xmockRequest = xmockRequest;
    }

    protected MockletHttpServletResponse xgetMockResponse() {
        return _xmockResponse;
    }

    protected void xsetMockResponse(MockletHttpServletResponse xmockResponse) {
        _xmockResponse = xmockResponse;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy