1
22
23 package com.liferay.portal.deploy.hot;
24
25 import com.liferay.portal.apache.bridges.struts.LiferayServletContextProvider;
26 import com.liferay.portal.kernel.deploy.hot.HotDeployEvent;
27 import com.liferay.portal.kernel.deploy.hot.HotDeployException;
28 import com.liferay.portal.kernel.deploy.hot.HotDeployListener;
29 import com.liferay.portal.kernel.job.Scheduler;
30 import com.liferay.portal.kernel.language.LanguageUtil;
31 import com.liferay.portal.kernel.lar.PortletDataHandler;
32 import com.liferay.portal.kernel.pop.MessageListener;
33 import com.liferay.portal.kernel.portlet.ConfigurationAction;
34 import com.liferay.portal.kernel.portlet.FriendlyURLMapper;
35 import com.liferay.portal.kernel.portlet.PortletLayoutListener;
36 import com.liferay.portal.kernel.search.Indexer;
37 import com.liferay.portal.kernel.servlet.PortletServlet;
38 import com.liferay.portal.kernel.servlet.ServletContextProvider;
39 import com.liferay.portal.kernel.servlet.URLEncoder;
40 import com.liferay.portal.kernel.util.ClassUtil;
41 import com.liferay.portal.kernel.util.GetterUtil;
42 import com.liferay.portal.kernel.util.HttpUtil;
43 import com.liferay.portal.kernel.util.LocaleUtil;
44 import com.liferay.portal.kernel.util.ObjectValuePair;
45 import com.liferay.portal.kernel.util.PropertiesUtil;
46 import com.liferay.portal.kernel.util.StringUtil;
47 import com.liferay.portal.kernel.util.Validator;
48 import com.liferay.portal.model.Portlet;
49 import com.liferay.portal.model.PortletApp;
50 import com.liferay.portal.model.PortletCategory;
51 import com.liferay.portal.model.PortletFilter;
52 import com.liferay.portal.model.PortletURLListener;
53 import com.liferay.portal.pop.POPServerUtil;
54 import com.liferay.portal.security.permission.ResourceActionsUtil;
55 import com.liferay.portal.service.PortletLocalServiceUtil;
56 import com.liferay.portal.service.ServiceComponentLocalServiceUtil;
57 import com.liferay.portal.util.Portal;
58 import com.liferay.portal.util.PortalInstances;
59 import com.liferay.portal.util.PropsValues;
60 import com.liferay.portal.util.WebAppPool;
61 import com.liferay.portal.util.WebKeys;
62 import com.liferay.portlet.CustomUserAttributes;
63 import com.liferay.portlet.PortletBag;
64 import com.liferay.portlet.PortletBagPool;
65 import com.liferay.portlet.PortletConfigFactory;
66 import com.liferay.portlet.PortletContextBag;
67 import com.liferay.portlet.PortletContextBagPool;
68 import com.liferay.portlet.PortletFilterFactory;
69 import com.liferay.portlet.PortletInstanceFactory;
70 import com.liferay.portlet.PortletPreferencesSerializer;
71 import com.liferay.portlet.PortletResourceBundles;
72 import com.liferay.portlet.PortletURLListenerFactory;
73 import com.liferay.portlet.social.model.SocialActivityInterpreter;
74 import com.liferay.portlet.social.model.impl.SocialActivityInterpreterImpl;
75 import com.liferay.portlet.social.service.SocialActivityInterpreterLocalServiceUtil;
76
77 import java.util.HashMap;
78 import java.util.HashSet;
79 import java.util.Iterator;
80 import java.util.List;
81 import java.util.Locale;
82 import java.util.Map;
83 import java.util.MissingResourceException;
84 import java.util.Properties;
85 import java.util.ResourceBundle;
86 import java.util.Set;
87
88 import javax.portlet.PortletConfig;
89 import javax.portlet.PortletContext;
90 import javax.portlet.PortletURLGenerationListener;
91 import javax.portlet.PreferencesValidator;
92
93 import javax.servlet.ServletContext;
94
95 import org.apache.commons.logging.Log;
96 import org.apache.commons.logging.LogFactory;
97 import org.apache.portals.bridges.struts.StrutsPortlet;
98
99
107 public class PortletHotDeployListener implements HotDeployListener {
108
109 public void invokeDeploy(HotDeployEvent event) throws HotDeployException {
110 String servletContextName = null;
111
112 try {
113
114
116 ServletContext ctx = event.getServletContext();
117
118 servletContextName = ctx.getServletContextName();
119
120 if (_log.isDebugEnabled()) {
121 _log.debug("Invoking deploy for " + servletContextName);
122 }
123
124
126 long[] companyIds = PortalInstances.getCompanyIds();
127
128
130 String[] xmls = new String[] {
131 HttpUtil.URLtoString(ctx.getResource(
132 "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_STANDARD)),
133 HttpUtil.URLtoString(ctx.getResource(
134 "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_CUSTOM)),
135 HttpUtil.URLtoString(ctx.getResource(
136 "/WEB-INF/liferay-portlet.xml")),
137 HttpUtil.URLtoString(ctx.getResource("/WEB-INF/web.xml"))
138 };
139
140 if (xmls[0] == null) {
141 return;
142 }
143
144 if (_log.isInfoEnabled()) {
145 _log.info("Registering portlets for " + servletContextName);
146 }
147
148 List<Portlet> portlets = PortletLocalServiceUtil.initWAR(
149 servletContextName, xmls, event.getPluginPackage());
150
151 if (_log.isInfoEnabled()) {
152 _log.info(
153 portlets.size() + " portlets for " + servletContextName +
154 " are ready for registration");
155 }
156
157
159 ClassLoader portletClassLoader = event.getContextClassLoader();
160
161 ctx.setAttribute(
162 PortletServlet.PORTLET_CLASS_LOADER, portletClassLoader);
163
164
166 boolean strutsBridges = false;
167
168 Iterator<Portlet> portletsItr = portlets.iterator();
169
170 while (portletsItr.hasNext()) {
171 Portlet portlet = portletsItr.next();
172
173 Class<?> portletClass = null;
174
175 try {
176 portletClass = portletClassLoader.loadClass(
177 portlet.getPortletClass());
178 }
179 catch (Exception e1) {
180 _log.error(e1, e1);
181
182 portletsItr.remove();
183
184 PortletLocalServiceUtil.destroyPortlet(portlet);
185
186 continue;
187 }
188
189 javax.portlet.Portlet portletInstance =
190 (javax.portlet.Portlet)portletClass.newInstance();
191
192 if (ClassUtil.isSubclass(portletClass,
193 StrutsPortlet.class.getName())) {
194
195 strutsBridges = true;
196 }
197
198 ConfigurationAction configurationActionInstance = null;
199
200 if (Validator.isNotNull(
201 portlet.getConfigurationActionClass())) {
202
203 configurationActionInstance =
204 (ConfigurationAction)portletClassLoader.loadClass(
205 portlet.getConfigurationActionClass()).
206 newInstance();
207 }
208
209 Indexer indexerInstance = null;
210
211 if (Validator.isNotNull(portlet.getIndexerClass())) {
212 indexerInstance = (Indexer)portletClassLoader.loadClass(
213 portlet.getIndexerClass()).newInstance();
214 }
215
216 Scheduler schedulerInstance = null;
217
218 if (Validator.isNotNull(portlet.getSchedulerClass())) {
219 schedulerInstance = (Scheduler)portletClassLoader.loadClass(
220 portlet.getSchedulerClass()).newInstance();
221
222 schedulerInstance.schedule();
223 }
224
225 FriendlyURLMapper friendlyURLMapperInstance = null;
226
227 if (Validator.isNotNull(portlet.getFriendlyURLMapperClass())) {
228 friendlyURLMapperInstance =
229 (FriendlyURLMapper)portletClassLoader.loadClass(
230 portlet.getFriendlyURLMapperClass()).newInstance();
231 }
232
233 URLEncoder urlEncoderInstance = null;
234
235 if (Validator.isNotNull(portlet.getURLEncoderClass())) {
236 urlEncoderInstance =
237 (URLEncoder)portletClassLoader.loadClass(
238 portlet.getURLEncoderClass()).newInstance();
239 }
240
241 PortletDataHandler portletDataHandlerInstance = null;
242
243 if (Validator.isNotNull(portlet.getPortletDataHandlerClass())) {
244 portletDataHandlerInstance =
245 (PortletDataHandler)portletClassLoader.loadClass(
246 portlet.getPortletDataHandlerClass()).newInstance();
247 }
248
249 PortletLayoutListener portletLayoutListenerInstance = null;
250
251 if (Validator.isNotNull(
252 portlet.getPortletLayoutListenerClass())) {
253
254 portletLayoutListenerInstance =
255 (PortletLayoutListener)portletClassLoader.loadClass(
256 portlet.getPortletLayoutListenerClass()).
257 newInstance();
258 }
259
260 MessageListener popMessageListenerInstance = null;
261
262 if (Validator.isNotNull(
263 portlet.getPopMessageListenerClass())) {
264
265 popMessageListenerInstance =
266 (MessageListener)portletClassLoader.loadClass(
267 portlet.getPopMessageListenerClass()).
268 newInstance();
269
270 POPServerUtil.addListener(popMessageListenerInstance);
271 }
272
273 SocialActivityInterpreter socialActivityInterpreterInstance =
274 null;
275
276 if (Validator.isNotNull(
277 portlet.getSocialActivityInterpreterClass())) {
278
279 socialActivityInterpreterInstance =
280 (SocialActivityInterpreter)
281 portletClassLoader.loadClass(
282 portlet.getSocialActivityInterpreterClass()).
283 newInstance();
284
285 socialActivityInterpreterInstance =
286 new SocialActivityInterpreterImpl(
287 socialActivityInterpreterInstance);
288
289 SocialActivityInterpreterLocalServiceUtil.
290 addActivityInterpreter(
291 socialActivityInterpreterInstance);
292 }
293
294 PreferencesValidator prefsValidatorInstance = null;
295
296 if (Validator.isNotNull(portlet.getPreferencesValidator())) {
297 prefsValidatorInstance =
298 (PreferencesValidator)portletClassLoader.loadClass(
299 portlet.getPreferencesValidator()).newInstance();
300
301 try {
302 if (PropsValues.PREFERENCE_VALIDATE_ON_STARTUP) {
303 prefsValidatorInstance.validate(
304 PortletPreferencesSerializer.fromDefaultXML(
305 portlet.getDefaultPreferences()));
306 }
307 }
308 catch (Exception e1) {
309 _log.warn(
310 "Portlet with the name " + portlet.getPortletId() +
311 " does not have valid default preferences");
312 }
313 }
314
315 Map<String, ResourceBundle> resourceBundles = null;
316
317 if (Validator.isNotNull(portlet.getResourceBundle())) {
318 resourceBundles = new HashMap();
319
320 initResourceBundle(
321 resourceBundles, portlet, portletClassLoader,
322 LocaleUtil.getDefault());
323
324 Iterator<String> supportLocalesItr =
325 portlet.getSupportedLocales().iterator();
326
327 while (supportLocalesItr.hasNext()) {
328 String supportedLocale = supportLocalesItr.next();
329
330 Locale locale = LocaleUtil.fromLanguageId(
331 supportedLocale);
332
333 initResourceBundle(
334 resourceBundles, portlet, portletClassLoader,
335 locale);
336 }
337 }
338
339 PortletBag portletBag = new PortletBag(
340 portlet.getPortletId(), ctx, portletInstance,
341 configurationActionInstance, indexerInstance,
342 schedulerInstance, friendlyURLMapperInstance,
343 urlEncoderInstance, portletDataHandlerInstance,
344 portletLayoutListenerInstance, popMessageListenerInstance,
345 socialActivityInterpreterInstance, prefsValidatorInstance,
346 resourceBundles);
347
348 PortletBagPool.put(portlet.getPortletId(), portletBag);
349
350 if (!portletsItr.hasNext()) {
351 initPortletApp(portlet, ctx, portletClassLoader);
352 }
353
354 try {
355 PortletInstanceFactory.create(portlet, ctx);
356 }
357 catch (Exception e1) {
358 _log.error(e1, e1);
359 }
360 }
361
362
364 if (!strutsBridges) {
365 strutsBridges = GetterUtil.getBoolean(
366 ctx.getInitParameter("struts-bridges-context-provider"));
367 }
368
369 if (strutsBridges) {
370 ctx.setAttribute(
371 ServletContextProvider.STRUTS_BRIDGES_CONTEXT_PROVIDER,
372 new LiferayServletContextProvider());
373 }
374
375
377 String xml = HttpUtil.URLtoString(ctx.getResource(
378 "/WEB-INF/liferay-display.xml"));
379
380 PortletCategory newPortletCategory =
381 PortletLocalServiceUtil.getWARDisplay(servletContextName, xml);
382
383 for (int i = 0; i < companyIds.length; i++) {
384 long companyId = companyIds[i];
385
386 PortletCategory portletCategory =
387 (PortletCategory)WebAppPool.get(
388 String.valueOf(companyId), WebKeys.PORTLET_CATEGORY);
389
390 if (portletCategory != null) {
391 portletCategory.merge(newPortletCategory);
392 }
393 else {
394 _log.error(
395 "Unable to register portlet for company " + companyId +
396 " because it does not exist");
397 }
398 }
399
400
402 String portletPropsName = ctx.getInitParameter(
403 "portlet_properties");
404
405 if (Validator.isNotNull(portletPropsName)) {
406 if (_log.isDebugEnabled()) {
407 _log.debug(
408 "Loading portlet properties " + portletPropsName);
409 }
410
411 Properties portletProps = new Properties();
412
413 PropertiesUtil.load(
414 portletProps,
415 StringUtil.read(portletClassLoader, portletPropsName));
416
417 if (_log.isDebugEnabled()) {
418 String portletPropsString = PropertiesUtil.list(
419 portletProps);
420
421 _log.debug(portletPropsString);
422 }
423
424 processProperties(
425 servletContextName, portletClassLoader, portletProps);
426 }
427
428
430 processServiceBuilder(ctx, portletClassLoader);
431
432
434 _vars.put(
435 servletContextName,
436 new ObjectValuePair<long[], List<Portlet>>(
437 companyIds, portlets));
438
439 if (_log.isInfoEnabled()) {
440 _log.info(
441 portlets.size() + " portlets for " + servletContextName +
442 " registered successfully");
443 }
444 }
445 catch (Exception e2) {
446 throw new HotDeployException(
447 "Error registering portlets for " + servletContextName, e2);
448 }
449 }
450
451 public void invokeUndeploy(HotDeployEvent event) throws HotDeployException {
452 String servletContextName = null;
453
454 try {
455 ServletContext ctx = event.getServletContext();
456
457 servletContextName = ctx.getServletContextName();
458
459 if (_log.isDebugEnabled()) {
460 _log.debug("Invoking undeploy for " + servletContextName);
461 }
462
463 ObjectValuePair<long[], List<Portlet>> ovp =
464 _vars.remove(servletContextName);
465
466 if (ovp == null) {
467 return;
468 }
469
470 long[] companyIds = ovp.getKey();
471 List<Portlet> portlets = ovp.getValue();
472
473 Set<String> portletIds = new HashSet<String>();
474
475 if (portlets != null) {
476 if (_log.isInfoEnabled()) {
477 _log.info(
478 "Unregistering portlets for " + servletContextName);
479 }
480
481 Iterator<Portlet> itr = portlets.iterator();
482
483 while (itr.hasNext()) {
484 Portlet portlet = itr.next();
485
486 Scheduler scheduler = portlet.getSchedulerInstance();
487
488 if (scheduler != null) {
489 scheduler.unschedule();
490 }
491
492 POPServerUtil.deleteListener(
493 portlet.getPopMessageListenerInstance());
494
495 SocialActivityInterpreterLocalServiceUtil.
496 deleteActivityInterpreter(
497 portlet.getSocialActivityInterpreterInstance());
498
499 PortletInstanceFactory.destroy(portlet);
500
501 portletIds.add(portlet.getPortletId());
502 }
503 }
504
505 if (portletIds.size() > 0) {
506 for (int i = 0; i < companyIds.length; i++) {
507 long companyId = companyIds[i];
508
509 PortletCategory portletCategory =
510 (PortletCategory)WebAppPool.get(
511 String.valueOf(companyId),
512 WebKeys.PORTLET_CATEGORY);
513
514 portletCategory.separate(portletIds);
515 }
516 }
517
518 PortletResourceBundles.remove(servletContextName);
519
520 if (_log.isInfoEnabled()) {
521 _log.info(
522 portlets.size() + " portlets for " + servletContextName +
523 " unregistered successfully");
524 }
525 }
526 catch (Exception e) {
527 throw new HotDeployException(
528 "Error unregistering portlets for " + servletContextName, e);
529 }
530 }
531
532 protected void initPortletApp(
533 Portlet portlet, ServletContext ctx, ClassLoader portletClassLoader)
534 throws Exception {
535
536 String servletContextName = ctx.getServletContextName();
537
538 PortletConfig portletConfig = PortletConfigFactory.create(
539 portlet, ctx);
540
541 PortletContext portletCtx = portletConfig.getPortletContext();
542
543 PortletContextBag portletContextBag = new PortletContextBag(
544 servletContextName);
545
546 PortletContextBagPool.put(servletContextName, portletContextBag);
547
548 PortletApp portletApp = portlet.getPortletApp();
549
550 Map<String, String> customUserAttributes =
551 portletApp.getCustomUserAttributes();
552
553 for (Map.Entry<String, String> entry :
554 customUserAttributes.entrySet()) {
555
556 String attrCustomClass = entry.getValue();
557
558 CustomUserAttributes customUserAttributesInstance =
559 (CustomUserAttributes)portletClassLoader.loadClass(
560 attrCustomClass).newInstance();
561
562 portletContextBag.getCustomUserAttributes().put(
563 attrCustomClass, customUserAttributesInstance);
564 }
565
566 Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
567
568 for (PortletFilter portletFilter : portletFilters) {
569 javax.portlet.filter.PortletFilter portletFilterInstance =
570 (javax.portlet.filter.PortletFilter)
571 portletClassLoader.loadClass(
572 portletFilter.getFilterClass()).newInstance();
573
574 portletContextBag.getPortletFilters().put(
575 portletFilter.getFilterName(), portletFilterInstance);
576
577 PortletFilterFactory.create(portletFilter, portletCtx);
578 }
579
580 Set<PortletURLListener> portletURLListeners =
581 portletApp.getPortletURLListeners();
582
583 for (PortletURLListener portletURLListener : portletURLListeners) {
584 PortletURLGenerationListener portletURLListenerInstance =
585 (PortletURLGenerationListener)portletClassLoader.loadClass(
586 portletURLListener.getListenerClass()).newInstance();
587
588 portletContextBag.getPortletURLListeners().put(
589 portletURLListener.getListenerClass(),
590 portletURLListenerInstance);
591
592 PortletURLListenerFactory.create(portletURLListener);
593 }
594 }
595
596 protected void initResourceBundle(
597 Map<String, ResourceBundle> resourceBundles, Portlet portlet,
598 ClassLoader portletClassLoader, Locale locale) {
599
600 try {
601 ResourceBundle resourceBundle = ResourceBundle.getBundle(
602 portlet.getResourceBundle(), locale, portletClassLoader);
603
604 resourceBundles.put(
605 LocaleUtil.toLanguageId(locale), resourceBundle);
606 }
607 catch (MissingResourceException mre) {
608 _log.warn(mre.getMessage());
609 }
610 }
611
612 protected void processProperties(
613 String servletContextName, ClassLoader portletClassLoader,
614 Properties portletProps)
615 throws Exception {
616
617 String languageBundleName = portletProps.getProperty("language.bundle");
618
619 if (Validator.isNotNull(languageBundleName)) {
620 Locale[] locales = LanguageUtil.getAvailableLocales();
621
622 for (int i = 0; i < locales.length; i++) {
623 ResourceBundle bundle = ResourceBundle.getBundle(
624 languageBundleName, locales[i], portletClassLoader);
625
626 PortletResourceBundles.put(
627 servletContextName, LocaleUtil.toLanguageId(locales[i]),
628 bundle);
629 }
630 }
631
632 String[] resourceActionConfigs = StringUtil.split(
633 portletProps.getProperty("resource.actions.configs"));
634
635 for (int i = 0; i < resourceActionConfigs.length; i++) {
636 ResourceActionsUtil.read(
637 servletContextName, portletClassLoader,
638 resourceActionConfigs[i]);
639 }
640 }
641
642 protected void processServiceBuilder(
643 ServletContext ctx, ClassLoader portletClassLoader)
644 throws Exception {
645
646 if (portletClassLoader.getResourceAsStream(
647 "portlet-service.properties") == null) {
648
649 return;
650 }
651
652 Properties serviceBuilderProps = new Properties();
653
654 PropertiesUtil.load(
655 serviceBuilderProps,
656 StringUtil.read(portletClassLoader, "portlet-service.properties"));
657
658 String buildNamespace = GetterUtil.getString(
659 serviceBuilderProps.getProperty("build.namespace"));
660 long buildNumber = GetterUtil.getLong(
661 serviceBuilderProps.getProperty("build.number"));
662 long buildDate = GetterUtil.getLong(
663 serviceBuilderProps.getProperty("build.date"));
664
665 if (_log.isDebugEnabled()) {
666 _log.debug("Build namespace " + buildNamespace);
667 _log.debug("Build number " + buildNumber);
668 _log.debug("Build date " + buildDate);
669 }
670
671 ServiceComponentLocalServiceUtil.updateServiceComponent(
672 ctx, portletClassLoader, buildNamespace, buildNumber, buildDate);
673 }
674
675 private static Log _log = LogFactory.getLog(PortletHotDeployListener.class);
676
677 private static Map<String, ObjectValuePair<long[], List<Portlet>>> _vars =
678 new HashMap<String, ObjectValuePair<long[], List<Portlet>>>();
679
680 }