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