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                                            urlPattern = urlPattern.substring(
193                                                    0, urlPattern.length() - 2);
194    
195                                            if ((pathNoQueryString.length() > urlPattern.length()) &&
196                                                    pathNoQueryString.startsWith(urlPattern) &&
197                                                    (pathNoQueryString.charAt(urlPattern.length()) ==
198                                                            CharPool.SLASH)) {
199    
200                                                    pathInfo = pathNoQueryString.substring(
201                                                            urlPattern.length());
202                                                    servletPath = urlPattern;
203    
204                                                    break;
205                                            }
206                                    }
207                            }
208    
209                            if (pathInfo == null) {
210                                    pathInfo = pathNoQueryString;
211                            }
212    
213                            String contextPath = portletRequest.getContextPath();
214    
215                            if (contextPath.equals(StringPool.SLASH)) {
216                                    requestURI = pathNoQueryString;
217                            }
218                            else {
219                                    requestURI = contextPath + pathNoQueryString;
220                            }
221                    }
222    
223                    PortletServletRequest portletServletRequest = new PortletServletRequest(
224                            httpServletRequest, portletRequest, pathInfo, queryString,
225                            requestURI, servletPath, _named, include);
226    
227                    PortletServletResponse portletServletResponse =
228                            new PortletServletResponse(
229                                    PortalUtil.getHttpServletResponse(portletResponse),
230                                    portletResponse, include);
231    
232                    URLEncoder urlEncoder = _portlet.getURLEncoderInstance();
233    
234                    if (urlEncoder != null) {
235                            portletResponseImpl.setURLEncoder(urlEncoder);
236                    }
237                    else if (strutsURLEncoder) {
238                            ThemeDisplay themeDisplay =
239                                    (ThemeDisplay)portletRequest.getAttribute(
240                                            WebKeys.THEME_DISPLAY);
241    
242                            URLEncoder strutsURLEncoderObj = new StrutsURLEncoder(
243                                    portletServletRequest.getContextPath(),
244                                    themeDisplay.getPathMain(),
245                                    (String)_liferayPortletContext.getAttribute(
246                                            Globals.SERVLET_KEY),
247                                    (LiferayPortletURL)portletResponseImpl.createRenderURL());
248    
249                            portletResponseImpl.setURLEncoder(strutsURLEncoderObj);
250                    }
251    
252                    try {
253                            if (include) {
254                                    _requestDispatcher.include(
255                                            portletServletRequest, portletServletResponse);
256                            }
257                            else {
258                                    _requestDispatcher.forward(
259                                            portletServletRequest, portletServletResponse);
260                            }
261                    }
262                    catch (ServletException se) {
263                            _log.error(se, se);
264    
265                            throw new PortletException(se);
266                    }
267            }
268    
269            protected Map<String, String[]> toParameterMap(String queryString) {
270                    Map<String, String[]> parameterMap = new HashMap<>();
271    
272                    for (String parameter :
273                                    StringUtil.split(queryString, CharPool.AMPERSAND)) {
274    
275                            String[] parameterArray = StringUtil.split(
276                                    parameter, CharPool.EQUAL);
277    
278                            String name = parameterArray[0];
279    
280                            String value = StringPool.BLANK;
281    
282                            if (parameterArray.length == 2) {
283                                    value = parameterArray[1];
284                            }
285    
286                            String[] values = parameterMap.get(name);
287    
288                            if (values == null) {
289                                    parameterMap.put(name, new String[] {value});
290                            }
291                            else {
292                                    String[] newValues = new String[values.length + 1];
293    
294                                    System.arraycopy(values, 0, newValues, 0, values.length);
295    
296                                    newValues[newValues.length - 1] = value;
297    
298                                    parameterMap.put(name, newValues);
299                            }
300                    }
301    
302                    return parameterMap;
303            }
304    
305            private static final Log _log = LogFactoryUtil.getLog(
306                    PortletRequestDispatcherImpl.class);
307    
308            private final LiferayPortletContext _liferayPortletContext;
309            private final boolean _named;
310            private final String _path;
311            private final Portlet _portlet;
312            private final RequestDispatcher _requestDispatcher;
313    
314    }