1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.web.portlet;
18
19 import java.io.IOException;
20 import java.security.Principal;
21 import java.util.Map;
22 import javax.portlet.ActionRequest;
23 import javax.portlet.ActionResponse;
24 import javax.portlet.EventRequest;
25 import javax.portlet.EventResponse;
26 import javax.portlet.PortletException;
27 import javax.portlet.PortletRequest;
28 import javax.portlet.PortletResponse;
29 import javax.portlet.RenderRequest;
30 import javax.portlet.RenderResponse;
31 import javax.portlet.ResourceRequest;
32 import javax.portlet.ResourceResponse;
33
34 import org.springframework.beans.BeanUtils;
35 import org.springframework.context.ApplicationContext;
36 import org.springframework.context.ApplicationContextException;
37 import org.springframework.context.ApplicationListener;
38 import org.springframework.context.ConfigurableApplicationContext;
39 import org.springframework.context.event.ContextRefreshedEvent;
40 import org.springframework.context.event.SourceFilteringListener;
41 import org.springframework.context.i18n.LocaleContext;
42 import org.springframework.context.i18n.LocaleContextHolder;
43 import org.springframework.context.i18n.SimpleLocaleContext;
44 import org.springframework.core.env.ConfigurableEnvironment;
45 import org.springframework.web.context.request.RequestAttributes;
46 import org.springframework.web.context.request.RequestContextHolder;
47 import org.springframework.web.context.request.ServletRequestAttributes;
48 import org.springframework.web.portlet.context.ConfigurablePortletApplicationContext;
49 import org.springframework.web.portlet.context.PortletApplicationContextUtils;
50 import org.springframework.web.portlet.context.PortletRequestAttributes;
51 import org.springframework.web.portlet.context.PortletRequestHandledEvent;
52 import org.springframework.web.portlet.context.StandardPortletEnvironment;
53 import org.springframework.web.portlet.context.XmlPortletApplicationContext;
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 public abstract class FrameworkPortlet extends GenericPortletBean
107 implements ApplicationListener<ContextRefreshedEvent> {
108
109
110
111
112
113 public static final Class<?> DEFAULT_CONTEXT_CLASS = XmlPortletApplicationContext.class;
114
115
116
117
118
119
120 public static final String DEFAULT_NAMESPACE_SUFFIX = "-portlet";
121
122
123
124
125
126 public static final String PORTLET_CONTEXT_PREFIX = FrameworkPortlet.class.getName() + ".CONTEXT.";
127
128
129
130
131
132 public static final String[] DEFAULT_USERINFO_ATTRIBUTE_NAMES = {"user.login.id", "user.name"};
133
134
135
136 private Class<?> contextClass = DEFAULT_CONTEXT_CLASS;
137
138
139 private String namespace;
140
141
142 private String contextConfigLocation;
143
144
145 private boolean publishContext = true;
146
147
148 private boolean publishEvents = true;
149
150
151 private boolean threadContextInheritable = false;
152
153
154 private String[] userinfoUsernameAttributes = DEFAULT_USERINFO_ATTRIBUTE_NAMES;
155
156
157 private ApplicationContext portletApplicationContext;
158
159
160 private boolean refreshEventReceived = false;
161
162
163
164
165
166
167
168
169 public void setContextClass(Class<?> contextClass) {
170 this.contextClass = contextClass;
171 }
172
173
174
175
176 public Class<?> getContextClass() {
177 return this.contextClass;
178 }
179
180
181
182
183
184 public void setNamespace(String namespace) {
185 this.namespace = namespace;
186 }
187
188
189
190
191
192 public String getNamespace() {
193 return (this.namespace != null) ? this.namespace : getPortletName() + DEFAULT_NAMESPACE_SUFFIX;
194 }
195
196
197
198
199
200
201 public void setContextConfigLocation(String contextConfigLocation) {
202 this.contextConfigLocation = contextConfigLocation;
203 }
204
205
206
207
208 public String getContextConfigLocation() {
209 return this.contextConfigLocation;
210 }
211
212
213
214
215
216
217
218 public void setPublishContext(boolean publishContext) {
219 this.publishContext = publishContext;
220 }
221
222
223
224
225
226
227
228 public void setPublishEvents(boolean publishEvents) {
229 this.publishEvents = publishEvents;
230 }
231
232
233
234
235
236
237
238
239
240
241
242
243
244 public void setThreadContextInheritable(boolean threadContextInheritable) {
245 this.threadContextInheritable = threadContextInheritable;
246 }
247
248
249
250
251
252
253 public void setUserinfoUsernameAttributes(String[] userinfoUsernameAttributes) {
254 this.userinfoUsernameAttributes = userinfoUsernameAttributes;
255 }
256
257
258
259
260
261
262 @Override
263 protected final void initPortletBean() throws PortletException {
264 getPortletContext().log("Initializing Spring FrameworkPortlet '" + getPortletName() + "'");
265 if (logger.isInfoEnabled()) {
266 logger.info("FrameworkPortlet '" + getPortletName() + "': initialization started");
267 }
268 long startTime = System.currentTimeMillis();
269
270 try {
271 this.portletApplicationContext = initPortletApplicationContext();
272 initFrameworkPortlet();
273 }
274 catch (PortletException ex) {
275 logger.error("Context initialization failed", ex);
276 throw ex;
277 }
278 catch (RuntimeException ex) {
279 logger.error("Context initialization failed", ex);
280 throw ex;
281 }
282
283 if (logger.isInfoEnabled()) {
284 long elapsedTime = System.currentTimeMillis() - startTime;
285 logger.info("FrameworkPortlet '" + getPortletName() + "': initialization completed in " + elapsedTime + " ms");
286 }
287 }
288
289
290
291
292
293
294
295 protected ApplicationContext initPortletApplicationContext() {
296 ApplicationContext parent = PortletApplicationContextUtils.getWebApplicationContext(getPortletContext());
297 ApplicationContext pac = createPortletApplicationContext(parent);
298
299 if (!this.refreshEventReceived) {
300
301
302 onRefresh(pac);
303 }
304
305 if (this.publishContext) {
306
307 String attName = getPortletContextAttributeName();
308 getPortletContext().setAttribute(attName, pac);
309 if (logger.isDebugEnabled()) {
310 logger.debug("Published ApplicationContext of portlet '" + getPortletName() +
311 "' as PortletContext attribute with name [" + attName + "]");
312 }
313 }
314 return pac;
315 }
316
317
318
319
320
321
322
323
324
325
326
327 protected ApplicationContext createPortletApplicationContext(ApplicationContext parent) {
328 Class<?> contextClass = getContextClass();
329 if (logger.isDebugEnabled()) {
330 logger.debug("Portlet with name '" + getPortletName() +
331 "' will try to create custom ApplicationContext context of class '" +
332 contextClass.getName() + "'" + ", using parent context [" + parent + "]");
333 }
334 if (!ConfigurablePortletApplicationContext.class.isAssignableFrom(contextClass)) {
335 throw new ApplicationContextException("Fatal initialization error in portlet with name '" + getPortletName() +
336 "': custom ApplicationContext class [" + contextClass.getName() +
337 "] is not of type ConfigurablePortletApplicationContext");
338 }
339 ConfigurablePortletApplicationContext pac =
340 (ConfigurablePortletApplicationContext) BeanUtils.instantiateClass(contextClass);
341
342
343 String portletContextName = getPortletContext().getPortletContextName();
344 if (portletContextName != null) {
345 pac.setId(ConfigurablePortletApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + portletContextName + "." + getPortletName());
346 }
347 else {
348 pac.setId(ConfigurablePortletApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + getPortletName());
349 }
350
351 pac.setEnvironment(getEnvironment());
352 pac.setParent(parent);
353 pac.setPortletContext(getPortletContext());
354 pac.setPortletConfig(getPortletConfig());
355 pac.setNamespace(getNamespace());
356 pac.setConfigLocation(getContextConfigLocation());
357 pac.addApplicationListener(new SourceFilteringListener(pac, this));
358
359
360
361
362 ConfigurableEnvironment env = pac.getEnvironment();
363 if (env instanceof StandardPortletEnvironment) {
364 ((StandardPortletEnvironment) env).initPropertySources(pac.getServletContext(), getPortletContext(), getPortletConfig());
365 }
366
367 postProcessPortletApplicationContext(pac);
368 pac.refresh();
369
370 return pac;
371 }
372
373
374
375
376
377
378
379
380
381
382 protected void postProcessPortletApplicationContext(ConfigurableApplicationContext pac) {
383 }
384
385
386
387
388
389
390
391 public String getPortletContextAttributeName() {
392 return PORTLET_CONTEXT_PREFIX + getPortletName();
393 }
394
395
396
397
398 public final ApplicationContext getPortletApplicationContext() {
399 return this.portletApplicationContext;
400 }
401
402
403
404
405
406
407
408
409
410 protected void initFrameworkPortlet() throws PortletException {
411 }
412
413
414
415
416
417
418
419 public void refresh() {
420 ApplicationContext pac = getPortletApplicationContext();
421 if (!(pac instanceof ConfigurableApplicationContext)) {
422 throw new IllegalStateException("Portlet ApplicationContext does not support refresh: " + pac);
423 }
424 ((ConfigurableApplicationContext) pac).refresh();
425 }
426
427
428
429
430
431
432
433
434
435 @Override
436 public void onApplicationEvent(ContextRefreshedEvent event) {
437 this.refreshEventReceived = true;
438 onRefresh(event.getApplicationContext());
439 }
440
441
442
443
444
445
446
447
448 protected void onRefresh(ApplicationContext context) {
449
450 }
451
452
453
454
455
456 @Override
457 protected String getTitle(RenderRequest renderRequest) {
458 try {
459 return super.getTitle(renderRequest);
460 }
461 catch (NullPointerException ex) {
462 return getPortletName();
463 }
464 }
465
466
467
468
469 @Override
470 public final void processAction(ActionRequest request, ActionResponse response)
471 throws PortletException, IOException {
472
473 processRequest(request, response);
474 }
475
476
477
478
479 @Override
480 protected final void doDispatch(RenderRequest request, RenderResponse response)
481 throws PortletException, IOException {
482
483 processRequest(request, response);
484 }
485
486 @Override
487 public void serveResource(ResourceRequest request, ResourceResponse response)
488 throws PortletException, IOException {
489
490 processRequest(request, response);
491 }
492
493 @Override
494 public void processEvent(EventRequest request, EventResponse response)
495 throws PortletException, IOException {
496
497 processRequest(request, response);
498 }
499
500
501
502
503
504
505
506
507 protected final void processRequest(PortletRequest request, PortletResponse response)
508 throws PortletException, IOException {
509
510 long startTime = System.currentTimeMillis();
511 Throwable failureCause = null;
512
513
514 LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
515 LocaleContextHolder.setLocaleContext(buildLocaleContext(request), this.threadContextInheritable);
516
517
518 RequestAttributes previousRequestAttributes = RequestContextHolder.getRequestAttributes();
519 PortletRequestAttributes requestAttributes = null;
520 if (previousRequestAttributes == null || previousRequestAttributes.getClass().equals(PortletRequestAttributes.class) ||
521 previousRequestAttributes.getClass().equals(ServletRequestAttributes.class)) {
522 requestAttributes = new PortletRequestAttributes(request, response);
523 RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
524 }
525
526 if (logger.isTraceEnabled()) {
527 logger.trace("Bound request context to thread: " + request);
528 }
529
530 try {
531 String phase = (String) request.getAttribute(PortletRequest.LIFECYCLE_PHASE);
532 if (PortletRequest.ACTION_PHASE.equals(phase)) {
533 doActionService((ActionRequest) request, (ActionResponse) response);
534 }
535 else if (PortletRequest.RENDER_PHASE.equals(phase)) {
536 doRenderService((RenderRequest) request, (RenderResponse) response);
537 }
538 else if (PortletRequest.RESOURCE_PHASE.equals(phase)) {
539 doResourceService((ResourceRequest) request, (ResourceResponse) response);
540 }
541 else if (PortletRequest.EVENT_PHASE.equals(phase)) {
542 doEventService((EventRequest) request, (EventResponse) response);
543 }
544 else {
545 throw new IllegalStateException("Invalid portlet request phase: " + phase);
546 }
547 }
548 catch (PortletException ex) {
549 failureCause = ex;
550 throw ex;
551 }
552 catch (IOException ex) {
553 failureCause = ex;
554 throw ex;
555 }
556 catch (Throwable ex) {
557 failureCause = ex;
558 throw new PortletException("Request processing failed", ex);
559 }
560
561 finally {
562
563 LocaleContextHolder.setLocaleContext(previousLocaleContext, this.threadContextInheritable);
564 if (requestAttributes != null) {
565 RequestContextHolder.setRequestAttributes(previousRequestAttributes, this.threadContextInheritable);
566 requestAttributes.requestCompleted();
567 }
568 if (logger.isTraceEnabled()) {
569 logger.trace("Cleared thread-bound resource request context: " + request);
570 }
571
572 if (failureCause != null) {
573 logger.error("Could not complete request", failureCause);
574 }
575 else {
576 logger.debug("Successfully completed request");
577 }
578 if (this.publishEvents) {
579
580 long processingTime = System.currentTimeMillis() - startTime;
581 this.portletApplicationContext.publishEvent(
582 new PortletRequestHandledEvent(this,
583 getPortletConfig().getPortletName(), request.getPortletMode().toString(),
584 (request instanceof ActionRequest ? "action" : "render"),
585 request.getRequestedSessionId(), getUsernameForRequest(request),
586 processingTime, failureCause));
587 }
588 }
589 }
590
591
592
593
594
595
596
597 protected LocaleContext buildLocaleContext(PortletRequest request) {
598 return new SimpleLocaleContext(request.getLocale());
599 }
600
601
602
603
604
605
606
607
608
609
610
611
612
613 protected String getUsernameForRequest(PortletRequest request) {
614
615 Principal userPrincipal = request.getUserPrincipal();
616 if (userPrincipal != null) {
617 return userPrincipal.getName();
618 }
619
620
621 String userName = request.getRemoteUser();
622 if (userName != null) {
623 return userName;
624 }
625
626
627 Map<?, ?> userInfo = (Map<?, ?>) request.getAttribute(PortletRequest.USER_INFO);
628 if (userInfo != null) {
629 for (int i = 0, n = this.userinfoUsernameAttributes.length; i < n; i++) {
630 userName = (String) userInfo.get(this.userinfoUsernameAttributes[i]);
631 if (userName != null) {
632 return userName;
633 }
634 }
635 }
636
637
638 return null;
639 }
640
641
642
643
644
645
646
647
648
649
650
651
652
653 protected abstract void doActionService(ActionRequest request, ActionResponse response)
654 throws Exception;
655
656
657
658
659
660
661
662
663
664
665
666
667 protected abstract void doRenderService(RenderRequest request, RenderResponse response)
668 throws Exception;
669
670
671
672
673
674
675
676
677
678
679
680
681 protected abstract void doResourceService(ResourceRequest request, ResourceResponse response)
682 throws Exception;
683
684
685
686
687
688
689
690
691
692
693
694
695 protected abstract void doEventService(EventRequest request, EventResponse response)
696 throws Exception;
697
698
699
700
701
702
703 @Override
704 public void destroy() {
705 getPortletContext().log("Destroying Spring FrameworkPortlet '" + getPortletName() + "'");
706 if (this.portletApplicationContext instanceof ConfigurableApplicationContext) {
707 ((ConfigurableApplicationContext) this.portletApplicationContext).close();
708 }
709 }
710
711 }