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