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.SchedulerEngineUtil;
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 import com.liferay.util.log4j.Log4JUtil;
085
086 import java.util.HashMap;
087 import java.util.HashSet;
088 import java.util.Iterator;
089 import java.util.List;
090 import java.util.Locale;
091 import java.util.Map;
092 import java.util.Properties;
093 import java.util.ResourceBundle;
094 import java.util.Set;
095
096 import javax.naming.Context;
097 import javax.naming.InitialContext;
098 import javax.naming.NamingException;
099
100 import javax.portlet.PortletURLGenerationListener;
101
102 import javax.servlet.ServletContext;
103
104 import javax.sql.DataSource;
105
106 import org.apache.portals.bridges.struts.StrutsPortlet;
107
108
114 public class PortletHotDeployListener extends BaseHotDeployListener {
115
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 public void invokeUndeploy(HotDeployEvent hotDeployEvent)
129 throws HotDeployException {
130
131 try {
132 doInvokeUndeploy(hotDeployEvent);
133 }
134 catch (Throwable t) {
135 throwHotDeployException(
136 hotDeployEvent, "Error unregistering portlets for ", t);
137 }
138 }
139
140 protected void bindDataSource(String servletContextName) throws Exception {
141 if (ServerDetector.isGlassfish() || ServerDetector.isJOnAS()) {
142 return;
143 }
144
145 if (_log.isDebugEnabled()) {
146 _log.debug("Dynamically binding the Liferay data source");
147 }
148
149 DataSource dataSource = InfrastructureUtil.getDataSource();
150
151 if (dataSource == null) {
152 if (_log.isDebugEnabled()) {
153 _log.debug(
154 "Abort dynamically binding the Liferay data source " +
155 "because it is not available");
156 }
157
158 return;
159 }
160
161 Context context = new InitialContext();
162
163 try {
164 try {
165 context.lookup(_JNDI_JDBC);
166 }
167 catch (NamingException ne) {
168 context.createSubcontext(_JNDI_JDBC);
169 }
170
171 try {
172 context.lookup(_JNDI_JDBC_LIFERAY_POOL);
173 }
174 catch (NamingException ne) {
175 context.bind(_JNDI_JDBC_LIFERAY_POOL, dataSource);
176 }
177
178 _dataSourceBindStates.put(servletContextName, true);
179 }
180 catch (Exception e) {
181 if (_log.isWarnEnabled()) {
182 _log.warn(
183 "Unable to dynamically bind the Liferay data source: " +
184 e.getMessage());
185 }
186 }
187 }
188
189 protected void destroyPortlet(Portlet portlet, Set<String> portletIds)
190 throws Exception {
191
192 PortletApp portletApp = portlet.getPortletApp();
193
194 Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
195
196 for (PortletFilter portletFilter : portletFilters) {
197 PortletFilterFactory.destroy(portletFilter);
198 }
199
200 Set<PortletURLListener> portletURLListeners =
201 portletApp.getPortletURLListeners();
202
203 for (PortletURLListener portletURLListener : portletURLListeners) {
204 PortletURLListenerFactory.destroy(portletURLListener);
205 }
206
207 List<Indexer> indexers = portlet.getIndexerInstances();
208
209 for (Indexer indexer : indexers) {
210 IndexerRegistryUtil.unregister(indexer);
211 }
212
213 if (PropsValues.SCHEDULER_ENABLED) {
214 List<SchedulerEntry> schedulerEntries =
215 portlet.getSchedulerEntries();
216
217 if ((schedulerEntries != null) && !schedulerEntries.isEmpty()) {
218 for (SchedulerEntry schedulerEntry : schedulerEntries) {
219 SchedulerEngineUtil.unschedule(
220 schedulerEntry, StorageType.MEMORY_CLUSTERED);
221 }
222 }
223 }
224
225 PollerProcessorUtil.deletePollerProcessor(portlet.getPortletId());
226
227 POPServerUtil.deleteListener(portlet.getPopMessageListenerInstance());
228
229 SocialActivityInterpreterLocalServiceUtil.deleteActivityInterpreter(
230 portlet.getSocialActivityInterpreterInstance());
231
232 SocialRequestInterpreterLocalServiceUtil.deleteRequestInterpreter(
233 portlet.getSocialRequestInterpreterInstance());
234
235 WebDAVUtil.deleteStorage(portlet.getWebDAVStorageInstance());
236
237 XmlRpcServlet.unregisterMethod(portlet.getXmlRpcMethodInstance());
238
239 List<AssetRendererFactory> assetRendererFactories =
240 portlet.getAssetRendererFactoryInstances();
241
242 if (assetRendererFactories != null) {
243 AssetRendererFactoryRegistryUtil.unregister(assetRendererFactories);
244 }
245
246 List<AtomCollectionAdapter<?>> atomCollectionAdapters =
247 portlet.getAtomCollectionAdapterInstances();
248
249 if (atomCollectionAdapters != null) {
250 AtomCollectionAdapterRegistryUtil.unregister(
251 atomCollectionAdapters);
252 }
253
254 List<WorkflowHandler> workflowHandlers =
255 portlet.getWorkflowHandlerInstances();
256
257 if (workflowHandlers != null) {
258 WorkflowHandlerRegistryUtil.unregister(workflowHandlers);
259 }
260
261 PortletInstanceFactoryUtil.destroy(portlet);
262
263 portletIds.add(portlet.getPortletId());
264 }
265
266 protected void doInvokeDeploy(HotDeployEvent hotDeployEvent)
267 throws Exception {
268
269 ServletContext servletContext = hotDeployEvent.getServletContext();
270
271 String servletContextName = servletContext.getServletContextName();
272
273 if (_log.isDebugEnabled()) {
274 _log.debug("Invoking deploy for " + servletContextName);
275 }
276
277 String[] xmls = new String[] {
278 HttpUtil.URLtoString(
279 servletContext.getResource(
280 "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_STANDARD)),
281 HttpUtil.URLtoString(
282 servletContext.getResource(
283 "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_CUSTOM)),
284 HttpUtil.URLtoString(
285 servletContext.getResource("/WEB-INF/liferay-portlet.xml")),
286 HttpUtil.URLtoString(servletContext.getResource("/WEB-INF/web.xml"))
287 };
288
289 if ((xmls[0] == null) && (xmls[1] == null)) {
290 return;
291 }
292
293 if (_log.isInfoEnabled()) {
294 _log.info("Registering portlets for " + servletContextName);
295 }
296
297 List<Portlet> portlets = PortletLocalServiceUtil.initWAR(
298 servletContextName, servletContext, xmls,
299 hotDeployEvent.getPluginPackage());
300
301 ClassLoader classLoader = hotDeployEvent.getContextClassLoader();
302
303 initLogger(classLoader);
304
305 boolean portletAppInitialized = false;
306
307 boolean phpPortlet = false;
308 boolean strutsBridges = false;
309
310 PortletBagFactory portletBagFactory = new PortletBagFactory();
311
312 portletBagFactory.setClassLoader(classLoader);
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 void initLogger(ClassLoader classLoader) {
538 Log4JUtil.configureLog4J(
539 classLoader.getResource("META-INF/portal-log4j.xml"));
540 }
541
542 protected PortletBag initPortlet(
543 Portlet portlet, PortletBagFactory portletBagFactory)
544 throws Exception {
545
546 return portletBagFactory.create(portlet);
547 }
548
549 protected void initPortletApp(
550 String servletContextName, ServletContext servletContext,
551 ClassLoader classLoader, Portlet portlet)
552 throws Exception {
553
554 PortletContextBag portletContextBag = new PortletContextBag(
555 servletContextName);
556
557 PortletContextBagPool.put(servletContextName, portletContextBag);
558
559 PortletApp portletApp = portlet.getPortletApp();
560
561 servletContext.setAttribute(PortletServlet.PORTLET_APP, portletApp);
562
563 Map<String, String> customUserAttributes =
564 portletApp.getCustomUserAttributes();
565
566 for (Map.Entry<String, String> entry :
567 customUserAttributes.entrySet()) {
568
569 String attrCustomClass = entry.getValue();
570
571 CustomUserAttributes customUserAttributesInstance =
572 (CustomUserAttributes)classLoader.loadClass(
573 attrCustomClass).newInstance();
574
575 portletContextBag.getCustomUserAttributes().put(
576 attrCustomClass, customUserAttributesInstance);
577 }
578
579 Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
580
581 for (PortletFilter portletFilter : portletFilters) {
582 javax.portlet.filter.PortletFilter portletFilterInstance =
583 (javax.portlet.filter.PortletFilter)newInstance(
584 classLoader,
585 new Class<?>[] {
586 javax.portlet.filter.ActionFilter.class,
587 javax.portlet.filter.EventFilter.class,
588 javax.portlet.filter.PortletFilter.class,
589 javax.portlet.filter.RenderFilter.class,
590 javax.portlet.filter.ResourceFilter.class
591 },
592 portletFilter.getFilterClass());
593
594 portletContextBag.getPortletFilters().put(
595 portletFilter.getFilterName(), portletFilterInstance);
596 }
597
598 InvokerPortlet invokerPortlet = PortletInstanceFactoryUtil.create(
599 portlet, servletContext);
600
601 invokerPortlet.setPortletFilters();
602
603 Set<PortletURLListener> portletURLListeners =
604 portletApp.getPortletURLListeners();
605
606 for (PortletURLListener portletURLListener : portletURLListeners) {
607 PortletURLGenerationListener portletURLListenerInstance =
608 (PortletURLGenerationListener)newInstance(
609 classLoader, PortletURLGenerationListener.class,
610 portletURLListener.getListenerClass());
611
612 portletContextBag.getPortletURLListeners().put(
613 portletURLListener.getListenerClass(),
614 portletURLListenerInstance);
615
616 PortletURLListenerFactory.create(portletURLListener);
617 }
618 }
619
620 protected void processPortletProperties(
621 String servletContextName, ClassLoader classLoader)
622 throws Exception {
623
624 Configuration portletPropertiesConfiguration = null;
625
626 try {
627 portletPropertiesConfiguration =
628 ConfigurationFactoryUtil.getConfiguration(
629 classLoader, "portlet");
630 }
631 catch (Exception e) {
632 if (_log.isDebugEnabled()) {
633 _log.debug("Unable to read portlet.properties");
634 }
635
636 return;
637 }
638
639 Properties portletProperties =
640 portletPropertiesConfiguration.getProperties();
641
642 if (portletProperties.size() == 0) {
643 return;
644 }
645
646 String languageBundleName = portletProperties.getProperty(
647 "language.bundle");
648
649 if (Validator.isNotNull(languageBundleName)) {
650 Locale[] locales = LanguageUtil.getAvailableLocales();
651
652 for (Locale locale : locales) {
653 ResourceBundle resourceBundle = ResourceBundle.getBundle(
654 languageBundleName, locale, classLoader);
655
656 PortletResourceBundles.put(
657 servletContextName, LocaleUtil.toLanguageId(locale),
658 resourceBundle);
659 }
660 }
661
662 String[] resourceActionConfigs = StringUtil.split(
663 portletProperties.getProperty(PropsKeys.RESOURCE_ACTIONS_CONFIGS));
664
665 for (String resourceActionConfig : resourceActionConfigs) {
666 ResourceActionsUtil.read(
667 servletContextName, classLoader, resourceActionConfig);
668 }
669 }
670
671 protected void unbindDataSource(String servletContextName) {
672 Boolean dataSourceBindState = _dataSourceBindStates.remove(
673 servletContextName);
674
675 if (dataSourceBindState == null) {
676 return;
677 }
678
679 try {
680 if (_log.isDebugEnabled()) {
681 _log.debug("Dynamically unbinding the Liferay data source");
682 }
683
684 Context context = new InitialContext();
685
686 try {
687 context.lookup(_JNDI_JDBC_LIFERAY_POOL);
688
689 context.unbind(_JNDI_JDBC_LIFERAY_POOL);
690 }
691 catch (NamingException ne) {
692 }
693
694 try {
695 context.lookup(_JNDI_JDBC);
696
697 context.destroySubcontext(_JNDI_JDBC);
698 }
699 catch (NamingException ne) {
700 }
701 }
702 catch (Exception e) {
703 if (_log.isWarnEnabled()) {
704 _log.warn(
705 "Unable to dynamically unbind the Liferay data source: " +
706 e.getMessage());
707 }
708 }
709 }
710
711 private static final String _JNDI_JDBC = "java_liferay:jdbc";
712
713 private static final String _JNDI_JDBC_LIFERAY_POOL =
714 _JNDI_JDBC + "/LiferayPool";
715
716 private static Log _log = LogFactoryUtil.getLog(
717 PortletHotDeployListener.class);
718
719 private static Map<String, Boolean> _dataSourceBindStates =
720 new HashMap<String, Boolean>();
721 private static Map<String, ObjectValuePair<long[], List<Portlet>>>
722 _portlets =
723 new HashMap<String, ObjectValuePair<long[], List<Portlet>>>();
724
725 }