001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.model.Portlet;
020    import com.liferay.portal.kernel.model.PortletApp;
021    import com.liferay.portal.kernel.portlet.LiferayPortletContext;
022    import com.liferay.portal.kernel.portlet.LiferayPortletRequestDispatcher;
023    import com.liferay.portal.kernel.portlet.LiferayPortletURL;
024    import com.liferay.portal.kernel.servlet.URLEncoder;
025    import com.liferay.portal.kernel.theme.ThemeDisplay;
026    import com.liferay.portal.kernel.util.CharPool;
027    import com.liferay.portal.kernel.util.JavaConstants;
028    import com.liferay.portal.kernel.util.PortalUtil;
029    import com.liferay.portal.kernel.util.StringPool;
030    import com.liferay.portal.kernel.util.StringUtil;
031    import com.liferay.portal.kernel.util.WebKeys;
032    import com.liferay.portal.servlet.DynamicServletRequestUtil;
033    import com.liferay.portal.struts.StrutsURLEncoder;
034    
035    import java.io.IOException;
036    
037    import java.util.HashMap;
038    import java.util.Map;
039    import java.util.Set;
040    
041    import javax.portlet.PortletContext;
042    import javax.portlet.PortletException;
043    import javax.portlet.PortletRequest;
044    import javax.portlet.PortletResponse;
045    import javax.portlet.RenderRequest;
046    import javax.portlet.RenderResponse;
047    
048    import javax.servlet.RequestDispatcher;
049    import javax.servlet.ServletException;
050    import javax.servlet.http.HttpServletRequest;
051    import javax.servlet.http.HttpServletResponse;
052    
053    import org.apache.struts.Globals;
054    
055    /**
056     * @author Brian Wing Shun Chan
057     * @author Brian Myunghun Kim
058     * @author Raymond Aug??
059     */
060    public class PortletRequestDispatcherImpl
061            implements LiferayPortletRequestDispatcher {
062    
063            public PortletRequestDispatcherImpl(
064                    RequestDispatcher requestDispatcher, boolean named,
065                    PortletContext portletContext) {
066    
067                    this(requestDispatcher, named, portletContext, null);
068            }
069    
070            public PortletRequestDispatcherImpl(
071                    RequestDispatcher requestDispatcher, boolean named,
072                    PortletContext portletContext, String path) {
073    
074                    _requestDispatcher = requestDispatcher;
075                    _named = named;
076                    _liferayPortletContext = (LiferayPortletContext)portletContext;
077                    _path = path;
078    
079                    _portlet = _liferayPortletContext.getPortlet();
080            }
081    
082            @Override
083            public void forward(
084                            PortletRequest portletRequest, PortletResponse portletResponse)
085                    throws IllegalStateException, IOException, PortletException {
086    
087                    HttpServletResponse httpServletResponse =
088                            PortalUtil.getHttpServletResponse(portletResponse);
089    
090                    if (httpServletResponse.isCommitted()) {
091                            throw new IllegalStateException("Response is already committed");
092                    }
093    
094                    dispatch(portletRequest, portletResponse, false, false);
095            }
096    
097            @Override
098            public void include(
099                            PortletRequest portletRequest, PortletResponse portletResponse)
100                    throws IOException, PortletException {
101    
102                    dispatch(portletRequest, portletResponse, false, true);
103            }
104    
105            @Override
106            public void include(
107                            PortletRequest portletRequest, PortletResponse portletResponse,
108                            boolean strutsURLEncoder)
109                    throws IOException, PortletException {
110    
111                    dispatch(portletRequest, portletResponse, strutsURLEncoder, true);
112            }
113    
114            @Override
115            public void include(
116                            RenderRequest renderRequest, RenderResponse renderResponse)
117                    throws IOException, PortletException {
118    
119                    dispatch(renderRequest, renderResponse, false, true);
120            }
121    
122            protected void checkCalledFlushBuffer(
123                    boolean include, PortletResponse portletResponse) {
124    
125                    if (!include && (portletResponse instanceof MimeResponseImpl)) {
126                            MimeResponseImpl mimeResponseImpl =
127                                    (MimeResponseImpl)portletResponse;
128    
129                            if (mimeResponseImpl.isCalledFlushBuffer()) {
130                                    throw new IllegalStateException();
131                            }
132                    }
133            }
134    
135            protected HttpServletRequest createDynamicServletRequest(
136                    HttpServletRequest httpServletRequest,
137                    PortletRequestImpl portletRequestImpl,
138                    Map<String, String[]> parameterMap) {
139    
140                    return DynamicServletRequestUtil.createDynamicServletRequest(
141                            httpServletRequest, portletRequestImpl.getPortlet(), parameterMap,
142                            true);
143            }
144    
145            protected void dispatch(
146                            PortletRequest portletRequest, PortletResponse portletResponse,
147                            boolean strutsURLEncoder, boolean include)
148                    throws IOException, PortletException {
149    
150                    checkCalledFlushBuffer(include, portletResponse);
151    
152                    PortletRequestImpl portletRequestImpl =
153                            PortletRequestImpl.getPortletRequestImpl(portletRequest);
154                    PortletResponseImpl portletResponseImpl =
155                            PortletResponseImpl.getPortletResponseImpl(portletResponse);
156    
157                    HttpServletRequest httpServletRequest =
158                            PortalUtil.getHttpServletRequest(portletRequest);
159    
160                    httpServletRequest.setAttribute(
161                            JavaConstants.JAVAX_PORTLET_REQUEST, portletRequest);
162                    httpServletRequest.setAttribute(
163                            JavaConstants.JAVAX_PORTLET_RESPONSE, portletResponse);
164    
165                    String pathInfo = null;
166                    String queryString = null;
167                    String requestURI = null;
168                    String servletPath = null;
169    
170                    if (_path != null) {
171                            String pathNoQueryString = _path;
172    
173                            int pos = _path.indexOf(CharPool.QUESTION);
174    
175                            if (pos != -1) {
176                                    pathNoQueryString = _path.substring(0, pos);
177                                    queryString = _path.substring(pos + 1);
178    
179                                    httpServletRequest = createDynamicServletRequest(
180                                            httpServletRequest, portletRequestImpl,
181                                            toParameterMap(queryString));
182                            }
183    
184                            Portlet portlet = portletRequestImpl.getPortlet();
185    
186                            PortletApp portletApp = portlet.getPortletApp();
187    
188                            Set<String> servletURLPatterns = portletApp.getServletURLPatterns();
189    
190                            for (String urlPattern : servletURLPatterns) {
191                                    if (urlPattern.endsWith("/*")) {
192                                            int length = urlPattern.length() - 2;
193    
194                                            if ((pathNoQueryString.length() > length) &&
195                                                    pathNoQueryString.regionMatches(
196                                                            0, urlPattern, 0, length) &&
197                                                    (pathNoQueryString.charAt(length) == CharPool.SLASH)) {
198    
199                                                    pathInfo = pathNoQueryString.substring(length);
200                                                    servletPath = urlPattern.substring(0, length);
201    
202                                                    break;
203                                            }
204                                    }
205                            }
206    
207                            if (pathInfo == null) {
208                                    pathInfo = pathNoQueryString;
209                            }
210    
211                            String contextPath = portletRequest.getContextPath();
212    
213                            if (contextPath.equals(StringPool.SLASH)) {
214                                    requestURI = pathNoQueryString;
215                            }
216                            else {
217                                    requestURI = contextPath + pathNoQueryString;
218                            }
219                    }
220    
221                    PortletServletRequest portletServletRequest = new PortletServletRequest(
222                            httpServletRequest, portletRequest, pathInfo, queryString,
223                            requestURI, servletPath, _named, include);
224    
225                    PortletServletResponse portletServletResponse =
226                            new PortletServletResponse(
227                                    PortalUtil.getHttpServletResponse(portletResponse),
228                                    portletResponse, include);
229    
230                    URLEncoder urlEncoder = _portlet.getURLEncoderInstance();
231    
232                    if (urlEncoder != null) {
233                            portletResponseImpl.setURLEncoder(urlEncoder);
234                    }
235                    else if (strutsURLEncoder) {
236                            ThemeDisplay themeDisplay =
237                                    (ThemeDisplay)portletRequest.getAttribute(
238                                            WebKeys.THEME_DISPLAY);
239    
240                            URLEncoder strutsURLEncoderObj = new StrutsURLEncoder(
241                                    portletServletRequest.getContextPath(),
242                                    themeDisplay.getPathMain(),
243                                    (String)_liferayPortletContext.getAttribute(
244                                            Globals.SERVLET_KEY),
245                                    (LiferayPortletURL)portletResponseImpl.createRenderURL());
246    
247                            portletResponseImpl.setURLEncoder(strutsURLEncoderObj);
248                    }
249    
250                    try {
251                            if (include) {
252                                    _requestDispatcher.include(
253                                            portletServletRequest, portletServletResponse);
254                            }
255                            else {
256                                    _requestDispatcher.forward(
257                                            portletServletRequest, portletServletResponse);
258                            }
259                    }
260                    catch (ServletException se) {
261                            _log.error(se, se);
262    
263                            throw new PortletException(se);
264                    }
265            }
266    
267            protected Map<String, String[]> toParameterMap(String queryString) {
268                    Map<String, String[]> parameterMap = new HashMap<>();
269    
270                    for (String parameter :
271                                    StringUtil.split(queryString, CharPool.AMPERSAND)) {
272    
273                            String[] parameterArray = StringUtil.split(
274                                    parameter, CharPool.EQUAL);
275    
276                            String name = parameterArray[0];
277    
278                            String value = StringPool.BLANK;
279    
280                            if (parameterArray.length == 2) {
281                                    value = parameterArray[1];
282                            }
283    
284                            String[] values = parameterMap.get(name);
285    
286                            if (values == null) {
287                                    parameterMap.put(name, new String[] {value});
288                            }
289                            else {
290                                    String[] newValues = new String[values.length + 1];
291    
292                                    System.arraycopy(values, 0, newValues, 0, values.length);
293    
294                                    newValues[newValues.length - 1] = value;
295    
296                                    parameterMap.put(name, newValues);
297                            }
298                    }
299    
300                    return parameterMap;
301            }
302    
303            private static final Log _log = LogFactoryUtil.getLog(
304                    PortletRequestDispatcherImpl.class);
305    
306            private final LiferayPortletContext _liferayPortletContext;
307            private final boolean _named;
308            private final String _path;
309            private final Portlet _portlet;
310            private final RequestDispatcher _requestDispatcher;
311    
312    }