1   /**
2    * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.deploy.hot;
24  
25  import com.liferay.portal.apache.bridges.struts.LiferayServletContextProvider;
26  import com.liferay.portal.kernel.configuration.Configuration;
27  import com.liferay.portal.kernel.configuration.ConfigurationFactoryUtil;
28  import com.liferay.portal.kernel.deploy.hot.HotDeployEvent;
29  import com.liferay.portal.kernel.deploy.hot.HotDeployException;
30  import com.liferay.portal.kernel.job.Scheduler;
31  import com.liferay.portal.kernel.language.LanguageUtil;
32  import com.liferay.portal.kernel.pop.MessageListener;
33  import com.liferay.portal.kernel.portlet.ConfigurationAction;
34  import com.liferay.portal.kernel.portlet.FriendlyURLMapper;
35  import com.liferay.portal.kernel.portlet.PortletBag;
36  import com.liferay.portal.kernel.portlet.PortletBagPool;
37  import com.liferay.portal.kernel.portlet.PortletLayoutListener;
38  import com.liferay.portal.kernel.search.Indexer;
39  import com.liferay.portal.kernel.servlet.PortletServlet;
40  import com.liferay.portal.kernel.servlet.ServletContextProvider;
41  import com.liferay.portal.kernel.servlet.URLEncoder;
42  import com.liferay.portal.kernel.util.ClassUtil;
43  import com.liferay.portal.kernel.util.GetterUtil;
44  import com.liferay.portal.kernel.util.HttpUtil;
45  import com.liferay.portal.kernel.util.LocaleUtil;
46  import com.liferay.portal.kernel.util.ObjectValuePair;
47  import com.liferay.portal.kernel.util.StringUtil;
48  import com.liferay.portal.kernel.util.Validator;
49  import com.liferay.portal.lar.PortletDataHandler;
50  import com.liferay.portal.model.Portlet;
51  import com.liferay.portal.model.PortletApp;
52  import com.liferay.portal.model.PortletCategory;
53  import com.liferay.portal.model.PortletFilter;
54  import com.liferay.portal.model.PortletURLListener;
55  import com.liferay.portal.pop.POPServerUtil;
56  import com.liferay.portal.security.permission.ResourceActionsUtil;
57  import com.liferay.portal.service.PortletLocalServiceUtil;
58  import com.liferay.portal.util.Portal;
59  import com.liferay.portal.util.PortalInstances;
60  import com.liferay.portal.util.PropsValues;
61  import com.liferay.portal.util.WebAppPool;
62  import com.liferay.portal.util.WebKeys;
63  import com.liferay.portlet.CustomUserAttributes;
64  import com.liferay.portlet.PortletBagImpl;
65  import com.liferay.portlet.PortletConfigFactory;
66  import com.liferay.portlet.PortletContextBag;
67  import com.liferay.portlet.PortletContextBagPool;
68  import com.liferay.portlet.PortletFilterFactory;
69  import com.liferay.portlet.PortletInstanceFactory;
70  import com.liferay.portlet.PortletPreferencesSerializer;
71  import com.liferay.portlet.PortletResourceBundles;
72  import com.liferay.portlet.PortletURLListenerFactory;
73  import com.liferay.portlet.social.model.SocialActivityInterpreter;
74  import com.liferay.portlet.social.model.SocialRequestInterpreter;
75  import com.liferay.portlet.social.model.impl.SocialActivityInterpreterImpl;
76  import com.liferay.portlet.social.model.impl.SocialRequestInterpreterImpl;
77  import com.liferay.portlet.social.service.SocialActivityInterpreterLocalServiceUtil;
78  import com.liferay.portlet.social.service.SocialRequestInterpreterLocalServiceUtil;
79  
80  import java.util.HashMap;
81  import java.util.HashSet;
82  import java.util.Iterator;
83  import java.util.List;
84  import java.util.Locale;
85  import java.util.Map;
86  import java.util.MissingResourceException;
87  import java.util.Properties;
88  import java.util.ResourceBundle;
89  import java.util.Set;
90  
91  import javax.portlet.PortletConfig;
92  import javax.portlet.PortletContext;
93  import javax.portlet.PortletURLGenerationListener;
94  import javax.portlet.PreferencesValidator;
95  
96  import javax.servlet.ServletContext;
97  
98  import org.apache.commons.logging.Log;
99  import org.apache.commons.logging.LogFactory;
100 import org.apache.portals.bridges.struts.StrutsPortlet;
101 
102 /**
103  * <a href="PortletHotDeployListener.java.html"><b><i>View Source</i></b></a>
104  *
105  * @author Brian Wing Shun Chan
106  * @author Brian Myunghun Kim
107  * @author Ivica Cardic
108  *
109  */
110 public class PortletHotDeployListener extends BaseHotDeployListener {
111 
112     public void invokeDeploy(HotDeployEvent event) throws HotDeployException {
113         try {
114             doInvokeDeploy(event);
115         }
116         catch (Exception e) {
117             throwHotDeployException(
118                 event, "Error registering portlets for ", e);
119         }
120     }
121 
122     public void invokeUndeploy(HotDeployEvent event) throws HotDeployException {
123         try {
124             doInvokeUndeploy(event);
125         }
126         catch (Exception e) {
127             throwHotDeployException(
128                 event, "Error unregistering portlets for ", e);
129         }
130     }
131 
132     protected void destroyPortlet(Portlet portlet, Set<String> portletIds)
133         throws Exception {
134 
135         PortletApp portletApp = portlet.getPortletApp();
136 
137         Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
138 
139         for (PortletFilter portletFilter : portletFilters) {
140             PortletFilterFactory.destroy(portletFilter);
141         }
142 
143         Set<PortletURLListener> portletURLListeners =
144             portletApp.getPortletURLListeners();
145 
146         for (PortletURLListener portletURLListener : portletURLListeners) {
147             PortletURLListenerFactory.destroy(portletURLListener);
148         }
149 
150         Scheduler scheduler = portlet.getSchedulerInstance();
151 
152         if (scheduler != null) {
153             scheduler.unschedule();
154         }
155 
156         POPServerUtil.deleteListener(portlet.getPopMessageListenerInstance());
157 
158         SocialActivityInterpreterLocalServiceUtil.deleteActivityInterpreter(
159             portlet.getSocialActivityInterpreterInstance());
160 
161         SocialRequestInterpreterLocalServiceUtil.deleteRequestInterpreter(
162             portlet.getSocialRequestInterpreterInstance());
163 
164         PortletInstanceFactory.destroy(portlet);
165 
166         portletIds.add(portlet.getPortletId());
167     }
168 
169     protected void doInvokeDeploy(HotDeployEvent event) throws Exception {
170 
171         // Servlet context
172 
173         ServletContext servletContext = event.getServletContext();
174 
175         String servletContextName = servletContext.getServletContextName();
176 
177         if (_log.isDebugEnabled()) {
178             _log.debug("Invoking deploy for " + servletContextName);
179         }
180 
181         // Company ids
182 
183         long[] companyIds = PortalInstances.getCompanyIds();
184 
185         // Initialize portlets
186 
187         String[] xmls = new String[] {
188             HttpUtil.URLtoString(servletContext.getResource(
189                 "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_STANDARD)),
190             HttpUtil.URLtoString(servletContext.getResource(
191                 "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_CUSTOM)),
192             HttpUtil.URLtoString(servletContext.getResource(
193                 "/WEB-INF/liferay-portlet.xml")),
194             HttpUtil.URLtoString(servletContext.getResource("/WEB-INF/web.xml"))
195         };
196 
197         if (xmls[0] == null) {
198             return;
199         }
200 
201         if (_log.isInfoEnabled()) {
202             _log.info("Registering portlets for " + servletContextName);
203         }
204 
205         List<Portlet> portlets = PortletLocalServiceUtil.initWAR(
206             servletContextName, xmls, event.getPluginPackage());
207 
208         if (_log.isInfoEnabled()) {
209             _log.info(
210                 portlets.size() + " portlets for " + servletContextName +
211                     " are ready for registration");
212         }
213 
214         // Class loader
215 
216         ClassLoader portletClassLoader = event.getContextClassLoader();
217 
218         servletContext.setAttribute(
219             PortletServlet.PORTLET_CLASS_LOADER, portletClassLoader);
220 
221         // Portlet context wrapper
222 
223         _strutsBridges = false;
224 
225         Iterator<Portlet> portletsItr = portlets.iterator();
226 
227         while (portletsItr.hasNext()) {
228             Portlet portlet = portletsItr.next();
229 
230             initPortlet(
231                 portlet, servletContext, portletClassLoader, portletsItr);
232         }
233 
234         // Struts bridges
235 
236         if (!_strutsBridges) {
237             _strutsBridges = GetterUtil.getBoolean(
238                 servletContext.getInitParameter(
239                     "struts-bridges-context-provider"));
240         }
241 
242         if (_strutsBridges) {
243             servletContext.setAttribute(
244                 ServletContextProvider.STRUTS_BRIDGES_CONTEXT_PROVIDER,
245                 new LiferayServletContextProvider());
246         }
247 
248         // Portlet display
249 
250         String xml = HttpUtil.URLtoString(servletContext.getResource(
251             "/WEB-INF/liferay-display.xml"));
252 
253         PortletCategory newPortletCategory =
254             PortletLocalServiceUtil.getWARDisplay(servletContextName, xml);
255 
256         for (int i = 0; i < companyIds.length; i++) {
257             long companyId = companyIds[i];
258 
259             PortletCategory portletCategory =
260                 (PortletCategory)WebAppPool.get(
261                     String.valueOf(companyId), WebKeys.PORTLET_CATEGORY);
262 
263             if (portletCategory != null) {
264                 portletCategory.merge(newPortletCategory);
265             }
266             else {
267                 _log.error(
268                     "Unable to register portlet for company " + companyId +
269                         " because it does not exist");
270             }
271         }
272 
273         // Portlet properties
274 
275         processPortletProperties(servletContextName, portletClassLoader);
276 
277         // Variables
278 
279         _vars.put(
280             servletContextName,
281             new ObjectValuePair<long[], List<Portlet>>(
282                 companyIds, portlets));
283 
284         if (_log.isInfoEnabled()) {
285             _log.info(
286                 portlets.size() + " portlets for " + servletContextName +
287                     " registered successfully");
288         }
289     }
290 
291     protected void doInvokeUndeploy(HotDeployEvent event) throws Exception {
292         ServletContext servletContext = event.getServletContext();
293 
294         String servletContextName = servletContext.getServletContextName();
295 
296         if (_log.isDebugEnabled()) {
297             _log.debug("Invoking undeploy for " + servletContextName);
298         }
299 
300         ObjectValuePair<long[], List<Portlet>> ovp =
301             _vars.remove(servletContextName);
302 
303         if (ovp == null) {
304             return;
305         }
306 
307         long[] companyIds = ovp.getKey();
308         List<Portlet> portlets = ovp.getValue();
309 
310         Set<String> portletIds = new HashSet<String>();
311 
312         if (portlets != null) {
313             if (_log.isInfoEnabled()) {
314                 _log.info(
315                     "Unregistering portlets for " + servletContextName);
316             }
317 
318             Iterator<Portlet> itr = portlets.iterator();
319 
320             while (itr.hasNext()) {
321                 Portlet portlet = itr.next();
322 
323                 destroyPortlet(portlet, portletIds);
324             }
325         }
326 
327         if (portletIds.size() > 0) {
328             for (int i = 0; i < companyIds.length; i++) {
329                 long companyId = companyIds[i];
330 
331                 PortletCategory portletCategory =
332                     (PortletCategory)WebAppPool.get(
333                         String.valueOf(companyId), WebKeys.PORTLET_CATEGORY);
334 
335                 portletCategory.separate(portletIds);
336             }
337         }
338 
339         PortletResourceBundles.remove(servletContextName);
340 
341         if (_log.isInfoEnabled()) {
342             _log.info(
343                 portlets.size() + " portlets for " + servletContextName +
344                     " unregistered successfully");
345         }
346     }
347 
348     protected void initPortlet(
349             Portlet portlet, ServletContext servletContext,
350             ClassLoader portletClassLoader, Iterator<Portlet> portletsItr)
351         throws Exception {
352 
353         Class<?> portletClass = null;
354 
355         try {
356             portletClass = portletClassLoader.loadClass(
357                 portlet.getPortletClass());
358         }
359         catch (Exception e) {
360             _log.error(e, e);
361 
362             portletsItr.remove();
363 
364             PortletLocalServiceUtil.destroyPortlet(portlet);
365 
366             return;
367         }
368 
369         javax.portlet.Portlet portletInstance =
370             (javax.portlet.Portlet)portletClass.newInstance();
371 
372         if (ClassUtil.isSubclass(portletClass, StrutsPortlet.class.getName())) {
373             _strutsBridges = true;
374         }
375 
376         ConfigurationAction configurationActionInstance = null;
377 
378         if (Validator.isNotNull(portlet.getConfigurationActionClass())) {
379             configurationActionInstance =
380                 (ConfigurationAction)portletClassLoader.loadClass(
381                     portlet.getConfigurationActionClass()).newInstance();
382         }
383 
384         Indexer indexerInstance = null;
385 
386         if (Validator.isNotNull(portlet.getIndexerClass())) {
387             indexerInstance = (Indexer)portletClassLoader.loadClass(
388                 portlet.getIndexerClass()).newInstance();
389         }
390 
391         Scheduler schedulerInstance = null;
392 
393         if (PropsValues.SCHEDULER_ENABLED &&
394             Validator.isNotNull(portlet.getSchedulerClass())) {
395 
396             schedulerInstance = (Scheduler)portletClassLoader.loadClass(
397                 portlet.getSchedulerClass()).newInstance();
398 
399             schedulerInstance.schedule();
400         }
401 
402         FriendlyURLMapper friendlyURLMapperInstance = null;
403 
404         if (Validator.isNotNull(portlet.getFriendlyURLMapperClass())) {
405             friendlyURLMapperInstance =
406                 (FriendlyURLMapper)portletClassLoader.loadClass(
407                     portlet.getFriendlyURLMapperClass()).newInstance();
408         }
409 
410         URLEncoder urlEncoderInstance = null;
411 
412         if (Validator.isNotNull(portlet.getURLEncoderClass())) {
413             urlEncoderInstance = (URLEncoder)portletClassLoader.loadClass(
414                 portlet.getURLEncoderClass()).newInstance();
415         }
416 
417         PortletDataHandler portletDataHandlerInstance = null;
418 
419         if (Validator.isNotNull(portlet.getPortletDataHandlerClass())) {
420             portletDataHandlerInstance =
421                 (PortletDataHandler)portletClassLoader.loadClass(
422                     portlet.getPortletDataHandlerClass()).newInstance();
423         }
424 
425         PortletLayoutListener portletLayoutListenerInstance = null;
426 
427         if (Validator.isNotNull(portlet.getPortletLayoutListenerClass())) {
428             portletLayoutListenerInstance =
429                 (PortletLayoutListener)portletClassLoader.loadClass(
430                     portlet.getPortletLayoutListenerClass()).newInstance();
431         }
432 
433         MessageListener popMessageListenerInstance = null;
434 
435         if (Validator.isNotNull(portlet.getPopMessageListenerClass())) {
436             popMessageListenerInstance =
437                 (MessageListener)portletClassLoader.loadClass(
438                     portlet.getPopMessageListenerClass()).newInstance();
439 
440             POPServerUtil.addListener(popMessageListenerInstance);
441         }
442 
443         SocialActivityInterpreter socialActivityInterpreterInstance = null;
444 
445         if (Validator.isNotNull(portlet.getSocialActivityInterpreterClass())) {
446             socialActivityInterpreterInstance =
447                 (SocialActivityInterpreter)portletClassLoader.loadClass(
448                     portlet.getSocialActivityInterpreterClass()).newInstance();
449 
450             socialActivityInterpreterInstance =
451                 new SocialActivityInterpreterImpl(
452                     portlet.getPortletId(), socialActivityInterpreterInstance);
453 
454             SocialActivityInterpreterLocalServiceUtil.addActivityInterpreter(
455                 socialActivityInterpreterInstance);
456         }
457 
458         SocialRequestInterpreter socialRequestInterpreterInstance = null;
459 
460         if (Validator.isNotNull(portlet.getSocialRequestInterpreterClass())) {
461             socialRequestInterpreterInstance =
462                 (SocialRequestInterpreter)portletClassLoader.loadClass(
463                     portlet.getSocialRequestInterpreterClass()).newInstance();
464 
465             socialRequestInterpreterInstance = new SocialRequestInterpreterImpl(
466                 portlet.getPortletId(), socialRequestInterpreterInstance);
467 
468             SocialRequestInterpreterLocalServiceUtil.addRequestInterpreter(
469                 socialRequestInterpreterInstance);
470         }
471 
472         PreferencesValidator prefsValidatorInstance = null;
473 
474         if (Validator.isNotNull(portlet.getPreferencesValidator())) {
475             prefsValidatorInstance =
476                 (PreferencesValidator)portletClassLoader.loadClass(
477                     portlet.getPreferencesValidator()).newInstance();
478 
479             try {
480                 if (PropsValues.PREFERENCE_VALIDATE_ON_STARTUP) {
481                     prefsValidatorInstance.validate(
482                         PortletPreferencesSerializer.fromDefaultXML(
483                             portlet.getDefaultPreferences()));
484                 }
485             }
486             catch (Exception e) {
487                 _log.warn(
488                     "Portlet with the name " + portlet.getPortletId() +
489                         " does not have valid default preferences");
490             }
491         }
492 
493         Map<String, ResourceBundle> resourceBundles = null;
494 
495         if (Validator.isNotNull(portlet.getResourceBundle())) {
496             resourceBundles = new HashMap<String, ResourceBundle>();
497 
498             initResourceBundle(
499                 resourceBundles, portlet, portletClassLoader,
500                 LocaleUtil.getDefault());
501 
502             Iterator<String> supportLocalesItr =
503                 portlet.getSupportedLocales().iterator();
504 
505             while (supportLocalesItr.hasNext()) {
506                 String supportedLocale = supportLocalesItr.next();
507 
508                 Locale locale = LocaleUtil.fromLanguageId(supportedLocale);
509 
510                 initResourceBundle(
511                     resourceBundles, portlet, portletClassLoader, locale);
512             }
513         }
514 
515         PortletBag portletBag = new PortletBagImpl(
516             portlet.getPortletId(), servletContext, portletInstance,
517             configurationActionInstance, indexerInstance, schedulerInstance,
518             friendlyURLMapperInstance, urlEncoderInstance,
519             portletDataHandlerInstance, portletLayoutListenerInstance,
520             popMessageListenerInstance, socialActivityInterpreterInstance,
521             socialRequestInterpreterInstance, prefsValidatorInstance,
522             resourceBundles);
523 
524         PortletBagPool.put(portlet.getPortletId(), portletBag);
525 
526         if (!portletsItr.hasNext()) {
527             initPortletApp(portlet, servletContext, portletClassLoader);
528         }
529 
530         try {
531             PortletInstanceFactory.create(portlet, servletContext);
532         }
533         catch (Exception e) {
534             _log.error(e, e);
535         }
536     }
537 
538     protected void initPortletApp(
539             Portlet portlet, ServletContext servletContext,
540             ClassLoader portletClassLoader)
541         throws Exception {
542 
543         String servletContextName = servletContext.getServletContextName();
544 
545         PortletConfig portletConfig = PortletConfigFactory.create(
546             portlet, servletContext);
547 
548         PortletContext portletContext = portletConfig.getPortletContext();
549 
550         PortletContextBag portletContextBag = new PortletContextBag(
551             servletContextName);
552 
553         PortletContextBagPool.put(servletContextName, portletContextBag);
554 
555         PortletApp portletApp = portlet.getPortletApp();
556 
557         Map<String, String> customUserAttributes =
558             portletApp.getCustomUserAttributes();
559 
560         for (Map.Entry<String, String> entry :
561                 customUserAttributes.entrySet()) {
562 
563             String attrCustomClass = entry.getValue();
564 
565             CustomUserAttributes customUserAttributesInstance =
566                 (CustomUserAttributes)portletClassLoader.loadClass(
567                     attrCustomClass).newInstance();
568 
569             portletContextBag.getCustomUserAttributes().put(
570                 attrCustomClass, customUserAttributesInstance);
571         }
572 
573         Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
574 
575         for (PortletFilter portletFilter : portletFilters) {
576             javax.portlet.filter.PortletFilter portletFilterInstance =
577                 (javax.portlet.filter.PortletFilter)
578                     portletClassLoader.loadClass(
579                         portletFilter.getFilterClass()).newInstance();
580 
581             portletContextBag.getPortletFilters().put(
582                 portletFilter.getFilterName(), portletFilterInstance);
583 
584             PortletFilterFactory.create(portletFilter, portletContext);
585         }
586 
587         Set<PortletURLListener> portletURLListeners =
588             portletApp.getPortletURLListeners();
589 
590         for (PortletURLListener portletURLListener : portletURLListeners) {
591             PortletURLGenerationListener portletURLListenerInstance =
592                 (PortletURLGenerationListener)portletClassLoader.loadClass(
593                     portletURLListener.getListenerClass()).newInstance();
594 
595             portletContextBag.getPortletURLListeners().put(
596                 portletURLListener.getListenerClass(),
597                 portletURLListenerInstance);
598 
599             PortletURLListenerFactory.create(portletURLListener);
600         }
601     }
602 
603     protected void initResourceBundle(
604         Map<String, ResourceBundle> resourceBundles, Portlet portlet,
605         ClassLoader portletClassLoader, Locale locale) {
606 
607         try {
608             ResourceBundle resourceBundle = ResourceBundle.getBundle(
609                 portlet.getResourceBundle(), locale, portletClassLoader);
610 
611             resourceBundles.put(
612                 LocaleUtil.toLanguageId(locale), resourceBundle);
613         }
614         catch (MissingResourceException mre) {
615             _log.warn(mre.getMessage());
616         }
617     }
618 
619     protected void processPortletProperties(
620             String servletContextName, ClassLoader portletClassLoader)
621         throws Exception {
622 
623         Configuration portletPropertiesConfiguration = null;
624 
625         try {
626             portletPropertiesConfiguration =
627                 ConfigurationFactoryUtil.getConfiguration(
628                     portletClassLoader, "portlet");
629         }
630         catch (Exception e) {
631             if (_log.isDebugEnabled()) {
632                 _log.debug("Unable to read portlet.properties");
633             }
634 
635             return;
636         }
637 
638         Properties portletProperties =
639             portletPropertiesConfiguration.getProperties();
640 
641         if (portletProperties.size() == 0) {
642             return;
643         }
644 
645         String languageBundleName = portletProperties.getProperty(
646             "language.bundle");
647 
648         if (Validator.isNotNull(languageBundleName)) {
649             Locale[] locales = LanguageUtil.getAvailableLocales();
650 
651             for (int i = 0; i < locales.length; i++) {
652                 ResourceBundle bundle = ResourceBundle.getBundle(
653                     languageBundleName, locales[i], portletClassLoader);
654 
655                 PortletResourceBundles.put(
656                     servletContextName, LocaleUtil.toLanguageId(locales[i]),
657                     bundle);
658             }
659         }
660 
661         String[] resourceActionConfigs = StringUtil.split(
662             portletProperties.getProperty("resource.actions.configs"));
663 
664         for (int i = 0; i < resourceActionConfigs.length; i++) {
665             ResourceActionsUtil.read(
666                 servletContextName, portletClassLoader,
667                 resourceActionConfigs[i]);
668         }
669     }
670 
671     private static Log _log = LogFactory.getLog(PortletHotDeployListener.class);
672 
673     private static Map<String, ObjectValuePair<long[], List<Portlet>>> _vars =
674         new HashMap<String, ObjectValuePair<long[], List<Portlet>>>();
675 
676     private boolean _strutsBridges;
677 
678 }