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