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.scheduler.SchedulerEngineHelperUtil;
029 import com.liferay.portal.kernel.scheduler.SchedulerEntry;
030 import com.liferay.portal.kernel.scheduler.StorageType;
031 import com.liferay.portal.kernel.servlet.DirectServletRegistryUtil;
032 import com.liferay.portal.kernel.servlet.FileTimestampUtil;
033 import com.liferay.portal.kernel.servlet.PortletServlet;
034 import com.liferay.portal.kernel.servlet.ServletContextPool;
035 import com.liferay.portal.kernel.servlet.ServletContextProvider;
036 import com.liferay.portal.kernel.settings.SettingsFactoryUtil;
037 import com.liferay.portal.kernel.util.ClassUtil;
038 import com.liferay.portal.kernel.util.GetterUtil;
039 import com.liferay.portal.kernel.util.HttpUtil;
040 import com.liferay.portal.kernel.util.InfrastructureUtil;
041 import com.liferay.portal.kernel.util.LocaleUtil;
042 import com.liferay.portal.kernel.util.PropsKeys;
043 import com.liferay.portal.kernel.util.ServerDetector;
044 import com.liferay.portal.kernel.util.StringUtil;
045 import com.liferay.portal.kernel.util.Validator;
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.PropsValues;
057 import com.liferay.portal.util.WebAppPool;
058 import com.liferay.portal.util.WebKeys;
059 import com.liferay.portlet.CustomUserAttributes;
060 import com.liferay.portlet.InvokerPortlet;
061 import com.liferay.portlet.PortletBagFactory;
062 import com.liferay.portlet.PortletContextBag;
063 import com.liferay.portlet.PortletContextBagPool;
064 import com.liferay.portlet.PortletFilterFactory;
065 import com.liferay.portlet.PortletInstanceFactoryUtil;
066 import com.liferay.portlet.PortletResourceBundles;
067 import com.liferay.portlet.PortletURLListenerFactory;
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 destroyPortlet(Portlet portlet, Set<String> portletIds)
176 throws Exception {
177
178 PortletApp portletApp = portlet.getPortletApp();
179
180 Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
181
182 for (PortletFilter portletFilter : portletFilters) {
183 PortletFilterFactory.destroy(portletFilter);
184 }
185
186 Set<PortletURLListener> portletURLListeners =
187 portletApp.getPortletURLListeners();
188
189 for (PortletURLListener portletURLListener : portletURLListeners) {
190 PortletURLListenerFactory.destroy(portletURLListener);
191 }
192
193 if (PropsValues.SCHEDULER_ENABLED) {
194 List<SchedulerEntry> schedulerEntries =
195 portlet.getSchedulerEntries();
196
197 if ((schedulerEntries != null) && !schedulerEntries.isEmpty()) {
198 for (SchedulerEntry schedulerEntry : schedulerEntries) {
199 SchedulerEngineHelperUtil.unschedule(
200 schedulerEntry, StorageType.MEMORY_CLUSTERED);
201 }
202 }
203 }
204
205 PortletInstanceFactoryUtil.destroy(portlet);
206
207 portletIds.add(portlet.getPortletId());
208 }
209
210 protected void doInvokeDeploy(HotDeployEvent hotDeployEvent)
211 throws Exception {
212
213 ServletContext servletContext = hotDeployEvent.getServletContext();
214
215 String servletContextName = servletContext.getServletContextName();
216
217 if (_log.isDebugEnabled()) {
218 _log.debug("Invoking deploy for " + servletContextName);
219 }
220
221 String[] xmls = new String[] {
222 HttpUtil.URLtoString(
223 servletContext.getResource(
224 "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_STANDARD)),
225 HttpUtil.URLtoString(
226 servletContext.getResource(
227 "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_CUSTOM)),
228 HttpUtil.URLtoString(
229 servletContext.getResource("/WEB-INF/liferay-portlet.xml")),
230 HttpUtil.URLtoString(servletContext.getResource("/WEB-INF/web.xml"))
231 };
232
233 if ((xmls[0] == null) && (xmls[1] == null)) {
234 return;
235 }
236
237 if (_log.isInfoEnabled()) {
238 _log.info("Registering portlets for " + servletContextName);
239 }
240
241 List<Portlet> portlets = PortletLocalServiceUtil.initWAR(
242 servletContextName, servletContext, xmls,
243 hotDeployEvent.getPluginPackage());
244
245 boolean portletAppInitialized = false;
246
247 boolean phpPortlet = false;
248 boolean strutsBridges = false;
249
250 PortletBagFactory portletBagFactory = new PortletBagFactory();
251
252 ClassLoader classLoader = hotDeployEvent.getContextClassLoader();
253
254 portletBagFactory.setClassLoader(classLoader);
255
256 portletBagFactory.setServletContext(servletContext);
257 portletBagFactory.setWARFile(true);
258
259 Iterator<Portlet> itr = portlets.iterator();
260
261 while (itr.hasNext()) {
262 Portlet portlet = itr.next();
263
264 PortletBag portletBag = portletBagFactory.create(portlet);
265
266 if (portletBag == null) {
267 itr.remove();
268 }
269 else {
270 if (!portletAppInitialized) {
271 initPortletApp(
272 servletContextName, servletContext, classLoader,
273 portlet);
274
275 portletAppInitialized = true;
276 }
277
278 javax.portlet.Portlet portletInstance =
279 portletBag.getPortletInstance();
280
281 if (ClassUtil.isSubclass(
282 portletInstance.getClass(),
283 PHPPortlet.class.getName())) {
284
285 phpPortlet = true;
286 }
287
288 if (ClassUtil.isSubclass(
289 portletInstance.getClass(),
290 StrutsPortlet.class.getName())) {
291
292 strutsBridges = true;
293 }
294 }
295 }
296
297 if (phpPortlet) {
298 bindDataSource(servletContextName);
299 }
300
301 if (!strutsBridges) {
302 strutsBridges = GetterUtil.getBoolean(
303 servletContext.getInitParameter(
304 "struts-bridges-context-provider"));
305 }
306
307 if (strutsBridges) {
308 servletContext.setAttribute(
309 ServletContextProvider.STRUTS_BRIDGES_CONTEXT_PROVIDER,
310 new LiferayServletContextProvider());
311 }
312
313 String xml = HttpUtil.URLtoString(
314 servletContext.getResource("/WEB-INF/liferay-display.xml"));
315
316 PortletCategory newPortletCategory =
317 PortletLocalServiceUtil.getWARDisplay(servletContextName, xml);
318
319 long[] companyIds = PortalInstances.getCompanyIds();
320
321 for (long companyId : companyIds) {
322 PortletCategory portletCategory = (PortletCategory)WebAppPool.get(
323 companyId, WebKeys.PORTLET_CATEGORY);
324
325 if (portletCategory != null) {
326 portletCategory.merge(newPortletCategory);
327 }
328 else {
329 _log.error(
330 "Unable to register portlet for company " + companyId +
331 " because it does not exist");
332 }
333 }
334
335 processPortletProperties(servletContextName, classLoader);
336
337 for (Portlet portlet : portlets) {
338 List<String> modelNames =
339 ResourceActionsUtil.getPortletModelResources(
340 portlet.getPortletId());
341
342 List<String> portletActions =
343 ResourceActionsUtil.getPortletResourceActions(
344 portlet.getPortletId());
345
346 ResourceActionLocalServiceUtil.checkResourceActions(
347 portlet.getPortletId(), portletActions);
348
349 for (String modelName : modelNames) {
350 List<String> modelActions =
351 ResourceActionsUtil.getModelResourceActions(modelName);
352
353 ResourceActionLocalServiceUtil.checkResourceActions(
354 modelName, modelActions);
355 }
356
357 for (long companyId : companyIds) {
358 Portlet curPortlet = PortletLocalServiceUtil.getPortletById(
359 companyId, portlet.getPortletId());
360
361 PortletLocalServiceUtil.checkPortlet(curPortlet);
362 }
363 }
364
365 for (Portlet portlet : portlets) {
366 boolean ready = GetterUtil.getBoolean(
367 servletContext.getInitParameter("portlets-ready-by-default"),
368 true);
369
370 portlet.setReady(ready);
371 }
372
373 registerClpMessageListeners(servletContext, classLoader);
374
375 JavadocManagerUtil.load(servletContextName, classLoader);
376
377 DirectServletRegistryUtil.clearServlets();
378 FileTimestampUtil.reset();
379 SettingsFactoryUtil.clearCache();
380
381 _portlets.put(servletContextName, portlets);
382
383 servletContext.setAttribute(WebKeys.PLUGIN_PORTLETS, portlets);
384
385 if (_log.isInfoEnabled()) {
386 if (portlets.size() == 1) {
387 _log.info(
388 "1 portlet for " + servletContextName +
389 " is available for use");
390 }
391 else {
392 _log.info(
393 portlets.size() + " portlets for " + servletContextName +
394 " are available for use");
395 }
396 }
397 }
398
399 protected void doInvokeUndeploy(HotDeployEvent hotDeployEvent)
400 throws Exception {
401
402 ServletContext servletContext = hotDeployEvent.getServletContext();
403
404 String servletContextName = servletContext.getServletContextName();
405
406 if (_log.isDebugEnabled()) {
407 _log.debug("Invoking undeploy for " + servletContextName);
408 }
409
410 List<Portlet> portlets = _portlets.remove(servletContextName);
411
412 if (portlets == null) {
413 return;
414 }
415
416 Set<String> portletIds = new HashSet<String>();
417
418 if (portlets != null) {
419 if (_log.isInfoEnabled()) {
420 _log.info("Unregistering portlets for " + servletContextName);
421 }
422
423 for (Portlet portlet : portlets) {
424 destroyPortlet(portlet, portletIds);
425 }
426 }
427
428 ServletContextPool.remove(servletContextName);
429
430 if (!portletIds.isEmpty()) {
431 long[] companyIds = PortalInstances.getCompanyIds();
432
433 for (long companyId : companyIds) {
434 PortletCategory portletCategory =
435 (PortletCategory)WebAppPool.get(
436 companyId, WebKeys.PORTLET_CATEGORY);
437
438 portletCategory.separate(portletIds);
439 }
440 }
441
442 PortletContextBagPool.remove(servletContextName);
443 PortletResourceBundles.remove(servletContextName);
444
445 unbindDataSource(servletContextName);
446
447 unregisterClpMessageListeners(servletContext);
448
449 JavadocManagerUtil.unload(servletContextName);
450
451 DirectServletRegistryUtil.clearServlets();
452
453 if (_log.isInfoEnabled()) {
454 if (portlets.size() == 1) {
455 _log.info(
456 "1 portlet for " + servletContextName +
457 " was unregistered");
458 }
459 else {
460 _log.info(
461 portlets.size() + " portlets for " + servletContextName +
462 " were unregistered");
463 }
464 }
465 }
466
467 protected void initPortletApp(
468 String servletContextName, ServletContext servletContext,
469 ClassLoader classLoader, Portlet portlet)
470 throws Exception {
471
472 PortletContextBag portletContextBag = new PortletContextBag(
473 servletContextName);
474
475 PortletContextBagPool.put(servletContextName, portletContextBag);
476
477 PortletApp portletApp = portlet.getPortletApp();
478
479 servletContext.setAttribute(PortletServlet.PORTLET_APP, portletApp);
480
481 Map<String, String> customUserAttributes =
482 portletApp.getCustomUserAttributes();
483
484 for (Map.Entry<String, String> entry :
485 customUserAttributes.entrySet()) {
486
487 String attrCustomClass = entry.getValue();
488
489 Class<?> clazz = classLoader.loadClass(attrCustomClass);
490
491 CustomUserAttributes customUserAttributesInstance =
492 (CustomUserAttributes)clazz.newInstance();
493
494 portletContextBag.getCustomUserAttributes().put(
495 attrCustomClass, customUserAttributesInstance);
496 }
497
498 Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
499
500 for (PortletFilter portletFilter : portletFilters) {
501 javax.portlet.filter.PortletFilter portletFilterInstance =
502 (javax.portlet.filter.PortletFilter)newInstance(
503 classLoader,
504 new Class<?>[] {
505 javax.portlet.filter.ActionFilter.class,
506 javax.portlet.filter.EventFilter.class,
507 javax.portlet.filter.PortletFilter.class,
508 javax.portlet.filter.RenderFilter.class,
509 javax.portlet.filter.ResourceFilter.class
510 },
511 portletFilter.getFilterClass());
512
513 portletContextBag.getPortletFilters().put(
514 portletFilter.getFilterName(), portletFilterInstance);
515 }
516
517 InvokerPortlet invokerPortlet = PortletInstanceFactoryUtil.create(
518 portlet, servletContext);
519
520 invokerPortlet.setPortletFilters();
521
522 Set<PortletURLListener> portletURLListeners =
523 portletApp.getPortletURLListeners();
524
525 for (PortletURLListener portletURLListener : portletURLListeners) {
526 PortletURLGenerationListener portletURLListenerInstance =
527 (PortletURLGenerationListener)newInstance(
528 classLoader, PortletURLGenerationListener.class,
529 portletURLListener.getListenerClass());
530
531 portletContextBag.getPortletURLListeners().put(
532 portletURLListener.getListenerClass(),
533 portletURLListenerInstance);
534
535 PortletURLListenerFactory.create(portletURLListener);
536 }
537 }
538
539 protected void processPortletProperties(
540 String servletContextName, ClassLoader classLoader)
541 throws Exception {
542
543 Configuration portletPropertiesConfiguration = null;
544
545 try {
546 portletPropertiesConfiguration =
547 ConfigurationFactoryUtil.getConfiguration(
548 classLoader, "portlet");
549 }
550 catch (Exception e) {
551 if (_log.isDebugEnabled()) {
552 _log.debug("Unable to read portlet.properties");
553 }
554
555 return;
556 }
557
558 Properties portletProperties =
559 portletPropertiesConfiguration.getProperties();
560
561 if (portletProperties.isEmpty()) {
562 return;
563 }
564
565 String languageBundleName = portletProperties.getProperty(
566 "language.bundle");
567
568 if (Validator.isNotNull(languageBundleName)) {
569 Locale[] locales = LanguageUtil.getAvailableLocales();
570
571 for (Locale locale : locales) {
572 ResourceBundle resourceBundle = ResourceBundle.getBundle(
573 languageBundleName, locale, classLoader);
574
575 PortletResourceBundles.put(
576 servletContextName, LocaleUtil.toLanguageId(locale),
577 resourceBundle);
578 }
579 }
580
581 String[] resourceActionConfigs = StringUtil.split(
582 portletProperties.getProperty(PropsKeys.RESOURCE_ACTIONS_CONFIGS));
583
584 for (String resourceActionConfig : resourceActionConfigs) {
585 ResourceActionsUtil.read(
586 servletContextName, classLoader, resourceActionConfig);
587 }
588 }
589
590 protected void unbindDataSource(String servletContextName) {
591 Boolean dataSourceBindState = _dataSourceBindStates.remove(
592 servletContextName);
593
594 if (dataSourceBindState == null) {
595 return;
596 }
597
598 try {
599 if (_log.isDebugEnabled()) {
600 _log.debug("Dynamically unbinding the Liferay data source");
601 }
602
603 Context context = new InitialContext();
604
605 try {
606 context.lookup(_JNDI_JDBC_LIFERAY_POOL);
607
608 context.unbind(_JNDI_JDBC_LIFERAY_POOL);
609 }
610 catch (NamingException ne) {
611 }
612
613 try {
614 context.lookup(_JNDI_JDBC);
615
616 context.destroySubcontext(_JNDI_JDBC);
617 }
618 catch (NamingException ne) {
619 }
620 }
621 catch (Exception e) {
622 if (_log.isWarnEnabled()) {
623 _log.warn(
624 "Unable to dynamically unbind the Liferay data source: " +
625 e.getMessage());
626 }
627 }
628 }
629
630 private static final String _JNDI_JDBC = "java_liferay:jdbc";
631
632 private static final String _JNDI_JDBC_LIFERAY_POOL =
633 _JNDI_JDBC + "/LiferayPool";
634
635 private static final Log _log = LogFactoryUtil.getLog(
636 PortletHotDeployListener.class);
637
638 private static final Map<String, Boolean> _dataSourceBindStates =
639 new HashMap<String, Boolean>();
640 private static final Map<String, List<Portlet>> _portlets =
641 new HashMap<String, List<Portlet>>();
642
643 }