Package com.alibaba.citrus.service.requestcontext.impl

Source Code of com.alibaba.citrus.service.requestcontext.impl.RequestContextCommitTests$MyRequestContextFactory

/*
* Copyright (c) 2002-2012 Alibaba Group Holding Limited.
* All rights reserved.
*
* 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 com.alibaba.citrus.service.requestcontext.impl;

import static com.alibaba.citrus.service.requestcontext.util.RequestContextUtil.*;
import static com.alibaba.citrus.test.TestUtil.*;
import static com.alibaba.citrus.util.CollectionUtil.*;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.citrus.service.requestcontext.RequestContext;
import com.alibaba.citrus.service.requestcontext.RequestContextException;
import com.alibaba.citrus.service.requestcontext.RequestContextFactory;
import com.alibaba.citrus.service.requestcontext.TwoPhaseCommitRequestContext;
import com.alibaba.citrus.service.requestcontext.support.AbstractRequestContextFactory;
import com.alibaba.citrus.test.TestEnvStatic;
import com.alibaba.citrus.util.internal.InterfaceImplementorBuilder;
import com.alibaba.citrus.util.internal.Servlet3Util.Servlet3OutputStream;
import org.junit.Before;
import org.junit.Test;

public class RequestContextCommitTests {
    private RequestContextChainingServiceImpl service;
    private ServletContext                    servletContext;
    private HttpServletRequest                request;
    private HttpServletResponse               response;
    private RequestContext                    requestContext1;
    private TwoPhaseCommitRequestContext      requestContext2;
    private Object                            overrider1;
    private Object                            overrider2;
    private RequestContext                    requestContext;

    static {
        TestEnvStatic.init();
    }

    @Before
    public void init() throws Exception {
        // servletContext/request/response
        servletContext = createNiceMock(ServletContext.class);
        request = createNiceMock(HttpServletRequest.class);
        response = createNiceMock(HttpServletResponse.class);

        expect(response.getWriter()).andReturn(new PrintWriter(System.out)).anyTimes();
        expect(response.getOutputStream()).andReturn(new Servlet3OutputStream(null) {
            @Override
            public void write(int b) throws IOException {
            }
        }).anyTimes();

        replay(servletContext, request, response);

        // requestContexts
        requestContext1 = createMock(RequestContext.class);
        requestContext2 = createMock(TwoPhaseCommitRequestContext.class);

        List<RequestContextFactory<?>> factories = createArrayList(new RequestContextFactory<?>[] {
                new MyRequestContextFactory(requestContext1, overrider1),
                new MyRequestContextFactory(requestContext2, overrider2),
        });

        service = new RequestContextChainingServiceImpl();
        service.setFactories(factories);
        service.afterPropertiesSet();
    }

    @Test
    public void commit() {
        // 接下来的提交,会触发RequestContext.commit,
        // 以及TwoPhaseCommitRequestContext.commitHeaders()。
        requestContext1.commit();
        expectLastCall().once();

        requestContext2.commitHeaders();
        expectLastCall().once();

        requestContext2.commit();
        expectLastCall().once();

        requestContext = service.getRequestContext(servletContext, request, response);

        service.commitRequestContext(requestContext);
        service.commitRequestContext(requestContext); // 不会重复提交

        verify(requestContext1, requestContext2);
    }

    @Test
    public void commitHeaders() {
        // 接下来的提交,不会触发RequestContext.commit,
        // 但会触发TwoPhaseCommitRequestContext.commitHeaders()。
        requestContext2.commitHeaders();
        expectLastCall().once();

        requestContext = service.getRequestContext(servletContext, request, response);

        service.commitHeaders(requestContext);
        service.commitHeaders(requestContext); // 不会重复提交

        verify(requestContext1, requestContext2);
    }

    @Test
    public void commitHeaders_thenCommitAll() {
        // 接下来的提交,会触发RequestContext.commit,
        // 以及TwoPhaseCommitRequestContext.commitHeaders()。
        requestContext1.commit();
        expectLastCall().once();

        requestContext2.commitHeaders();
        expectLastCall().once();

        requestContext2.commit();
        expectLastCall().once();

        requestContext = service.getRequestContext(servletContext, request, response);

        service.commitHeaders(requestContext);
        service.commitRequestContext(requestContext);

        verify(requestContext1, requestContext2);
    }

    @Test
    public void autoCommitHeaders_writer() throws Exception {
        // 接下来对writer或stream的操作,将会自动触发TwoPhaseCommitRequestContext.commitHeaders()。
        requestContext2.commitHeaders();
        expectLastCall().once();

        requestContext = service.getRequestContext(servletContext, request, response);
        PrintWriter out = requestContext.getResponse().getWriter();

        out.println("hi");
        out.flush();

        verify(requestContext1, requestContext2);
    }

    @Test
    public void autoCommitHeaders_stream() throws Exception {
        // 接下来对writer或stream的操作,将会自动触发TwoPhaseCommitRequestContext.commitHeaders()。
        requestContext2.commitHeaders();
        expectLastCall().once();

        requestContext = service.getRequestContext(servletContext, request, response);
        ServletOutputStream out = requestContext.getResponse().getOutputStream();

        out.println("hi");
        out.flush();

        verify(requestContext1, requestContext2);
    }

    private int count;

    /** 测试当在commit时间接触发了commitHeaders时,commitHeaders不会被执行。 */
    @Test
    public void preventCommitHeaders_whenDoCommitting() throws Exception {
        // 用来测试执行顺序。
        count = 0;

        overrider1 = new Object() {
            public void commit() {
                try {
                    // 在commit时,触发commitHeaders
                    requestContext1.getResponse().getWriter().flush();
                } catch (IOException e) {
                    throw new RequestContextException(e);
                }

                assertEquals(0, count++);
            }
        };
        overrider2 = new Object() {
            private RequestContext thisObject;

            public void setThisProxy(Object o) {
                thisObject = (RequestContext) o;
            }

            public void commitHeaders() {
                assertEquals(1, count++);

                CommitMonitor monitor = findRequestContext(thisObject, SimpleRequestContext.class);
                assertFalse(getFieldValue(monitor, "headersCommitted", Boolean.class));
                assertTrue(getFieldValue(monitor, "committed", Boolean.class));

                assertTrue(monitor.isCommitted());
                assertTrue(monitor.isHeadersCommitted());
            }

            public void commit() {
                assertEquals(2, count++);
            }
        };

        List<RequestContextFactory<?>> factories = createArrayList(new RequestContextFactory<?>[] {
                new MyRequestContextFactory(requestContext2, overrider2),
                new MyRequestContextFactory(requestContext1, overrider1), // 先提交requestContext1,再提交requestContext2
        });

        service = new RequestContextChainingServiceImpl();
        service.setFactories(factories);
        service.afterPropertiesSet();

        requestContext = service.getRequestContext(servletContext, request, response);
        service.commitRequestContext(requestContext);

        verify(requestContext1, requestContext2);
    }

    private CountDownLatch latch;

    /** 测试多线程不会同时执行commit和commitHeaders。 */
    @Test
    public void synchronization() throws Exception {
        // 用来测试执行顺序。
        count = 0;

        latch = new CountDownLatch(1);

        overrider1 = new Object() {
            public void commit() throws Exception {
                latch.await();
                assertEquals(2, count++);
            }
        };
        overrider2 = new Object() {
            public void commitHeaders() {
                assertEquals(3, count++);
            }

            public void commit() {
                assertEquals(4, count++);
            }
        };

        List<RequestContextFactory<?>> factories = createArrayList(new RequestContextFactory<?>[] {
                new MyRequestContextFactory(requestContext2, overrider2),
                new MyRequestContextFactory(requestContext1, overrider1), // 先提交requestContext1,再提交requestContext2
        });

        service = new RequestContextChainingServiceImpl();
        service.setFactories(factories);
        service.afterPropertiesSet();

        requestContext = service.getRequestContext(servletContext, request, response);

        Thread t1 = new Thread(new Runnable() {
            public void run() {
                assertEquals(0, count++);
                service.commitRequestContext(requestContext);
                assertEquals(0, count++);
            }
        });
        Thread t2 = new Thread(new Runnable() {
            public void run() {
                assertEquals(1, count++);
                service.commitHeaders(requestContext);
                assertEquals(5, count++);
            }
        });

        t1.start();

        // 确保thread1进入等待latch状态
        TimeUnit.MILLISECONDS.sleep(10);
        assertEquals(1, count);

        t2.start();

        // 确保thread2进入等待monitor的状态
        TimeUnit.MILLISECONDS.sleep(10);
        assertEquals(2, count);

        latch.countDown();

        t1.join();
        t2.join();
    }

    private class MyRequestContextFactory extends AbstractRequestContextFactory<RequestContext> {
        private final RequestContext requestContext;
        private final Object         overrider;

        private MyRequestContextFactory(RequestContext requestContext, Object overrider) {
            this.requestContext = requestContext;
            this.overrider = overrider;
        }

        @Override
        public RequestContext getRequestContextWrapper(RequestContext wrappedContext) {
            expect(requestContext.getServletContext()).andReturn(wrappedContext.getServletContext()).anyTimes();
            expect(requestContext.getRequest()).andReturn(wrappedContext.getRequest()).anyTimes();
            expect(requestContext.getResponse()).andReturn(wrappedContext.getResponse()).anyTimes();
            expect(requestContext.getWrappedRequestContext()).andReturn(wrappedContext).anyTimes();
            requestContext.prepare();
            expectLastCall().once();
            replay(requestContext);

            if (overrider != null) {
                return (RequestContext) new InterfaceImplementorBuilder()
                        .addInterface(requestContext.getClass().getInterfaces())
                        .toObject(overrider, requestContext);
            } else {
                return requestContext;
            }
        }

        @Override
        public String[] getFeatures() {
            return new String[0]//To change body of implemented methods use File | Settings | File Templates.
        }

        @Override
        public FeatureOrder[] featureOrders() {
            return new FeatureOrder[0]//To change body of implemented methods use File | Settings | File Templates.
        }
    }
}
TOP

Related Classes of com.alibaba.citrus.service.requestcontext.impl.RequestContextCommitTests$MyRequestContextFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.