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