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