1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portlet;
16  
17  import com.liferay.portal.kernel.log.Log;
18  import com.liferay.portal.kernel.log.LogFactoryUtil;
19  import com.liferay.portal.kernel.portlet.LiferayPortletURL;
20  import com.liferay.portal.kernel.servlet.URLEncoder;
21  import com.liferay.portal.kernel.util.ArrayUtil;
22  import com.liferay.portal.kernel.util.StringPool;
23  import com.liferay.portal.kernel.util.StringUtil;
24  import com.liferay.portal.model.Portlet;
25  import com.liferay.portal.model.PortletApp;
26  import com.liferay.portal.servlet.NamespaceServletRequest;
27  import com.liferay.portal.struts.StrutsURLEncoder;
28  import com.liferay.portal.theme.ThemeDisplay;
29  import com.liferay.portal.util.PortalUtil;
30  import com.liferay.portal.util.WebKeys;
31  import com.liferay.util.servlet.DynamicServletRequest;
32  
33  import java.io.IOException;
34  
35  import java.util.HashMap;
36  import java.util.Map;
37  import java.util.Set;
38  
39  import javax.portlet.PortletException;
40  import javax.portlet.PortletRequest;
41  import javax.portlet.PortletRequestDispatcher;
42  import javax.portlet.PortletResponse;
43  import javax.portlet.RenderRequest;
44  import javax.portlet.RenderResponse;
45  
46  import javax.servlet.RequestDispatcher;
47  import javax.servlet.ServletException;
48  import javax.servlet.http.HttpServletRequest;
49  import javax.servlet.http.HttpServletResponse;
50  
51  import org.apache.struts.Globals;
52  
53  /**
54   * <a href="PortletRequestDispatcherImpl.java.html"><b><i>View Source</i></b>
55   * </a>
56   *
57   * @author Brian Wing Shun Chan
58   * @author Brian Myunghun Kim
59   */
60  public class PortletRequestDispatcherImpl implements PortletRequestDispatcher {
61  
62      public PortletRequestDispatcherImpl(
63          RequestDispatcher requestDispatcher, boolean named,
64          PortletContextImpl portletContextImpl) {
65  
66          this(requestDispatcher, named, portletContextImpl, null);
67      }
68  
69      public PortletRequestDispatcherImpl(
70          RequestDispatcher requestDispatcher, boolean named,
71          PortletContextImpl portletContextImpl, String path) {
72  
73          _requestDispatcher = requestDispatcher;
74          _named = named;
75          _portlet = portletContextImpl.getPortlet();
76          _portletContextImpl = portletContextImpl;
77          _path = path;
78      }
79  
80      public void forward(
81              PortletRequest portletRequest, PortletResponse portletResponse)
82          throws IllegalStateException, IOException, PortletException {
83  
84          HttpServletResponse response = PortalUtil.getHttpServletResponse(
85              portletResponse);
86  
87          if (response.isCommitted()) {
88              throw new IllegalStateException("Response is already committed");
89          }
90  
91          try {
92              dispatch(portletRequest, portletResponse, false, false);
93          }
94          catch (ServletException se) {
95              _log.error(se, se);
96  
97              throw new PortletException(se);
98          }
99      }
100 
101     public void include(
102             PortletRequest portletRequest, PortletResponse portletResponse)
103         throws IOException, PortletException {
104 
105         try {
106             dispatch(portletRequest, portletResponse, false, true);
107         }
108         catch (ServletException se) {
109             _log.error(se, se);
110 
111             throw new PortletException(se);
112         }
113     }
114 
115     public void include(
116             PortletRequest portletRequest, PortletResponse portletResponse,
117             boolean strutsURLEncoder)
118         throws IOException, PortletException {
119 
120         try {
121             dispatch(portletRequest, portletResponse, strutsURLEncoder, true);
122         }
123         catch (ServletException se) {
124             _log.error(se, se);
125 
126             throw new PortletException(se);
127         }
128     }
129 
130     public void include(
131             RenderRequest renderRequest, RenderResponse renderResponse)
132         throws IOException, PortletException {
133 
134         try {
135             dispatch(renderRequest, renderResponse, false, true);
136         }
137         catch (ServletException se) {
138             _log.error(se, se);
139 
140             throw new PortletException(se);
141         }
142     }
143 
144     protected void dispatch(
145             PortletRequest portletRequest, PortletResponse portletResponse,
146             boolean strutsURLEncoder, boolean include)
147         throws IOException, ServletException {
148 
149         if (!include) {
150             if (portletResponse instanceof MimeResponseImpl) {
151                 MimeResponseImpl mimeResponseImpl =
152                     (MimeResponseImpl)portletResponse;
153 
154                 if (mimeResponseImpl.isCalledFlushBuffer()) {
155                     throw new IllegalStateException();
156                 }
157             }
158         }
159 
160         PortletRequestImpl portletRequestImpl =
161             (PortletRequestImpl)portletRequest;
162         PortletResponseImpl portletResponseImpl =
163             PortletResponseImpl.getPortletResponseImpl(portletResponse);
164 
165         HttpServletRequest request = PortalUtil.getHttpServletRequest(
166             portletRequest);
167         HttpServletResponse response = PortalUtil.getHttpServletResponse(
168             portletResponse);
169 
170         String pathInfo = null;
171         String queryString = null;
172         String requestURI = null;
173         String servletPath = null;
174 
175         if (_path != null) {
176             String pathNoQueryString = _path;
177 
178             int pos = _path.indexOf(StringPool.QUESTION);
179 
180             if (pos != -1) {
181                 pathNoQueryString = _path.substring(0, pos);
182                 queryString = _path.substring(pos + 1, _path.length());
183 
184                 Map<String, String[]> queryParams =
185                     new HashMap<String, String[]>();
186 
187                 String[] queryParamsArray = StringUtil.split(
188                     queryString, StringPool.AMPERSAND);
189 
190                 for (int i = 0; i < queryParamsArray.length; i++) {
191                     String[] nameValuePair = StringUtil.split(
192                         queryParamsArray[i], StringPool.EQUAL);
193 
194                     String name = nameValuePair[0];
195                     String value = StringPool.BLANK;
196 
197                     if (nameValuePair.length == 2) {
198                         value = nameValuePair[1];
199                     }
200 
201                     String[] values = queryParams.get(name);
202 
203                     if (values == null) {
204                         queryParams.put(name, new String[] {value});
205                     }
206                     else {
207                         String[] newValues = new String[values.length + 1];
208 
209                         System.arraycopy(
210                             values, 0, newValues, 0, values.length);
211 
212                         newValues[newValues.length - 1] = value;
213 
214                         queryParams.put(name, newValues);
215                     }
216                 }
217 
218                 DynamicServletRequest dynamicRequest = null;
219 
220                 if (portletRequestImpl.isPrivateRequestAttributes()) {
221                     String portletNamespace = PortalUtil.getPortletNamespace(
222                         portletRequestImpl.getPortletName());
223 
224                     dynamicRequest = new NamespaceServletRequest(
225                         request, portletNamespace, portletNamespace);
226                 }
227                 else {
228                     dynamicRequest = new DynamicServletRequest(request);
229                 }
230 
231                 for (Map.Entry<String, String[]> entry :
232                         queryParams.entrySet()) {
233 
234                     String name = entry.getKey();
235                     String[] values = entry.getValue();
236 
237                     String[] oldValues = dynamicRequest.getParameterValues(
238                         name);
239 
240                     if (oldValues == null) {
241                         dynamicRequest.setParameterValues(name, values);
242                     }
243                     else {
244                         String[] newValues = ArrayUtil.append(
245                             values, oldValues);
246 
247                         dynamicRequest.setParameterValues(name, newValues);
248                     }
249                 }
250 
251                 request = dynamicRequest;
252             }
253 
254             Portlet portlet = portletRequestImpl.getPortlet();
255 
256             PortletApp portletApp = portlet.getPortletApp();
257 
258             Set<String> servletURLPatterns = portletApp.getServletURLPatterns();
259 
260             for (String urlPattern : servletURLPatterns) {
261                 if (urlPattern.endsWith("/*")) {
262                     pos = urlPattern.indexOf("/*");
263 
264                     urlPattern = urlPattern.substring(0, pos);
265 
266                     if (pathNoQueryString.startsWith(urlPattern)) {
267                         pathInfo = pathNoQueryString.substring(
268                             urlPattern.length());
269                         servletPath = urlPattern;
270 
271                         break;
272                     }
273                 }
274             }
275 
276             if ((pathInfo == null) && (servletPath == null)) {
277                 pathInfo = pathNoQueryString;
278                 servletPath = pathNoQueryString;
279             }
280 
281             requestURI = portletRequest.getContextPath() + pathNoQueryString;
282         }
283 
284         PortletServletRequest portletServletRequest = new PortletServletRequest(
285             request, portletRequestImpl, pathInfo, queryString, requestURI,
286             servletPath, _named, include);
287 
288         PortletServletResponse portletServletResponse =
289             new PortletServletResponse(response, portletResponseImpl, include);
290 
291         URLEncoder urlEncoder = _portlet.getURLEncoderInstance();
292 
293         if (urlEncoder != null) {
294             portletResponseImpl.setURLEncoder(urlEncoder);
295         }
296         else if (strutsURLEncoder) {
297             ThemeDisplay themeDisplay =
298                 (ThemeDisplay)portletRequest.getAttribute(
299                     WebKeys.THEME_DISPLAY);
300 
301             URLEncoder strutsURLEncoderObj = new StrutsURLEncoder(
302                 portletServletRequest.getContextPath(),
303                 themeDisplay.getPathMain(),
304                 (String)_portletContextImpl.getAttribute(
305                     Globals.SERVLET_KEY),
306                 (LiferayPortletURL)portletResponseImpl.createRenderURL());
307 
308             portletResponseImpl.setURLEncoder(strutsURLEncoderObj);
309         }
310 
311         if (include) {
312             _requestDispatcher.include(
313                 portletServletRequest, portletServletResponse);
314         }
315         else {
316             _requestDispatcher.forward(
317                 portletServletRequest, portletServletResponse);
318         }
319     }
320 
321     private static Log _log = LogFactoryUtil.getLog(
322         PortletRequestDispatcherImpl.class);
323 
324     private RequestDispatcher _requestDispatcher;
325     private boolean _named;
326     private Portlet _portlet;
327     private PortletContextImpl _portletContextImpl;
328     private String _path;
329 
330 }