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