1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.portletbridge.portlet;
17
18 import java.io.IOException;
19 import java.io.PrintWriter;
20 import java.net.URI;
21 import java.net.URISyntaxException;
22 import java.text.MessageFormat;
23 import java.util.Arrays;
24 import java.util.Enumeration;
25 import java.util.HashSet;
26 import java.util.PropertyResourceBundle;
27 import java.util.ResourceBundle;
28 import java.util.Set;
29
30 import javax.servlet.ServletException;
31 import javax.servlet.http.HttpServlet;
32 import javax.servlet.http.HttpServletRequest;
33 import javax.servlet.http.HttpServletResponse;
34 import javax.servlet.http.HttpSession;
35
36 import org.apache.commons.httpclient.Header;
37 import org.apache.commons.httpclient.HttpMethodBase;
38 import org.apache.commons.httpclient.HttpStatus;
39 import org.apache.commons.httpclient.URIException;
40 import org.apache.commons.httpclient.methods.GetMethod;
41 import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
42 import org.apache.commons.httpclient.methods.PostMethod;
43 import org.portletbridge.PortletBridgeException;
44 import org.portletbridge.ResourceException;
45
46 /***
47 * @author jmccrindle
48 * @author rickard
49 */
50 public class PortletBridgeServlet extends HttpServlet {
51
52 /***
53 * default serial version id
54 */
55 private static final long serialVersionUID = 7841139248662925798L;
56
57 public static final ResourceBundle resourceBundle = PropertyResourceBundle
58 .getBundle("org.portletbridge.portlet.PortletBridgePortlet");
59
60 private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
61 .getLog(PortletBridgeServlet.class);
62
63 private PortletBridgeService portletBridgeService = new DefaultPortletBridgeService();
64
65 private HttpClientTemplate httpClientTemplate = new DefaultHttpClientTemplate();
66
67 private String mementoSessionKey;
68
69 private BridgeFunctionsFactory bridgeFunctionsFactory;
70
71 private Set ignoreRequestHeaders;
72
73 private Set ignorePostToGetRequestHeaders;
74
75 /***
76 * Initialise the servlet. Will throw a servlet exception if the
77 * proxyBrowserSessionKey is not set.
78 *
79 * @see javax.servlet.GenericServlet#init()
80 */
81 public void init() throws ServletException {
82
83
84 mementoSessionKey = this.getServletConfig().getInitParameter(
85 "mementoSessionKey");
86
87 log.debug("init(): mementoSessionKey=" + mementoSessionKey);
88
89 if (mementoSessionKey == null) {
90 throw new ServletException(resourceBundle
91 .getString("error.mementoSessionKey"));
92 }
93
94
95 String cssRegex = this.getServletConfig().getInitParameter("cssRegex");
96 String javascriptRegex = this.getServletConfig().getInitParameter(
97 "jsRegex");
98
99 ContentRewriter javascriptRewriter = new RegexContentRewriter(
100 javascriptRegex);
101 ContentRewriter cssRewriter = new RegexContentRewriter(cssRegex);
102
103 bridgeFunctionsFactory = new BridgeFunctionsFactory(DefaultIdGenerator
104 .getInstance(), javascriptRewriter, cssRewriter);
105
106
107 ignoreRequestHeaders = new HashSet(Arrays.asList(getInitParameter(
108 "ignoreRequestHeaders").split(",")));
109
110 ignorePostToGetRequestHeaders = new HashSet(Arrays.asList(getInitParameter(
111 "ignorePostToGetRequestHeaders").split(",")));
112
113 }
114
115 /***
116 * url pattern should be: http://host:port/context/servlet/id
117 */
118 protected void doGet(final HttpServletRequest request,
119 final HttpServletResponse response) throws ServletException,
120 IOException {
121
122 final String id = portletBridgeService.getIdFromRequestUri(request
123 .getContextPath(), request.getRequestURI());
124
125 HttpSession session = request.getSession();
126 if (session == null) {
127 throw new ServletException(resourceBundle
128 .getString("error.nosession")
129 + ", URL=" + request.getRequestURI());
130 }
131 final PortletBridgeMemento memento = (PortletBridgeMemento) session
132 .getAttribute(mementoSessionKey);
133 if (memento == null) {
134 throw new ServletException(resourceBundle
135 .getString("error.nomemento")
136 + ", URL=" + request.getRequestURI());
137 }
138 BridgeRequest bridgeRequest = memento.getBridgeRequest(id);
139 if (bridgeRequest == null) {
140 throw new ServletException(resourceBundle
141 .getString("error.nobridgerequest")
142 + ", URL=" + request.getRequestURI());
143 }
144 final PerPortletMemento perPortletMemento = memento
145 .getPerPortletMemento(bridgeRequest.getPortletId());
146 if (perPortletMemento == null) {
147 throw new ServletException(resourceBundle
148 .getString("error.noperportletmemento")
149 + ", URL=" + request.getRequestURI());
150 }
151
152
153 URI url = bridgeRequest.getUrl();
154
155
156
157 if (request.getQueryString() != null
158 && request.getQueryString().trim().length() > 0) {
159 try {
160
161
162 String urlAsString = url.toString();
163 url = new URI(urlAsString + ((url.getQuery() != null) ? '&' : '?') + request.getQueryString());
164 PseudoRenderResponse renderResponse = createRenderResponse(bridgeRequest);
165 bridgeRequest = memento.createBridgeRequest(renderResponse, DefaultIdGenerator.getInstance().nextId(), url);
166 } catch (URISyntaxException e) {
167 throw new ServletException(e.getMessage() + ", doGet(): URL="
168 + url + ", id=" + id + ", request URI="
169 + request.getRequestURI(), e);
170 }
171 }
172
173 log.debug("doGet(): URL=" + url + ", id=" + id + ", request URI="
174 + request.getRequestURI());
175
176 fetch(request, response, bridgeRequest, memento, perPortletMemento, url);
177
178 }
179
180 /***
181 * Create a PseudoRenderResponse
182 *
183 * @param bridgeRequest the bridgeRequest to use
184 * @return a render response
185 */
186 protected PseudoRenderResponse createRenderResponse(BridgeRequest bridgeRequest) {
187 PseudoRenderResponse renderResponse = new PseudoRenderResponse(
188 bridgeRequest
189 .getPortletId(),
190 bridgeRequest
191 .getPageUrl(),
192 bridgeRequest
193 .getId());
194 return renderResponse;
195 }
196
197 /***
198 * @param response
199 * @param bridgeRequest
200 * @param perPortletMemento
201 * @param url
202 * @throws ServletException
203 */
204 protected void fetch(final HttpServletRequest request,
205 final HttpServletResponse response,
206 final BridgeRequest bridgeRequest,
207 final PortletBridgeMemento memento,
208 final PerPortletMemento perPortletMemento, final URI url)
209 throws ServletException {
210 try {
211 GetMethod getMethod = new GetMethod(url.toString());
212
213 copyRequestHeaders(request, getMethod);
214 httpClientTemplate.service(getMethod, perPortletMemento,
215 new HttpClientCallback() {
216 public Object doInHttpClient(int statusCode,
217 HttpMethodBase method)
218 throws ResourceException, Throwable {
219 if (statusCode == HttpStatus.SC_OK) {
220
221
222 org.apache.commons.httpclient.URI effectiveUri = method.getURI();
223 BridgeRequest effectiveBridgeRequest = null;
224 if(!effectiveUri.toString().equals(url.toString())) {
225 PseudoRenderResponse renderResponse = createRenderResponse(bridgeRequest);
226 effectiveBridgeRequest = memento.createBridgeRequest(renderResponse, DefaultIdGenerator.getInstance().nextId(), new URI(effectiveUri.toString()));
227 } else {
228 effectiveBridgeRequest = bridgeRequest;
229 }
230 Header responseHeader = method
231 .getResponseHeader("Content-Type");
232 if (responseHeader != null
233 && responseHeader.getValue()
234 .startsWith("text/html")) {
235 String content = ResourceUtil.getString(
236 method.getResponseBodyAsStream(),
237 method.getResponseCharSet());
238
239
240 perPortletMemento.enqueueContent(
241 effectiveBridgeRequest.getId(),
242 new PortletBridgeContent(url,
243 "get", content));
244
245
246
247 response.sendRedirect(effectiveBridgeRequest
248 .getPageUrl());
249 } else if (responseHeader != null
250 && responseHeader.getValue()
251 .startsWith("text/javascript")) {
252
253 String content = ResourceUtil.getString(
254 method.getResponseBodyAsStream(),
255 method.getResponseCharSet());
256 BridgeFunctions bridge = bridgeFunctionsFactory
257 .createBridgeFunctions(
258 memento,
259 perPortletMemento,
260 getServletName(),
261 url,
262 new PseudoRenderRequest(request.getContextPath()),
263 createRenderResponse(effectiveBridgeRequest));
264 response.setContentType("text/javascript");
265 PrintWriter writer = response.getWriter();
266 writer.write(bridge.script(null, content));
267 writer.flush();
268 } else if (responseHeader != null
269 && responseHeader.getValue()
270 .startsWith("text/css")) {
271
272 String content = ResourceUtil.getString(
273 method.getResponseBodyAsStream(),
274 method.getResponseCharSet());
275 BridgeFunctions bridge = bridgeFunctionsFactory
276 .createBridgeFunctions(
277 memento,
278 perPortletMemento,
279 getServletName(),
280 url,
281 new PseudoRenderRequest(request.getContextPath()),
282 createRenderResponse(effectiveBridgeRequest));
283 response.setContentType("text/css");
284 PrintWriter writer = response.getWriter();
285 writer.write(bridge.style(null, content));
286 writer.flush();
287 } else {
288
289
290
291
292 Header header = method
293 .getResponseHeader("Content-Type");
294 response
295 .setContentType(((null == header
296 .getName() ? "" : header
297 .getName())
298 + ": " + (null == header
299 .getValue() ? "" : header
300 .getValue())));
301
302 log.trace("fetch(): returning URL=" + url
303 + ", as stream, content type="
304 + header);
305 ResourceUtil.copy(method
306 .getResponseBodyAsStream(),
307 response.getOutputStream(), 4096);
308 }
309 } else {
310
311
312 response.sendError(statusCode);
313 }
314 return null;
315 }
316 });
317 } catch (ResourceException resourceException) {
318 String format = MessageFormat.format(resourceBundle
319 .getString(resourceException.getMessage()),
320 resourceException.getArgs());
321 throw new ServletException(format, resourceException);
322 }
323 }
324
325 protected void doPost(final HttpServletRequest request,
326 final HttpServletResponse response) throws ServletException,
327 IOException {
328
329 final String id = portletBridgeService.getIdFromRequestUri(request
330 .getContextPath(), request.getRequestURI());
331
332 HttpSession session = request.getSession();
333 if (session == null) {
334 throw new ServletException(resourceBundle
335 .getString("error.nosession"));
336 }
337 final PortletBridgeMemento memento = (PortletBridgeMemento) session
338 .getAttribute(mementoSessionKey);
339 if (memento == null) {
340 throw new ServletException(resourceBundle
341 .getString("error.nomemento"));
342 }
343 final BridgeRequest bridgeRequest = memento.getBridgeRequest(id);
344 if (bridgeRequest == null) {
345 throw new ServletException(resourceBundle
346 .getString("error.nobridgerequest"));
347 }
348 final PerPortletMemento perPortletMemento = memento
349 .getPerPortletMemento(bridgeRequest.getPortletId());
350 if (perPortletMemento == null) {
351 throw new ServletException(resourceBundle
352 .getString("error.noperportletmemento"));
353 }
354
355
356 final URI url = bridgeRequest.getUrl();
357
358 log.debug("doPost(): URL=" + url);
359
360 try {
361 PostMethod postMethod = new PostMethod(url.toString());
362 copyRequestHeaders(request, postMethod);
363 postMethod.setRequestEntity(new InputStreamRequestEntity(request
364 .getInputStream()));
365 httpClientTemplate.service(postMethod, perPortletMemento,
366 new HttpClientCallback() {
367 public Object doInHttpClient(int statusCode,
368 HttpMethodBase method)
369 throws ResourceException, Throwable {
370 if (statusCode == HttpStatus.SC_OK) {
371
372
373 Header responseHeader = method
374 .getResponseHeader("Content-Type");
375 if (responseHeader != null
376 && responseHeader.getValue()
377 .startsWith("text/html")) {
378 String content = ResourceUtil.getString(
379 method.getResponseBodyAsStream(),
380 method.getResponseCharSet());
381
382
383 perPortletMemento.enqueueContent(
384 bridgeRequest.getId(),
385 new PortletBridgeContent(url,
386 "post", content));
387
388
389
390
391 log
392 .debug("doPost(): doing response.sendRedirect to URL="
393 + bridgeRequest
394 .getPageUrl());
395
396 response.sendRedirect(bridgeRequest
397 .getPageUrl());
398 } else {
399
400
401
402
403 response.setContentType(method
404 .getResponseHeader("Content-Type")
405 .toExternalForm());
406 ResourceUtil.copy(method
407 .getResponseBodyAsStream(),
408 response.getOutputStream(), 4096);
409 }
410 } else if (statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
411 Header locationHeader = method.getResponseHeader("Location");
412 if(locationHeader != null) {
413 URI redirectUrl = new URI(locationHeader.getValue().trim());
414 log.debug("redirecting to [" + redirectUrl + "]");
415 PseudoRenderResponse renderResponse = createRenderResponse(bridgeRequest);
416 BridgeRequest updatedBridgeRequest = memento.createBridgeRequest(renderResponse, DefaultIdGenerator.getInstance().nextId(), redirectUrl);
417 fetch(request, response, updatedBridgeRequest,
418 memento, perPortletMemento, redirectUrl);
419
420 } else {
421 throw new PortletBridgeException("error.missingLocation");
422 }
423 } else {
424
425
426 response.sendError(statusCode);
427 }
428 return null;
429 }
430 });
431 } catch (ResourceException resourceException) {
432 String format = MessageFormat.format(resourceBundle
433 .getString(resourceException.getMessage()),
434 resourceException.getArgs());
435 throw new ServletException(format, resourceException);
436 }
437 }
438
439 public void setPortletBridgeService(
440 PortletBridgeService portletBridgeService) {
441 this.portletBridgeService = portletBridgeService;
442 }
443
444 public void setHttpClientTemplate(HttpClientTemplate httpClientTemplate) {
445 this.httpClientTemplate = httpClientTemplate;
446 }
447
448 protected void copyRequestHeaders(HttpServletRequest request,
449 HttpMethodBase method) {
450
451 Enumeration properties = request.getHeaderNames();
452 while (properties.hasMoreElements()) {
453 String propertyName = (String) properties.nextElement();
454 String propertyNameToLower = propertyName.toLowerCase();
455 if (!ignoreRequestHeaders.contains(propertyNameToLower)
456 && !(method instanceof GetMethod && ignorePostToGetRequestHeaders.contains(propertyNameToLower))) {
457 Enumeration values = request.getHeaders(propertyName);
458 while (values.hasMoreElements()) {
459 String property = (String) values.nextElement();
460
461 method.setRequestHeader(propertyName, property);
462 }
463 }
464 }
465
466
467
468 try {
469 if (method.getURI().getHost().equals(request.getHeader("host"))) {
470 String cookie = request.getHeader("cookie");
471 if (cookie != null)
472 method.setRequestHeader("cookie", cookie);
473 }
474 } catch (URIException e) {
475 log.warn(e, e);
476 }
477
478 }
479
480 }