1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.deploy.hot;
16  
17  import com.liferay.portal.apache.bridges.struts.LiferayServletContextProvider;
18  import com.liferay.portal.kernel.configuration.Configuration;
19  import com.liferay.portal.kernel.configuration.ConfigurationFactoryUtil;
20  import com.liferay.portal.kernel.deploy.hot.BaseHotDeployListener;
21  import com.liferay.portal.kernel.deploy.hot.HotDeployEvent;
22  import com.liferay.portal.kernel.deploy.hot.HotDeployException;
23  import com.liferay.portal.kernel.language.LanguageUtil;
24  import com.liferay.portal.kernel.log.Log;
25  import com.liferay.portal.kernel.log.LogFactoryUtil;
26  import com.liferay.portal.kernel.portlet.PortletBag;
27  import com.liferay.portal.kernel.scheduler.SchedulerEngineUtil;
28  import com.liferay.portal.kernel.scheduler.SchedulerEntry;
29  import com.liferay.portal.kernel.search.Indexer;
30  import com.liferay.portal.kernel.search.IndexerRegistryUtil;
31  import com.liferay.portal.kernel.servlet.PortletServlet;
32  import com.liferay.portal.kernel.servlet.ServletContextProvider;
33  import com.liferay.portal.kernel.util.ClassUtil;
34  import com.liferay.portal.kernel.util.GetterUtil;
35  import com.liferay.portal.kernel.util.HttpUtil;
36  import com.liferay.portal.kernel.util.LocaleUtil;
37  import com.liferay.portal.kernel.util.ObjectValuePair;
38  import com.liferay.portal.kernel.util.StringUtil;
39  import com.liferay.portal.kernel.util.Validator;
40  import com.liferay.portal.kernel.webdav.WebDAVUtil;
41  import com.liferay.portal.kernel.workflow.WorkflowHandler;
42  import com.liferay.portal.kernel.workflow.WorkflowHandlerRegistryUtil;
43  import com.liferay.portal.model.Portlet;
44  import com.liferay.portal.model.PortletApp;
45  import com.liferay.portal.model.PortletCategory;
46  import com.liferay.portal.model.PortletFilter;
47  import com.liferay.portal.model.PortletURLListener;
48  import com.liferay.portal.poller.PollerProcessorUtil;
49  import com.liferay.portal.pop.POPServerUtil;
50  import com.liferay.portal.security.permission.ResourceActionsUtil;
51  import com.liferay.portal.service.PortletLocalServiceUtil;
52  import com.liferay.portal.service.ResourceActionLocalServiceUtil;
53  import com.liferay.portal.service.ResourceCodeLocalServiceUtil;
54  import com.liferay.portal.util.Portal;
55  import com.liferay.portal.util.PortalInstances;
56  import com.liferay.portal.util.PropsValues;
57  import com.liferay.portal.util.WebAppPool;
58  import com.liferay.portal.util.WebKeys;
59  import com.liferay.portal.xmlrpc.XmlRpcServlet;
60  import com.liferay.portlet.CustomUserAttributes;
61  import com.liferay.portlet.PortletBagFactory;
62  import com.liferay.portlet.PortletConfigFactory;
63  import com.liferay.portlet.PortletContextBag;
64  import com.liferay.portlet.PortletContextBagPool;
65  import com.liferay.portlet.PortletFilterFactory;
66  import com.liferay.portlet.PortletInstanceFactoryUtil;
67  import com.liferay.portlet.PortletResourceBundles;
68  import com.liferay.portlet.PortletURLListenerFactory;
69  import com.liferay.portlet.asset.AssetRendererFactoryRegistryUtil;
70  import com.liferay.portlet.asset.model.AssetRendererFactory;
71  import com.liferay.portlet.social.service.SocialActivityInterpreterLocalServiceUtil;
72  import com.liferay.portlet.social.service.SocialRequestInterpreterLocalServiceUtil;
73  
74  import java.util.HashMap;
75  import java.util.HashSet;
76  import java.util.Iterator;
77  import java.util.List;
78  import java.util.Locale;
79  import java.util.Map;
80  import java.util.Properties;
81  import java.util.ResourceBundle;
82  import java.util.Set;
83  
84  import javax.portlet.PortletConfig;
85  import javax.portlet.PortletContext;
86  import javax.portlet.PortletURLGenerationListener;
87  
88  import javax.servlet.ServletContext;
89  
90  import org.apache.portals.bridges.struts.StrutsPortlet;
91  
92  /**
93   * <a href="PortletHotDeployListener.java.html"><b><i>View Source</i></b></a>
94   *
95   * @author Brian Wing Shun Chan
96   * @author Brian Myunghun Kim
97   * @author Ivica Cardic
98   * @author Raymond Augé
99   */
100 public class PortletHotDeployListener extends BaseHotDeployListener {
101 
102     public void invokeDeploy(HotDeployEvent event) throws HotDeployException {
103         try {
104             doInvokeDeploy(event);
105         }
106         catch (Throwable t) {
107             throwHotDeployException(
108                 event, "Error registering portlets for ", t);
109         }
110     }
111 
112     public void invokeUndeploy(HotDeployEvent event) throws HotDeployException {
113         try {
114             doInvokeUndeploy(event);
115         }
116         catch (Throwable t) {
117             throwHotDeployException(
118                 event, "Error unregistering portlets for ", t);
119         }
120     }
121 
122     protected void destroyPortlet(Portlet portlet, Set<String> portletIds)
123         throws Exception {
124 
125         PortletApp portletApp = portlet.getPortletApp();
126 
127         Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
128 
129         for (PortletFilter portletFilter : portletFilters) {
130             PortletFilterFactory.destroy(portletFilter);
131         }
132 
133         Set<PortletURLListener> portletURLListeners =
134             portletApp.getPortletURLListeners();
135 
136         for (PortletURLListener portletURLListener : portletURLListeners) {
137             PortletURLListenerFactory.destroy(portletURLListener);
138         }
139 
140         Indexer indexer = portlet.getIndexerInstance();
141 
142         if (indexer != null) {
143             IndexerRegistryUtil.unregister(indexer);
144         }
145 
146         if (PropsValues.SCHEDULER_ENABLED){
147             List<SchedulerEntry> schedulerEntries =
148                 portlet.getSchedulerEntries();
149 
150             if ((schedulerEntries != null) && !schedulerEntries.isEmpty()) {
151                 for (SchedulerEntry schedulerEntry : schedulerEntries) {
152                     SchedulerEngineUtil.unschedule(schedulerEntry);
153                 }
154             }
155         }
156 
157         PollerProcessorUtil.deletePollerProcessor(portlet.getPortletId());
158 
159         POPServerUtil.deleteListener(portlet.getPopMessageListenerInstance());
160 
161         SocialActivityInterpreterLocalServiceUtil.deleteActivityInterpreter(
162             portlet.getSocialActivityInterpreterInstance());
163 
164         SocialRequestInterpreterLocalServiceUtil.deleteRequestInterpreter(
165             portlet.getSocialRequestInterpreterInstance());
166 
167         WebDAVUtil.deleteStorage(portlet.getWebDAVStorageInstance());
168 
169         XmlRpcServlet.unregisterMethod(portlet.getXmlRpcMethodInstance());
170 
171         List<AssetRendererFactory> assetRendererFactories =
172             portlet.getAssetRendererFactoryInstances();
173 
174         if (assetRendererFactories != null) {
175             AssetRendererFactoryRegistryUtil.unregister(assetRendererFactories);
176         }
177 
178         List<WorkflowHandler> workflowHandlers =
179             portlet.getWorkflowHandlerInstances();
180 
181         if (workflowHandlers != null) {
182             WorkflowHandlerRegistryUtil.unregister(workflowHandlers);
183         }
184 
185         PortletInstanceFactoryUtil.destroy(portlet);
186 
187         portletIds.add(portlet.getPortletId());
188     }
189 
190     protected void doInvokeDeploy(HotDeployEvent event) throws Exception {
191 
192         // Servlet context
193 
194         ServletContext servletContext = event.getServletContext();
195 
196         String servletContextName = servletContext.getServletContextName();
197 
198         if (_log.isDebugEnabled()) {
199             _log.debug("Invoking deploy for " + servletContextName);
200         }
201 
202         // Company ids
203 
204         long[] companyIds = PortalInstances.getCompanyIds();
205 
206         // Initialize portlets
207 
208         String[] xmls = new String[] {
209             HttpUtil.URLtoString(servletContext.getResource(
210                 "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_STANDARD)),
211             HttpUtil.URLtoString(servletContext.getResource(
212                 "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_CUSTOM)),
213             HttpUtil.URLtoString(servletContext.getResource(
214                 "/WEB-INF/liferay-portlet.xml")),
215             HttpUtil.URLtoString(servletContext.getResource("/WEB-INF/web.xml"))
216         };
217 
218         if (xmls[0] == null) {
219             return;
220         }
221 
222         if (_log.isInfoEnabled()) {
223             _log.info("Registering portlets for " + servletContextName);
224         }
225 
226         List<Portlet> portlets = PortletLocalServiceUtil.initWAR(
227             servletContextName, servletContext, xmls, event.getPluginPackage());
228 
229         // Class loader
230 
231         ClassLoader portletClassLoader = event.getContextClassLoader();
232 
233         servletContext.setAttribute(
234             PortletServlet.PORTLET_CLASS_LOADER, portletClassLoader);
235 
236         // Portlet context wrapper
237 
238         _portletAppInitialized = false;
239         _strutsBridges = false;
240 
241         PortletBagFactory portletBagFactory = new PortletBagFactory();
242 
243         portletBagFactory.setClassLoader(portletClassLoader);
244         portletBagFactory.setServletContext(servletContext);
245         portletBagFactory.setWARFile(true);
246 
247         Iterator<Portlet> itr = portlets.iterator();
248 
249         while (itr.hasNext()) {
250             Portlet portlet = itr.next();
251 
252             PortletBag portletBag = initPortlet(portlet, portletBagFactory);
253 
254             if (portletBag == null) {
255                 itr.remove();
256             }
257             else {
258                 if (!_portletAppInitialized) {
259                     initPortletApp(
260                         portlet, servletContextName, servletContext,
261                         portletClassLoader);
262 
263                     _portletAppInitialized = true;
264                 }
265             }
266         }
267 
268         // Struts bridges
269 
270         if (!_strutsBridges) {
271             _strutsBridges = GetterUtil.getBoolean(
272                 servletContext.getInitParameter(
273                     "struts-bridges-context-provider"));
274         }
275 
276         if (_strutsBridges) {
277             servletContext.setAttribute(
278                 ServletContextProvider.STRUTS_BRIDGES_CONTEXT_PROVIDER,
279                 new LiferayServletContextProvider());
280         }
281 
282         // Portlet display
283 
284         String xml = HttpUtil.URLtoString(servletContext.getResource(
285             "/WEB-INF/liferay-display.xml"));
286 
287         PortletCategory newPortletCategory =
288             PortletLocalServiceUtil.getWARDisplay(servletContextName, xml);
289 
290         for (int i = 0; i < companyIds.length; i++) {
291             long companyId = companyIds[i];
292 
293             PortletCategory portletCategory =
294                 (PortletCategory)WebAppPool.get(
295                     String.valueOf(companyId), WebKeys.PORTLET_CATEGORY);
296 
297             if (portletCategory != null) {
298                 portletCategory.merge(newPortletCategory);
299             }
300             else {
301                 _log.error(
302                     "Unable to register portlet for company " + companyId +
303                         " because it does not exist");
304             }
305         }
306 
307         // Portlet properties
308 
309         processPortletProperties(servletContextName, portletClassLoader);
310 
311         // Resource actions, resource codes, and check
312 
313         itr = portlets.iterator();
314 
315         while (itr.hasNext()) {
316             Portlet portlet = itr.next();
317 
318             List<String> modelNames =
319                 ResourceActionsUtil.getPortletModelResources(
320                     portlet.getPortletId());
321 
322             for (long companyId : companyIds) {
323                 ResourceCodeLocalServiceUtil.checkResourceCodes(
324                     companyId, portlet.getPortletId());
325 
326                 for (String modelName : modelNames) {
327                     ResourceCodeLocalServiceUtil.checkResourceCodes(
328                         companyId, modelName);
329                 }
330             }
331 
332             List<String> portletActions =
333                 ResourceActionsUtil.getPortletResourceActions(
334                     portlet.getPortletId());
335 
336             ResourceActionLocalServiceUtil.checkResourceActions(
337                 portlet.getPortletId(), portletActions);
338 
339             for (String modelName : modelNames) {
340                 List<String> modelActions =
341                     ResourceActionsUtil.getModelResourceActions(modelName);
342 
343                 ResourceActionLocalServiceUtil.checkResourceActions(
344                     modelName, modelActions);
345             }
346 
347             for (long companyId : companyIds) {
348                 Portlet curPortlet = PortletLocalServiceUtil.getPortletById(
349                     companyId, portlet.getPortletId());
350 
351                 PortletLocalServiceUtil.checkPortlet(curPortlet);
352             }
353         }
354 
355         // ClpMessageListener
356 
357         registerClpMessageListeners(servletContext, portletClassLoader);
358 
359         // Variables
360 
361         _vars.put(
362             servletContextName,
363             new ObjectValuePair<long[], List<Portlet>>(
364                 companyIds, portlets));
365 
366         if (_log.isInfoEnabled()) {
367             if (portlets.size() == 1) {
368                 _log.info(
369                     "1 portlet for " + servletContextName +
370                         " is available for use");
371             }
372             else {
373                 _log.info(
374                     portlets.size() + " portlets for " + servletContextName +
375                         " are available for use");
376             }
377         }
378     }
379 
380     protected void doInvokeUndeploy(HotDeployEvent event) throws Exception {
381         ServletContext servletContext = event.getServletContext();
382 
383         String servletContextName = servletContext.getServletContextName();
384 
385         if (_log.isDebugEnabled()) {
386             _log.debug("Invoking undeploy for " + servletContextName);
387         }
388 
389         ObjectValuePair<long[], List<Portlet>> ovp =
390             _vars.remove(servletContextName);
391 
392         if (ovp == null) {
393             return;
394         }
395 
396         long[] companyIds = ovp.getKey();
397         List<Portlet> portlets = ovp.getValue();
398 
399         Set<String> portletIds = new HashSet<String>();
400 
401         if (portlets != null) {
402             if (_log.isInfoEnabled()) {
403                 _log.info(
404                     "Unregistering portlets for " + servletContextName);
405             }
406 
407             Iterator<Portlet> itr = portlets.iterator();
408 
409             while (itr.hasNext()) {
410                 Portlet portlet = itr.next();
411 
412                 destroyPortlet(portlet, portletIds);
413             }
414         }
415 
416         if (portletIds.size() > 0) {
417             for (int i = 0; i < companyIds.length; i++) {
418                 long companyId = companyIds[i];
419 
420                 PortletCategory portletCategory =
421                     (PortletCategory)WebAppPool.get(
422                         String.valueOf(companyId), WebKeys.PORTLET_CATEGORY);
423 
424                 portletCategory.separate(portletIds);
425             }
426         }
427 
428         PortletResourceBundles.remove(servletContextName);
429 
430         unregisterClpMessageListeners(servletContext);
431 
432         if (_log.isInfoEnabled()) {
433             if (portlets.size() == 1) {
434                 _log.info(
435                     "1 portlet for " + servletContextName +
436                         " was unregistered");
437             }
438             else {
439                 _log.info(
440                     portlets.size() + " portlets for " + servletContextName +
441                         " was unregistered");
442             }
443         }
444     }
445 
446     protected PortletBag initPortlet(
447             Portlet portlet, PortletBagFactory portletBagFactory)
448         throws Exception {
449 
450         PortletBag portletBag = portletBagFactory.create(portlet);
451 
452         if (portletBag == null) {
453             return null;
454         }
455 
456         javax.portlet.Portlet portletInstance = portletBag.getPortletInstance();
457 
458         if (ClassUtil.isSubclass(
459                 portletInstance.getClass(), StrutsPortlet.class.getName())) {
460 
461             _strutsBridges = true;
462         }
463 
464         return portletBag;
465     }
466 
467     protected void initPortletApp(
468             Portlet portlet, String servletContextName,
469             ServletContext servletContext, ClassLoader portletClassLoader)
470         throws Exception {
471 
472         PortletConfig portletConfig = PortletConfigFactory.create(
473             portlet, servletContext);
474 
475         PortletContext portletContext = portletConfig.getPortletContext();
476 
477         PortletContextBag portletContextBag = new PortletContextBag(
478             servletContextName);
479 
480         PortletContextBagPool.put(servletContextName, portletContextBag);
481 
482         PortletApp portletApp = portlet.getPortletApp();
483 
484         Map<String, String> customUserAttributes =
485             portletApp.getCustomUserAttributes();
486 
487         for (Map.Entry<String, String> entry :
488                 customUserAttributes.entrySet()) {
489 
490             String attrCustomClass = entry.getValue();
491 
492             CustomUserAttributes customUserAttributesInstance =
493                 (CustomUserAttributes)portletClassLoader.loadClass(
494                     attrCustomClass).newInstance();
495 
496             portletContextBag.getCustomUserAttributes().put(
497                 attrCustomClass, customUserAttributesInstance);
498         }
499 
500         Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
501 
502         for (PortletFilter portletFilter : portletFilters) {
503             javax.portlet.filter.PortletFilter portletFilterInstance =
504                 (javax.portlet.filter.PortletFilter)newInstance(
505                     portletClassLoader,
506                     new Class<?>[] {
507                         javax.portlet.filter.ActionFilter.class,
508                         javax.portlet.filter.EventFilter.class,
509                         javax.portlet.filter.PortletFilter.class,
510                         javax.portlet.filter.RenderFilter.class,
511                         javax.portlet.filter.ResourceFilter.class
512                     },
513                     portletFilter.getFilterClass());
514 
515             portletContextBag.getPortletFilters().put(
516                 portletFilter.getFilterName(), portletFilterInstance);
517 
518             PortletFilterFactory.create(portletFilter, portletContext);
519         }
520 
521         Set<PortletURLListener> portletURLListeners =
522             portletApp.getPortletURLListeners();
523 
524         for (PortletURLListener portletURLListener : portletURLListeners) {
525             PortletURLGenerationListener portletURLListenerInstance =
526                 (PortletURLGenerationListener)newInstance(
527                     portletClassLoader, PortletURLGenerationListener.class,
528                     portletURLListener.getListenerClass());
529 
530             portletContextBag.getPortletURLListeners().put(
531                 portletURLListener.getListenerClass(),
532                 portletURLListenerInstance);
533 
534             PortletURLListenerFactory.create(portletURLListener);
535         }
536     }
537 
538     protected void processPortletProperties(
539             String servletContextName, ClassLoader portletClassLoader)
540         throws Exception {
541 
542         Configuration portletPropertiesConfiguration = null;
543 
544         try {
545             portletPropertiesConfiguration =
546                 ConfigurationFactoryUtil.getConfiguration(
547                     portletClassLoader, "portlet");
548         }
549         catch (Exception e) {
550             if (_log.isDebugEnabled()) {
551                 _log.debug("Unable to read portlet.properties");
552             }
553 
554             return;
555         }
556 
557         Properties portletProperties =
558             portletPropertiesConfiguration.getProperties();
559 
560         if (portletProperties.size() == 0) {
561             return;
562         }
563 
564         String languageBundleName = portletProperties.getProperty(
565             "language.bundle");
566 
567         if (Validator.isNotNull(languageBundleName)) {
568             Locale[] locales = LanguageUtil.getAvailableLocales();
569 
570             for (int i = 0; i < locales.length; i++) {
571                 ResourceBundle resourceBundle = ResourceBundle.getBundle(
572                     languageBundleName, locales[i], portletClassLoader);
573 
574                 PortletResourceBundles.put(
575                     servletContextName, LocaleUtil.toLanguageId(locales[i]),
576                     resourceBundle);
577             }
578         }
579 
580         String[] resourceActionConfigs = StringUtil.split(
581             portletProperties.getProperty("resource.actions.configs"));
582 
583         for (int i = 0; i < resourceActionConfigs.length; i++) {
584             ResourceActionsUtil.read(
585                 servletContextName, portletClassLoader,
586                 resourceActionConfigs[i]);
587         }
588     }
589 
590     private static Log _log = LogFactoryUtil.getLog(
591         PortletHotDeployListener.class);
592 
593     private static Map<String, ObjectValuePair<long[], List<Portlet>>> _vars =
594         new HashMap<String, ObjectValuePair<long[], List<Portlet>>>();
595 
596     private boolean _portletAppInitialized;
597     private boolean _strutsBridges;
598 
599 }