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.portlet.LiferayPortletContext;
020    import com.liferay.portal.kernel.portlet.LiferayPortletRequestDispatcher;
021    import com.liferay.portal.kernel.portlet.LiferayPortletURL;
022    import com.liferay.portal.kernel.servlet.DynamicServletRequest;
023    import com.liferay.portal.kernel.servlet.URLEncoder;
024    import com.liferay.portal.kernel.util.ArrayUtil;
025    import com.liferay.portal.kernel.util.CharPool;
026    import com.liferay.portal.kernel.util.JavaConstants;
027    import com.liferay.portal.kernel.util.StringPool;
028    import com.liferay.portal.kernel.util.StringUtil;
029    import com.liferay.portal.kernel.util.WebKeys;
030    import com.liferay.portal.model.Portlet;
031    import com.liferay.portal.model.PortletApp;
032    import com.liferay.portal.servlet.NamespaceServletRequest;
033    import com.liferay.portal.struts.StrutsURLEncoder;
034    import com.liferay.portal.theme.ThemeDisplay;
035    import com.liferay.portal.util.PortalUtil;
036    
037    import java.io.IOException;
038    
039    import java.util.HashMap;
040    import java.util.Map;
041    import java.util.Set;
042    
043    import javax.portlet.PortletContext;
044    import javax.portlet.PortletException;
045    import javax.portlet.PortletRequest;
046    import javax.portlet.PortletResponse;
047    import javax.portlet.RenderRequest;
048    import javax.portlet.RenderResponse;
049    
050    import javax.servlet.RequestDispatcher;
051    import javax.servlet.ServletException;
052    import javax.servlet.http.HttpServletRequest;
053    import javax.servlet.http.HttpServletResponse;
054    
055    import org.apache.struts.Globals;
056    
057    /**
058     * @author Brian Wing Shun Chan
059     * @author Brian Myunghun Kim
060     * @author Raymond Aug??
061     */
062    public class PortletRequestDispatcherImpl
063            implements LiferayPortletRequestDispatcher {
064    
065            public PortletRequestDispatcherImpl(
066                    RequestDispatcher requestDispatcher, boolean named,
067                    PortletContext portletContext) {
068    
069                    this(requestDispatcher, named, portletContext, null);
070            }
071    
072            public PortletRequestDispatcherImpl(
073                    RequestDispatcher requestDispatcher, boolean named,
074                    PortletContext portletContext, String path) {
075    
076                    _requestDispatcher = requestDispatcher;
077                    _named = named;
078                    _liferayPortletContext = (LiferayPortletContext)portletContext;
079                    _path = path;
080    
081                    _portlet = _liferayPortletContext.getPortlet();
082            }
083    
084            @Override
085            public void forward(
086                            PortletRequest portletRequest, PortletResponse portletResponse)
087                    throws IllegalStateException, IOException, PortletException {
088    
089                    HttpServletResponse httpServletResponse =
090                            PortalUtil.getHttpServletResponse(portletResponse);
091    
092                    if (httpServletResponse.isCommitted()) {
093                            throw new IllegalStateException("Response is already committed");
094                    }
095    
096                    dispatch(portletRequest, portletResponse, false, false);
097            }
098    
099            @Override
100            public void include(
101                            PortletRequest portletRequest, PortletResponse portletResponse)
102                    throws IOException, PortletException {
103    
104                    dispatch(portletRequest, portletResponse, false, true);
105            }
106    
107            @Override
108            public void include(
109                            PortletRequest portletRequest, PortletResponse portletResponse,
110                            boolean strutsURLEncoder)
111                    throws IOException, PortletException {
112    
113                    dispatch(portletRequest, portletResponse, strutsURLEncoder, true);
114            }
115    
116            @Override
117            public void include(
118                            RenderRequest renderRequest, RenderResponse renderResponse)
119                    throws IOException, PortletException {
120    
121                    dispatch(renderRequest, renderResponse, false, true);
122            }
123    
124            protected void checkCalledFlushBuffer(
125                    boolean include, PortletResponse portletResponse) {
126    
127                    if (!include && (portletResponse instanceof MimeResponseImpl)) {
128                            MimeResponseImpl mimeResponseImpl =
129                                    (MimeResponseImpl)portletResponse;
130    
131                            if (mimeResponseImpl.isCalledFlushBuffer()) {
132                                    throw new IllegalStateException();
133                            }
134                    }
135            }
136    
137            protected HttpServletRequest createDynamicServletRequest(
138                    HttpServletRequest httpServletRequest,
139                    PortletRequestImpl portletRequestImpl,
140                    Map<String, String[]> parameterMap) {
141    
142                    DynamicServletRequest dynamicServletRequest = null;
143    
144                    if (portletRequestImpl.isPrivateRequestAttributes()) {
145                            String portletNamespace = PortalUtil.getPortletNamespace(
146                                    portletRequestImpl.getPortletName());
147    
148                            dynamicServletRequest = new NamespaceServletRequest(
149                                    httpServletRequest, portletNamespace, portletNamespace);
150                    }
151                    else {
152                            dynamicServletRequest = new DynamicServletRequest(
153                                    httpServletRequest);
154                    }
155    
156                    for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
157                            String name = entry.getKey();
158    
159                            String[] values = entry.getValue();
160    
161                            String[] oldValues = dynamicServletRequest.getParameterValues(name);
162    
163                            if (oldValues != null) {
164                                    values = ArrayUtil.append(values, oldValues);
165                            }
166    
167                            dynamicServletRequest.setParameterValues(name, values);
168                    }
169    
170                    return dynamicServletRequest;
171            }
172    
173            protected void dispatch(
174                            PortletRequest portletRequest, PortletResponse portletResponse,
175                            boolean strutsURLEncoder, boolean include)
176                    throws IOException, PortletException {
177    
178                    checkCalledFlushBuffer(include, portletResponse);
179    
180                    PortletRequestImpl portletRequestImpl =
181                            PortletRequestImpl.getPortletRequestImpl(portletRequest);
182                    PortletResponseImpl portletResponseImpl =
183                            PortletResponseImpl.getPortletResponseImpl(portletResponse);
184    
185                    HttpServletRequest httpServletRequest =
186                            PortalUtil.getHttpServletRequest(portletRequest);
187    
188                    httpServletRequest.setAttribute(
189                            JavaConstants.JAVAX_PORTLET_REQUEST, portletRequest);
190                    httpServletRequest.setAttribute(
191                            JavaConstants.JAVAX_PORTLET_RESPONSE, portletResponse);
192    
193                    String pathInfo = null;
194                    String queryString = null;
195                    String requestURI = null;
196                    String servletPath = null;
197    
198                    if (_path != null) {
199                            String pathNoQueryString = _path;
200    
201                            int pos = _path.indexOf(CharPool.QUESTION);
202    
203                            if (pos != -1) {
204                                    pathNoQueryString = _path.substring(0, pos);
205                                    queryString = _path.substring(pos + 1);
206    
207                                    httpServletRequest = createDynamicServletRequest(
208                                            httpServletRequest, portletRequestImpl,
209                                            toParameterMap(queryString));
210                            }
211    
212                            Portlet portlet = portletRequestImpl.getPortlet();
213    
214                            PortletApp portletApp = portlet.getPortletApp();
215    
216                            Set<String> servletURLPatterns = portletApp.getServletURLPatterns();
217    
218                            for (String urlPattern : servletURLPatterns) {
219                                    if (urlPattern.endsWith("/*")) {
220                                            urlPattern = urlPattern.substring(
221                                                    0, urlPattern.length() - 2);
222    
223                                            if ((pathNoQueryString.length() > urlPattern.length()) &&
224                                                    pathNoQueryString.startsWith(urlPattern) &&
225                                                    (pathNoQueryString.charAt(urlPattern.length()) ==
226                                                            CharPool.SLASH)) {
227    
228                                                    pathInfo = pathNoQueryString.substring(
229                                                            urlPattern.length());
230                                                    servletPath = urlPattern;
231    
232                                                    break;
233                                            }
234                                    }
235                            }
236    
237                            if (pathInfo == null) {
238                                    pathInfo = pathNoQueryString;
239                            }
240    
241                            String contextPath = portletRequest.getContextPath();
242    
243                            if (contextPath.equals(StringPool.SLASH)) {
244                                    requestURI = pathNoQueryString;
245                            }
246                            else {
247                                    requestURI = contextPath + pathNoQueryString;
248                            }
249                    }
250    
251                    PortletServletRequest portletServletRequest = new PortletServletRequest(
252                            httpServletRequest, portletRequest, pathInfo, queryString,
253                            requestURI, servletPath, _named, include);
254    
255                    PortletServletResponse portletServletResponse =
256                            new PortletServletResponse(
257                                    PortalUtil.getHttpServletResponse(portletResponse),
258                                    portletResponse, include);
259    
260                    URLEncoder urlEncoder = _portlet.getURLEncoderInstance();
261    
262                    if (urlEncoder != null) {
263                            portletResponseImpl.setURLEncoder(urlEncoder);
264                    }
265                    else if (strutsURLEncoder) {
266                            ThemeDisplay themeDisplay =
267                                    (ThemeDisplay)portletRequest.getAttribute(
268                                            WebKeys.THEME_DISPLAY);
269    
270                            URLEncoder strutsURLEncoderObj = new StrutsURLEncoder(
271                                    portletServletRequest.getContextPath(),
272                                    themeDisplay.getPathMain(),
273                                    (String)_liferayPortletContext.getAttribute(
274                                            Globals.SERVLET_KEY),
275                                    (LiferayPortletURL)portletResponseImpl.createRenderURL());
276    
277                            portletResponseImpl.setURLEncoder(strutsURLEncoderObj);
278                    }
279    
280                    try {
281                            if (include) {
282                                    _requestDispatcher.include(
283                                            portletServletRequest, portletServletResponse);
284                            }
285                            else {
286                                    _requestDispatcher.forward(
287                                            portletServletRequest, portletServletResponse);
288                            }
289                    }
290                    catch (ServletException se) {
291                            _log.error(se, se);
292    
293                            throw new PortletException(se);
294                    }
295            }
296    
297            protected Map<String, String[]> toParameterMap(String queryString) {
298                    Map<String, String[]> parameterMap = new HashMap<>();
299    
300                    for (String parameter :
301                                    StringUtil.split(queryString, CharPool.AMPERSAND)) {
302    
303                            String[] parameterArray = StringUtil.split(
304                                    parameter, CharPool.EQUAL);
305    
306                            String name = parameterArray[0];
307    
308                            String value = StringPool.BLANK;
309    
310                            if (parameterArray.length == 2) {
311                                    value = parameterArray[1];
312                            }
313    
314                            String[] values = parameterMap.get(name);
315    
316                            if (values == null) {
317                                    parameterMap.put(name, new String[] {value});
318                            }
319                            else {
320                                    String[] newValues = new String[values.length + 1];
321    
322                                    System.arraycopy(values, 0, newValues, 0, values.length);
323    
324                                    newValues[newValues.length - 1] = value;
325    
326                                    parameterMap.put(name, newValues);
327                            }
328                    }
329    
330                    return parameterMap;
331            }
332    
333            private static final Log _log = LogFactoryUtil.getLog(
334                    PortletRequestDispatcherImpl.class);
335    
336            private final LiferayPortletContext _liferayPortletContext;
337            private final boolean _named;
338            private final String _path;
339            private final Portlet _portlet;
340            private final RequestDispatcher _requestDispatcher;
341    
342    }