1   /**
2    * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portlet;
24  
25  import com.liferay.portal.kernel.portlet.LiferayPortletURL;
26  import com.liferay.portal.kernel.servlet.URLEncoder;
27  import com.liferay.portal.kernel.util.ArrayUtil;
28  import com.liferay.portal.kernel.util.StringPool;
29  import com.liferay.portal.kernel.util.StringUtil;
30  import com.liferay.portal.model.Portlet;
31  import com.liferay.portal.model.PortletApp;
32  import com.liferay.portal.servlet.NamespaceServletRequest;
33  import com.liferay.portal.struts.StrutsURLEncoder;
34  import com.liferay.portal.theme.ThemeDisplay;
35  import com.liferay.portal.util.PortalUtil;
36  import com.liferay.portal.util.WebKeys;
37  import com.liferay.util.servlet.DynamicServletRequest;
38  
39  import java.io.IOException;
40  
41  import java.util.HashMap;
42  import java.util.Map;
43  import java.util.Set;
44  
45  import javax.portlet.PortletException;
46  import javax.portlet.PortletRequest;
47  import javax.portlet.PortletRequestDispatcher;
48  import javax.portlet.PortletResponse;
49  import javax.portlet.RenderRequest;
50  import javax.portlet.RenderResponse;
51  
52  import javax.servlet.RequestDispatcher;
53  import javax.servlet.ServletException;
54  import javax.servlet.http.HttpServletRequest;
55  import javax.servlet.http.HttpServletResponse;
56  
57  import org.apache.commons.logging.Log;
58  import org.apache.commons.logging.LogFactory;
59  import org.apache.struts.Globals;
60  
61  /**
62   * <a href="PortletRequestDispatcherImpl.java.html"><b><i>View Source</i></b>
63   * </a>
64   *
65   * @author Brian Wing Shun Chan
66   * @author Brian Myunghun Kim
67   *
68   */
69  public class PortletRequestDispatcherImpl implements PortletRequestDispatcher {
70  
71      public PortletRequestDispatcherImpl(
72          RequestDispatcher rd, boolean named,
73          PortletContextImpl portletCtxImpl) {
74  
75          this(rd, named, portletCtxImpl, null);
76      }
77  
78      public PortletRequestDispatcherImpl(
79          RequestDispatcher rd, boolean named, PortletContextImpl portletCtxImpl,
80          String path) {
81  
82          _rd = rd;
83          _named = named;
84          _portlet = portletCtxImpl.getPortlet();
85          _portletCtxImpl = portletCtxImpl;
86          _path = path;
87      }
88  
89      public void forward(PortletRequest req, PortletResponse res)
90          throws IllegalStateException, IOException, PortletException {
91  
92          HttpServletResponse httpRes = PortalUtil.getHttpServletResponse(res);
93  
94          if (httpRes.isCommitted()) {
95              throw new IllegalStateException("Response is already committed");
96          }
97  
98          dispatch(req, res, false, false);
99      }
100 
101     public void include(PortletRequest req, PortletResponse res)
102         throws IOException, PortletException {
103 
104         dispatch(req, res, false, true);
105     }
106 
107     public void include(
108             PortletRequest req, PortletResponse res, boolean strutsURLEncoder)
109         throws IOException, PortletException {
110 
111         dispatch(req, res, strutsURLEncoder, true);
112     }
113 
114     public void include(RenderRequest req, RenderResponse res)
115         throws IOException, PortletException {
116 
117         dispatch(req, res, false, true);
118     }
119 
120     protected void dispatch(
121             PortletRequest req, PortletResponse res, boolean strutsURLEncoder,
122             boolean include)
123         throws IOException, PortletException {
124 
125         if (!include) {
126             if (res instanceof MimeResponseImpl) {
127                 MimeResponseImpl mimeResImpl = (MimeResponseImpl)res;
128 
129                 if (mimeResImpl.isCalledFlushBuffer()) {
130                     throw new IllegalStateException();
131                 }
132             }
133         }
134 
135         try {
136             PortletRequestImpl reqImpl = (PortletRequestImpl)req;
137             PortletResponseImpl resImpl =
138                 PortletResponseImpl.getPortletResponseImpl(res);
139 
140             HttpServletRequest httpReq = PortalUtil.getHttpServletRequest(req);
141             HttpServletResponse httpRes =
142                 PortalUtil.getHttpServletResponse(res);
143 
144             String pathInfo = null;
145             String queryString = null;
146             String requestURI = null;
147             String servletPath = null;
148 
149             if (_path != null) {
150                 /*if (ServerDetector.isJetty()) {
151                     int pos = _path.indexOf(StringPool.QUESTION);
152 
153                     if (pos != -1) {
154                         _path = _path.substring(0, pos);
155                     }
156                 }*/
157 
158                 String pathNoQueryString = _path;
159 
160                 int pos = _path.indexOf(StringPool.QUESTION);
161 
162                 if (pos != -1) {
163                     pathNoQueryString = _path.substring(0, pos);
164                     queryString = _path.substring(pos + 1, _path.length());
165 
166                     Map<String, String[]> queryParams =
167                         new HashMap<String, String[]>();
168 
169                     String[] queryParamsArray =
170                         StringUtil.split(queryString, StringPool.AMPERSAND);
171 
172                     for (int i = 0; i < queryParamsArray.length; i++) {
173                         String[] nameValuePair = StringUtil.split(
174                             queryParamsArray[i], StringPool.EQUAL);
175                         String name = nameValuePair[0];
176                         String value = nameValuePair[1];
177 
178                         String[] values = queryParams.get(name);
179 
180                         if (values == null) {
181                             queryParams.put(name, new String[] {value});
182                         }
183                         else {
184                             String[] newValues = new String[values.length + 1];
185 
186                             System.arraycopy(
187                                 values, 0, newValues, 0, values.length);
188 
189                             newValues[newValues.length - 1] = value;
190 
191                             queryParams.put(name, newValues);
192                         }
193                     }
194 
195                     DynamicServletRequest dynamicReq = null;
196 
197                     if (reqImpl.isPrivateRequestAttributes()) {
198                         String portletNamespace =
199                             PortalUtil.getPortletNamespace(
200                                 reqImpl.getPortletName());
201 
202                         dynamicReq = new NamespaceServletRequest(
203                             httpReq, portletNamespace, portletNamespace);
204                     }
205                     else {
206                         dynamicReq = new DynamicServletRequest(httpReq);
207                     }
208 
209                     for (Map.Entry<String, String[]> entry :
210                             queryParams.entrySet()) {
211 
212                         String name = entry.getKey();
213                         String[] values = entry.getValue();
214 
215                         String[] oldValues =
216                             dynamicReq.getParameterValues(name);
217 
218                         if (oldValues == null) {
219                             dynamicReq.setParameterValues(name, values);
220                         }
221                         else {
222                             String[] newValues = ArrayUtil.append(
223                                 values, oldValues);
224 
225                             dynamicReq.setParameterValues(name, newValues);
226                         }
227                     }
228 
229                     httpReq = dynamicReq;
230                 }
231 
232                 Portlet portlet = reqImpl.getPortlet();
233 
234                 PortletApp portletApp = portlet.getPortletApp();
235 
236                 Set<String> servletURLPatterns =
237                     portletApp.getServletURLPatterns();
238 
239                 for (String urlPattern : servletURLPatterns) {
240                     if (urlPattern.endsWith("/*")) {
241                         pos = urlPattern.indexOf("/*");
242 
243                         urlPattern = urlPattern.substring(0, pos);
244 
245                         if (pathNoQueryString.startsWith(urlPattern)) {
246                             pathInfo = pathNoQueryString.substring(
247                                 urlPattern.length());
248                             servletPath = urlPattern;
249 
250                             break;
251                         }
252                     }
253                 }
254 
255                 if ((pathInfo == null) && (servletPath == null)) {
256                     pathInfo = StringPool.BLANK;
257                     servletPath = pathNoQueryString;
258                 }
259 
260                 requestURI = req.getContextPath() + pathNoQueryString;
261             }
262 
263             PortletServletRequest portletServletReq = new PortletServletRequest(
264                 httpReq, reqImpl, pathInfo, queryString, requestURI,
265                 servletPath, _named, include);
266 
267             PortletServletResponse portletServletRes =
268                 new PortletServletResponse(httpRes, resImpl, include);
269 
270             URLEncoder urlEncoder = _portlet.getURLEncoderInstance();
271 
272             if (urlEncoder != null) {
273                 resImpl.setURLEncoder(urlEncoder);
274             }
275             else if (strutsURLEncoder) {
276                 ThemeDisplay themeDisplay =
277                     (ThemeDisplay)req.getAttribute(WebKeys.THEME_DISPLAY);
278 
279                 URLEncoder strutsURLEncoderObj = new StrutsURLEncoder(
280                     portletServletReq.getContextPath(),
281                     themeDisplay.getPathMain(),
282                     (String)_portletCtxImpl.getAttribute(Globals.SERVLET_KEY),
283                     (LiferayPortletURL)resImpl.createRenderURL());
284 
285                 resImpl.setURLEncoder(strutsURLEncoderObj);
286             }
287 
288             if (include) {
289                 _rd.include(portletServletReq, portletServletRes);
290             }
291             else {
292                 _rd.forward(portletServletReq, portletServletRes);
293             }
294         }
295         catch (ServletException se) {
296             _log.error(se, se);
297 
298             throw new PortletException(se);
299         }
300     }
301 
302     private static Log _log =
303         LogFactory.getLog(PortletRequestDispatcherImpl.class);
304 
305     private RequestDispatcher _rd;
306     private boolean _named;
307     private Portlet _portlet;
308     private PortletContextImpl _portletCtxImpl;
309     private String _path;
310 
311 }