/* * Copyright 2007-2012 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 net.paoding.rose.web.portal.impl; import java.util.concurrent.ExecutorService; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import net.paoding.rose.web.Invocation; import net.paoding.rose.web.impl.thread.InvocationBean; import net.paoding.rose.web.portal.Pipe; import net.paoding.rose.web.portal.Portal; import net.paoding.rose.web.portal.PortalFactory; import net.paoding.rose.web.portal.WindowListener; import net.paoding.rose.web.portal.PortalSetting; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.util.Assert; /** * {@link PortalFactory} 的实现。 * <p> * * 创建 {@link PortalFactoryImpl}实例后,应该通过 * {@link #setExecutorService(ExecutorService)} 或 * {@link #setExecutorServiceBySpring(ThreadPoolTaskExecutor)} * 设置执行器,用于执行Portal下的每个“窗口请求”。 * <p> * * 可选设置 {@link WindowListener} 来获知portal的创建以及窗口的创建、执行等状态信息。 * * @see PortalImpl * * @author 王志亮 [qieqie.wang@gmail.com] * */ public class PortalFactoryImpl implements PortalFactory, InitializingBean { protected Log logger = LogFactory.getLog(getClass()); private ExecutorService executorService; private WindowListener windowListener; public void setExecutorService(ExecutorService executor) { if (logger.isInfoEnabled()) { logger.info("using executorService: " + executor); } this.executorService = executor; } public ExecutorService getExecutorService() { return executorService; } public void setWindowListener(WindowListener portalListener) { this.windowListener = portalListener; } public WindowListener getWindowListener() { return windowListener; } @Override public void afterPropertiesSet() throws Exception { Assert.notNull(windowListener); Assert.notNull(executorService); } @Override public Portal createPortal(Invocation inv) { PortalImpl portal = (PortalImpl) inv .getAttribute("$$paoding-rose-portal.portal"); if (portal != null) { return portal; } portal = new PortalImpl(inv, executorService, windowListener); // long timeout = 0; PortalSetting portalSetting = inv.getMethod().getAnnotation(PortalSetting.class); if (portalSetting != null) { if (portalSetting.timeout() >= 0) { long annotationTimeout = portalSetting.timeUnit().toMillis(portalSetting.timeout()); // < 0的情况,是PortalSetting的默认设置,即如果PortalSetting没有设置有效的timeout,则使用defaultTimeout策略 // == 0的情况表示并且要求表示不需要设置超时时间,并且也不使用defaultTimeout策略 if (annotationTimeout >= 0) { timeout = annotationTimeout; } } } if (timeout > 0) { portal.setTimeout(timeout); } // 换request对象 HttpServletRequest innerRequest = inv.getRequest(); HttpServletRequestWrapper requestWrapper = null; while (innerRequest instanceof HttpServletRequestWrapper) { requestWrapper = (HttpServletRequestWrapper) innerRequest; innerRequest = (HttpServletRequest) ((HttpServletRequestWrapper) innerRequest) .getRequest(); } final PortalRequest portalRequest = new PortalRequest(portal, innerRequest); if (requestWrapper == null) { inv.setRequest(portalRequest); } else { requestWrapper.setRequest(portalRequest); } // 换response对象 HttpServletResponse innerResponse = inv.getResponse(); HttpServletResponseWrapper responseWrapper = null; while (innerResponse instanceof HttpServletResponseWrapper) { responseWrapper = (HttpServletResponseWrapper) innerResponse; innerResponse = (HttpServletResponse) ((HttpServletResponseWrapper) innerResponse) .getResponse(); } final PortalResponse portalResponse = new PortalResponse(portal, innerResponse); if (responseWrapper == null) { ((InvocationBean) inv).setResponse(portalResponse); } else { responseWrapper.setResponse(portalResponse); } // inv.setAttribute("$$paoding-rose-portal.portal", portal); return portal; } @Override public Pipe createPipe(Invocation inv, boolean create) { PipeImpl pipe = (PipeImpl) inv.getHeadInvocation().getAttribute( "$$paoding-rose-portal.pipe"); if (pipe == null) { if (create) { pipe = new PipeImpl(inv, executorService, windowListener); inv.getHeadInvocation().setAttribute("$$paoding-rose-portal.pipe", pipe); } } else if (pipe.getInvocation() != inv) { // 因为PortalWaitInterceptor的waitForPipeWindows无法良好处理 // 尚不支持portal/pipe转发出去的地址还使用pipe // 否则,waitForPipeWindows的getWindows方法可能会有java.util.ConcurrentModificationException异常 throw new UnsupportedOperationException(// "Pipe is only allowed in one place for a request, " + "don't forward to path that using pipe. "); } return pipe; } }