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