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