001
014
015 package com.liferay.portal.deploy.hot;
016
017 import com.liferay.portal.apache.bridges.struts.LiferayServletContextProvider;
018 import com.liferay.portal.kernel.configuration.Configuration;
019 import com.liferay.portal.kernel.configuration.ConfigurationFactoryUtil;
020 import com.liferay.portal.kernel.deploy.hot.BaseHotDeployListener;
021 import com.liferay.portal.kernel.deploy.hot.HotDeployEvent;
022 import com.liferay.portal.kernel.deploy.hot.HotDeployException;
023 import com.liferay.portal.kernel.javadoc.JavadocManagerUtil;
024 import com.liferay.portal.kernel.language.LanguageUtil;
025 import com.liferay.portal.kernel.log.Log;
026 import com.liferay.portal.kernel.log.LogFactoryUtil;
027 import com.liferay.portal.kernel.portlet.PortletBag;
028 import com.liferay.portal.kernel.portlet.PortletBagPool;
029 import com.liferay.portal.kernel.servlet.DirectServletRegistryUtil;
030 import com.liferay.portal.kernel.servlet.FileTimestampUtil;
031 import com.liferay.portal.kernel.servlet.PortletServlet;
032 import com.liferay.portal.kernel.servlet.ServletContextPool;
033 import com.liferay.portal.kernel.servlet.ServletContextProvider;
034 import com.liferay.portal.kernel.util.ClassUtil;
035 import com.liferay.portal.kernel.util.GetterUtil;
036 import com.liferay.portal.kernel.util.HttpUtil;
037 import com.liferay.portal.kernel.util.InfrastructureUtil;
038 import com.liferay.portal.kernel.util.LocaleUtil;
039 import com.liferay.portal.kernel.util.PropsKeys;
040 import com.liferay.portal.kernel.util.ResourceBundleUtil;
041 import com.liferay.portal.kernel.util.ServerDetector;
042 import com.liferay.portal.kernel.util.StringUtil;
043 import com.liferay.portal.kernel.util.Validator;
044 import com.liferay.portal.kernel.util.WebKeys;
045 import com.liferay.portal.language.LanguageResources;
046 import com.liferay.portal.model.Portlet;
047 import com.liferay.portal.model.PortletApp;
048 import com.liferay.portal.model.PortletCategory;
049 import com.liferay.portal.model.PortletFilter;
050 import com.liferay.portal.model.PortletURLListener;
051 import com.liferay.portal.security.permission.ResourceActionsUtil;
052 import com.liferay.portal.service.PortletLocalServiceUtil;
053 import com.liferay.portal.service.ResourceActionLocalServiceUtil;
054 import com.liferay.portal.util.Portal;
055 import com.liferay.portal.util.PortalInstances;
056 import com.liferay.portal.util.WebAppPool;
057 import com.liferay.portlet.CustomUserAttributes;
058 import com.liferay.portlet.InvokerPortlet;
059 import com.liferay.portlet.PortletContextBag;
060 import com.liferay.portlet.PortletContextBagPool;
061 import com.liferay.portlet.PortletFilterFactory;
062 import com.liferay.portlet.PortletInstanceFactoryUtil;
063 import com.liferay.portlet.PortletURLListenerFactory;
064 import com.liferay.registry.Registry;
065 import com.liferay.registry.RegistryUtil;
066 import com.liferay.registry.ServiceRegistration;
067 import com.liferay.registry.collections.ServiceRegistrationMap;
068 import com.liferay.registry.collections.ServiceRegistrationMapImpl;
069 import com.liferay.util.bridges.php.PHPPortlet;
070
071 import java.util.HashMap;
072 import java.util.HashSet;
073 import java.util.Iterator;
074 import java.util.List;
075 import java.util.Locale;
076 import java.util.Map;
077 import java.util.MissingResourceException;
078 import java.util.Properties;
079 import java.util.ResourceBundle;
080 import java.util.Set;
081
082 import javax.naming.Context;
083 import javax.naming.InitialContext;
084 import javax.naming.NamingException;
085
086 import javax.portlet.PortletURLGenerationListener;
087
088 import javax.servlet.ServletContext;
089
090 import javax.sql.DataSource;
091
092 import org.apache.portals.bridges.struts.StrutsPortlet;
093
094
100 public class PortletHotDeployListener extends BaseHotDeployListener {
101
102 @Override
103 public void invokeDeploy(HotDeployEvent hotDeployEvent)
104 throws HotDeployException {
105
106 try {
107 doInvokeDeploy(hotDeployEvent);
108 }
109 catch (Throwable t) {
110 throwHotDeployException(
111 hotDeployEvent, "Error registering portlets for ", t);
112 }
113 }
114
115 @Override
116 public void invokeUndeploy(HotDeployEvent hotDeployEvent)
117 throws HotDeployException {
118
119 try {
120 doInvokeUndeploy(hotDeployEvent);
121 }
122 catch (Throwable t) {
123 throwHotDeployException(
124 hotDeployEvent, "Error unregistering portlets for ", t);
125 }
126 }
127
128 protected void bindDataSource(String servletContextName) throws Exception {
129 if (ServerDetector.isGlassfish() || ServerDetector.isJOnAS()) {
130 return;
131 }
132
133 if (_log.isDebugEnabled()) {
134 _log.debug("Dynamically binding the Liferay data source");
135 }
136
137 DataSource dataSource = InfrastructureUtil.getDataSource();
138
139 if (dataSource == null) {
140 if (_log.isDebugEnabled()) {
141 _log.debug(
142 "Abort dynamically binding the Liferay data source " +
143 "because it is not available");
144 }
145
146 return;
147 }
148
149 Context context = new InitialContext();
150
151 try {
152 try {
153 context.lookup(_JNDI_JDBC);
154 }
155 catch (NamingException ne) {
156 context.createSubcontext(_JNDI_JDBC);
157 }
158
159 try {
160 context.lookup(_JNDI_JDBC_LIFERAY_POOL);
161 }
162 catch (NamingException ne) {
163 context.bind(_JNDI_JDBC_LIFERAY_POOL, dataSource);
164 }
165
166 _dataSourceBindStates.put(servletContextName, true);
167 }
168 catch (Exception e) {
169 if (_log.isWarnEnabled()) {
170 _log.warn(
171 "Unable to dynamically bind the Liferay data source: " +
172 e.getMessage());
173 }
174 }
175 }
176
177 protected void checkResourceBundles(
178 ClassLoader classLoader, Portlet portlet) {
179
180 if (Validator.isNull(portlet.getResourceBundle())) {
181 return;
182 }
183
184 Registry registry = RegistryUtil.getRegistry();
185
186 for (Locale locale : LanguageUtil.getAvailableLocales()) {
187 try {
188 ResourceBundle resourceBundle = ResourceBundleUtil.getBundle(
189 portlet.getResourceBundle(), locale, classLoader);
190
191 Map<String, Object> properties = new HashMap<>();
192
193 properties.put("language.id", LocaleUtil.toLanguageId(locale));
194 properties.put("javax.portlet.name", portlet.getPortletId());
195
196 ServiceRegistration<ResourceBundle> serviceRegistration =
197 registry.registerService(
198 ResourceBundle.class, resourceBundle, properties);
199
200 _serviceRegistrations.put(resourceBundle, serviceRegistration);
201 }
202 catch (MissingResourceException mre) {
203 if (_log.isInfoEnabled()) {
204 _log.info(
205 "Portlet " + portlet.getPortletName() + " does " +
206 "not have translations for available locale " +
207 locale);
208 }
209 }
210
211 Map<String, Object> properties = new HashMap<>();
212
213 properties.put("language.id", LocaleUtil.toLanguageId(locale));
214 properties.put("javax.portlet.name", portlet.getPortletId());
215 properties.put("service.ranking", Integer.MIN_VALUE);
216
217 ResourceBundle resourceBundle = LanguageResources.getResourceBundle(
218 locale);
219
220 ServiceRegistration<ResourceBundle> serviceRegistration =
221 registry.registerService(
222 ResourceBundle.class, resourceBundle, properties);
223
224 _serviceRegistrations.put(resourceBundle, serviceRegistration);
225 }
226 }
227
228 protected void destroyPortlet(Portlet portlet, Set<String> portletIds)
229 throws Exception {
230
231 PortletApp portletApp = portlet.getPortletApp();
232
233 Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
234
235 for (PortletFilter portletFilter : portletFilters) {
236 PortletFilterFactory.destroy(portletFilter);
237 }
238
239 Set<PortletURLListener> portletURLListeners =
240 portletApp.getPortletURLListeners();
241
242 for (PortletURLListener portletURLListener : portletURLListeners) {
243 PortletURLListenerFactory.destroy(portletURLListener);
244 }
245
246 PortletInstanceFactoryUtil.destroy(portlet);
247
248 portletIds.add(portlet.getPortletId());
249
250 for (ResourceBundle resourceBundle : _serviceRegistrations.keySet()) {
251 ServiceRegistration<ResourceBundle> serviceRegistration =
252 _serviceRegistrations.remove(resourceBundle);
253
254 if (serviceRegistration != null) {
255 serviceRegistration.unregister();
256 }
257 }
258 }
259
260 protected void doInvokeDeploy(HotDeployEvent hotDeployEvent)
261 throws Exception {
262
263 ServletContext servletContext = hotDeployEvent.getServletContext();
264
265 String servletContextName = servletContext.getServletContextName();
266
267 if (_log.isDebugEnabled()) {
268 _log.debug("Invoking deploy for " + servletContextName);
269 }
270
271 String[] xmls = new String[] {
272 HttpUtil.URLtoString(
273 servletContext.getResource(
274 "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_STANDARD)),
275 HttpUtil.URLtoString(
276 servletContext.getResource(
277 "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_CUSTOM)),
278 HttpUtil.URLtoString(
279 servletContext.getResource("/WEB-INF/liferay-portlet.xml")),
280 HttpUtil.URLtoString(servletContext.getResource("/WEB-INF/web.xml"))
281 };
282
283 if ((xmls[0] == null) && (xmls[1] == null)) {
284 return;
285 }
286
287 if (_log.isInfoEnabled()) {
288 _log.info("Registering portlets for " + servletContextName);
289 }
290
291 PortletContextBag portletContextBag = new PortletContextBag(
292 servletContextName);
293
294 PortletContextBagPool.put(servletContextName, portletContextBag);
295
296 List<Portlet> portlets = PortletLocalServiceUtil.initWAR(
297 servletContextName, servletContext, xmls,
298 hotDeployEvent.getPluginPackage());
299
300 boolean portletAppInitialized = false;
301
302 boolean phpPortlet = false;
303 boolean strutsBridges = false;
304
305 ClassLoader classLoader = hotDeployEvent.getContextClassLoader();
306
307 Iterator<Portlet> itr = portlets.iterator();
308
309 while (itr.hasNext()) {
310 Portlet portlet = itr.next();
311
312 PortletBag portletBag = PortletBagPool.get(
313 portlet.getRootPortletId());
314
315 if (!portletAppInitialized) {
316 initPortletApp(
317 servletContextName, servletContext, classLoader, portlet);
318
319 portletAppInitialized = true;
320 }
321
322 javax.portlet.Portlet portletInstance =
323 portletBag.getPortletInstance();
324
325 if (ClassUtil.isSubclass(
326 portletInstance.getClass(), PHPPortlet.class.getName())) {
327
328 phpPortlet = true;
329 }
330
331 if (ClassUtil.isSubclass(
332 portletInstance.getClass(),
333 StrutsPortlet.class.getName())) {
334
335 strutsBridges = true;
336 }
337 }
338
339 if (phpPortlet) {
340 bindDataSource(servletContextName);
341 }
342
343 if (!strutsBridges) {
344 strutsBridges = GetterUtil.getBoolean(
345 servletContext.getInitParameter(
346 "struts-bridges-context-provider"));
347 }
348
349 if (strutsBridges) {
350 servletContext.setAttribute(
351 ServletContextProvider.STRUTS_BRIDGES_CONTEXT_PROVIDER,
352 new LiferayServletContextProvider());
353 }
354
355 String xml = HttpUtil.URLtoString(
356 servletContext.getResource("/WEB-INF/liferay-display.xml"));
357
358 PortletCategory newPortletCategory =
359 PortletLocalServiceUtil.getWARDisplay(servletContextName, xml);
360
361 long[] companyIds = PortalInstances.getCompanyIds();
362
363 for (long companyId : companyIds) {
364 PortletCategory portletCategory = (PortletCategory)WebAppPool.get(
365 companyId, WebKeys.PORTLET_CATEGORY);
366
367 if (portletCategory != null) {
368 portletCategory.merge(newPortletCategory);
369 }
370 else {
371 _log.error(
372 "Unable to register portlet for company " + companyId +
373 " because it does not exist");
374 }
375 }
376
377 processPortletProperties(servletContextName, classLoader);
378
379 for (Portlet portlet : portlets) {
380 List<String> modelNames =
381 ResourceActionsUtil.getPortletModelResources(
382 portlet.getPortletId());
383
384 List<String> portletActions =
385 ResourceActionsUtil.getPortletResourceActions(
386 portlet.getPortletId());
387
388 ResourceActionLocalServiceUtil.checkResourceActions(
389 portlet.getPortletId(), portletActions);
390
391 checkResourceBundles(classLoader, portlet);
392
393 for (String modelName : modelNames) {
394 List<String> modelActions =
395 ResourceActionsUtil.getModelResourceActions(modelName);
396
397 ResourceActionLocalServiceUtil.checkResourceActions(
398 modelName, modelActions);
399 }
400
401 for (long companyId : companyIds) {
402 Portlet curPortlet = PortletLocalServiceUtil.getPortletById(
403 companyId, portlet.getPortletId());
404
405 PortletLocalServiceUtil.checkPortlet(curPortlet);
406 }
407 }
408
409 for (Portlet portlet : portlets) {
410 boolean ready = GetterUtil.getBoolean(
411 servletContext.getInitParameter("portlets-ready-by-default"),
412 true);
413
414 portlet.setReady(ready);
415 }
416
417 registerClpMessageListeners(servletContext, classLoader);
418
419 JavadocManagerUtil.load(servletContextName, classLoader);
420
421 DirectServletRegistryUtil.clearServlets();
422 FileTimestampUtil.reset();
423
424 _portlets.put(servletContextName, portlets);
425
426 servletContext.setAttribute(WebKeys.PLUGIN_PORTLETS, portlets);
427
428 if (_log.isInfoEnabled()) {
429 if (portlets.size() == 1) {
430 _log.info(
431 "1 portlet for " + servletContextName +
432 " is available for use");
433 }
434 else {
435 _log.info(
436 portlets.size() + " portlets for " + servletContextName +
437 " are available for use");
438 }
439 }
440 }
441
442 protected void doInvokeUndeploy(HotDeployEvent hotDeployEvent)
443 throws Exception {
444
445 ServletContext servletContext = hotDeployEvent.getServletContext();
446
447 String servletContextName = servletContext.getServletContextName();
448
449 if (_log.isDebugEnabled()) {
450 _log.debug("Invoking undeploy for " + servletContextName);
451 }
452
453 List<Portlet> portlets = _portlets.remove(servletContextName);
454
455 if (portlets == null) {
456 return;
457 }
458
459 Set<String> portletIds = new HashSet<>();
460
461 if (portlets != null) {
462 if (_log.isInfoEnabled()) {
463 _log.info("Unregistering portlets for " + servletContextName);
464 }
465
466 for (Portlet portlet : portlets) {
467 destroyPortlet(portlet, portletIds);
468 }
469 }
470
471 ServletContextPool.remove(servletContextName);
472
473 if (!portletIds.isEmpty()) {
474 long[] companyIds = PortalInstances.getCompanyIds();
475
476 for (long companyId : companyIds) {
477 PortletCategory portletCategory =
478 (PortletCategory)WebAppPool.get(
479 companyId, WebKeys.PORTLET_CATEGORY);
480
481 portletCategory.separate(portletIds);
482 }
483 }
484
485 PortletContextBagPool.remove(servletContextName);
486
487 unbindDataSource(servletContextName);
488
489 unregisterClpMessageListeners(servletContext);
490
491 JavadocManagerUtil.unload(servletContextName);
492
493 DirectServletRegistryUtil.clearServlets();
494
495 if (_log.isInfoEnabled()) {
496 if (portlets.size() == 1) {
497 _log.info(
498 "1 portlet for " + servletContextName +
499 " was unregistered");
500 }
501 else {
502 _log.info(
503 portlets.size() + " portlets for " + servletContextName +
504 " were unregistered");
505 }
506 }
507 }
508
509 protected void initPortletApp(
510 String servletContextName, ServletContext servletContext,
511 ClassLoader classLoader, Portlet portlet)
512 throws Exception {
513
514 PortletContextBag portletContextBag = PortletContextBagPool.get(
515 servletContextName);
516
517 PortletApp portletApp = portlet.getPortletApp();
518
519 servletContext.setAttribute(PortletServlet.PORTLET_APP, portletApp);
520
521 Map<String, String> customUserAttributes =
522 portletApp.getCustomUserAttributes();
523
524 for (Map.Entry<String, String> entry :
525 customUserAttributes.entrySet()) {
526
527 String attrCustomClass = entry.getValue();
528
529 Class<?> clazz = classLoader.loadClass(attrCustomClass);
530
531 CustomUserAttributes customUserAttributesInstance =
532 (CustomUserAttributes)clazz.newInstance();
533
534 portletContextBag.getCustomUserAttributes().put(
535 attrCustomClass, customUserAttributesInstance);
536 }
537
538 Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
539
540 for (PortletFilter portletFilter : portletFilters) {
541 javax.portlet.filter.PortletFilter portletFilterInstance =
542 (javax.portlet.filter.PortletFilter)newInstance(
543 classLoader,
544 new Class<?>[] {
545 javax.portlet.filter.ActionFilter.class,
546 javax.portlet.filter.EventFilter.class,
547 javax.portlet.filter.PortletFilter.class,
548 javax.portlet.filter.RenderFilter.class,
549 javax.portlet.filter.ResourceFilter.class
550 },
551 portletFilter.getFilterClass());
552
553 portletContextBag.getPortletFilters().put(
554 portletFilter.getFilterName(), portletFilterInstance);
555 }
556
557 InvokerPortlet invokerPortlet = PortletInstanceFactoryUtil.create(
558 portlet, servletContext);
559
560 invokerPortlet.setPortletFilters();
561
562 Set<PortletURLListener> portletURLListeners =
563 portletApp.getPortletURLListeners();
564
565 for (PortletURLListener portletURLListener : portletURLListeners) {
566 PortletURLGenerationListener portletURLListenerInstance =
567 (PortletURLGenerationListener)newInstance(
568 classLoader, PortletURLGenerationListener.class,
569 portletURLListener.getListenerClass());
570
571 portletContextBag.getPortletURLListeners().put(
572 portletURLListener.getListenerClass(),
573 portletURLListenerInstance);
574
575 PortletURLListenerFactory.create(portletURLListener);
576 }
577 }
578
579 protected void processPortletProperties(
580 String servletContextName, ClassLoader classLoader)
581 throws Exception {
582
583 Configuration portletPropertiesConfiguration = null;
584
585 try {
586 portletPropertiesConfiguration =
587 ConfigurationFactoryUtil.getConfiguration(
588 classLoader, "portlet");
589 }
590 catch (Exception e) {
591 if (_log.isDebugEnabled()) {
592 _log.debug("Unable to read portlet.properties");
593 }
594
595 return;
596 }
597
598 Properties portletProperties =
599 portletPropertiesConfiguration.getProperties();
600
601 if (portletProperties.isEmpty()) {
602 return;
603 }
604
605 String[] resourceActionConfigs = StringUtil.split(
606 portletProperties.getProperty(PropsKeys.RESOURCE_ACTIONS_CONFIGS));
607
608 for (String resourceActionConfig : resourceActionConfigs) {
609 ResourceActionsUtil.read(
610 servletContextName, classLoader, resourceActionConfig);
611 }
612 }
613
614 protected void unbindDataSource(String servletContextName) {
615 Boolean dataSourceBindState = _dataSourceBindStates.remove(
616 servletContextName);
617
618 if (dataSourceBindState == null) {
619 return;
620 }
621
622 try {
623 if (_log.isDebugEnabled()) {
624 _log.debug("Dynamically unbinding the Liferay data source");
625 }
626
627 Context context = new InitialContext();
628
629 try {
630 context.lookup(_JNDI_JDBC_LIFERAY_POOL);
631
632 context.unbind(_JNDI_JDBC_LIFERAY_POOL);
633 }
634 catch (NamingException ne) {
635 }
636
637 try {
638 context.lookup(_JNDI_JDBC);
639
640 context.destroySubcontext(_JNDI_JDBC);
641 }
642 catch (NamingException ne) {
643 }
644 }
645 catch (Exception e) {
646 if (_log.isWarnEnabled()) {
647 _log.warn(
648 "Unable to dynamically unbind the Liferay data source: " +
649 e.getMessage());
650 }
651 }
652 }
653
654 private static final String _JNDI_JDBC = "java_liferay:jdbc";
655
656 private static final String _JNDI_JDBC_LIFERAY_POOL =
657 _JNDI_JDBC + "/LiferayPool";
658
659 private static final Log _log = LogFactoryUtil.getLog(
660 PortletHotDeployListener.class);
661
662 private static final Map<String, Boolean> _dataSourceBindStates =
663 new HashMap<>();
664 private static final Map<String, List<Portlet>> _portlets = new HashMap<>();
665
666 private final ServiceRegistrationMap<ResourceBundle>
667 _serviceRegistrations = new ServiceRegistrationMapImpl<>();
668
669 }