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