001
014
015 package com.liferay.portal.deploy.hot;
016
017 import com.liferay.portal.apache.bridges.struts.LiferayServletContextProvider;
018 import com.liferay.portal.kernel.atom.AtomCollectionAdapter;
019 import com.liferay.portal.kernel.atom.AtomCollectionAdapterRegistryUtil;
020 import com.liferay.portal.kernel.configuration.Configuration;
021 import com.liferay.portal.kernel.configuration.ConfigurationFactoryUtil;
022 import com.liferay.portal.kernel.deploy.hot.BaseHotDeployListener;
023 import com.liferay.portal.kernel.deploy.hot.HotDeployEvent;
024 import com.liferay.portal.kernel.deploy.hot.HotDeployException;
025 import com.liferay.portal.kernel.javadoc.JavadocManagerUtil;
026 import com.liferay.portal.kernel.language.LanguageUtil;
027 import com.liferay.portal.kernel.lar.StagedModelDataHandler;
028 import com.liferay.portal.kernel.lar.StagedModelDataHandlerRegistryUtil;
029 import com.liferay.portal.kernel.log.Log;
030 import com.liferay.portal.kernel.log.LogFactoryUtil;
031 import com.liferay.portal.kernel.notifications.UserNotificationHandler;
032 import com.liferay.portal.kernel.notifications.UserNotificationManagerUtil;
033 import com.liferay.portal.kernel.portlet.PortletBag;
034 import com.liferay.portal.kernel.scheduler.SchedulerEngineHelperUtil;
035 import com.liferay.portal.kernel.scheduler.SchedulerEntry;
036 import com.liferay.portal.kernel.scheduler.StorageType;
037 import com.liferay.portal.kernel.search.Indexer;
038 import com.liferay.portal.kernel.search.IndexerRegistryUtil;
039 import com.liferay.portal.kernel.servlet.DirectServletRegistryUtil;
040 import com.liferay.portal.kernel.servlet.PortletServlet;
041 import com.liferay.portal.kernel.servlet.ServletContextPool;
042 import com.liferay.portal.kernel.servlet.ServletContextProvider;
043 import com.liferay.portal.kernel.trash.TrashHandler;
044 import com.liferay.portal.kernel.trash.TrashHandlerRegistryUtil;
045 import com.liferay.portal.kernel.util.ClassUtil;
046 import com.liferay.portal.kernel.util.GetterUtil;
047 import com.liferay.portal.kernel.util.HttpUtil;
048 import com.liferay.portal.kernel.util.InfrastructureUtil;
049 import com.liferay.portal.kernel.util.LocaleUtil;
050 import com.liferay.portal.kernel.util.PropsKeys;
051 import com.liferay.portal.kernel.util.ServerDetector;
052 import com.liferay.portal.kernel.util.StringUtil;
053 import com.liferay.portal.kernel.util.Validator;
054 import com.liferay.portal.kernel.webdav.WebDAVUtil;
055 import com.liferay.portal.kernel.workflow.WorkflowHandler;
056 import com.liferay.portal.kernel.workflow.WorkflowHandlerRegistryUtil;
057 import com.liferay.portal.model.Portlet;
058 import com.liferay.portal.model.PortletApp;
059 import com.liferay.portal.model.PortletCategory;
060 import com.liferay.portal.model.PortletFilter;
061 import com.liferay.portal.model.PortletURLListener;
062 import com.liferay.portal.poller.PollerProcessorUtil;
063 import com.liferay.portal.pop.POPServerUtil;
064 import com.liferay.portal.security.permission.ResourceActionsUtil;
065 import com.liferay.portal.service.PortletLocalServiceUtil;
066 import com.liferay.portal.service.ResourceActionLocalServiceUtil;
067 import com.liferay.portal.util.Portal;
068 import com.liferay.portal.util.PortalInstances;
069 import com.liferay.portal.util.PropsValues;
070 import com.liferay.portal.util.WebAppPool;
071 import com.liferay.portal.util.WebKeys;
072 import com.liferay.portal.xmlrpc.XmlRpcServlet;
073 import com.liferay.portlet.CustomUserAttributes;
074 import com.liferay.portlet.InvokerPortlet;
075 import com.liferay.portlet.PortletBagFactory;
076 import com.liferay.portlet.PortletContextBag;
077 import com.liferay.portlet.PortletContextBagPool;
078 import com.liferay.portlet.PortletFilterFactory;
079 import com.liferay.portlet.PortletInstanceFactoryUtil;
080 import com.liferay.portlet.PortletResourceBundles;
081 import com.liferay.portlet.PortletURLListenerFactory;
082 import com.liferay.portlet.asset.AssetRendererFactoryRegistryUtil;
083 import com.liferay.portlet.asset.model.AssetRendererFactory;
084 import com.liferay.portlet.social.model.SocialActivityInterpreter;
085 import com.liferay.portlet.social.service.SocialActivityInterpreterLocalServiceUtil;
086 import com.liferay.portlet.social.service.SocialRequestInterpreterLocalServiceUtil;
087 import com.liferay.util.bridges.php.PHPPortlet;
088
089 import java.util.HashMap;
090 import java.util.HashSet;
091 import java.util.Iterator;
092 import java.util.List;
093 import java.util.Locale;
094 import java.util.Map;
095 import java.util.Properties;
096 import java.util.ResourceBundle;
097 import java.util.Set;
098
099 import javax.naming.Context;
100 import javax.naming.InitialContext;
101 import javax.naming.NamingException;
102
103 import javax.portlet.PortletURLGenerationListener;
104
105 import javax.servlet.ServletContext;
106
107 import javax.sql.DataSource;
108
109 import org.apache.portals.bridges.struts.StrutsPortlet;
110
111
117 public class PortletHotDeployListener extends BaseHotDeployListener {
118
119 @Override
120 public void invokeDeploy(HotDeployEvent hotDeployEvent)
121 throws HotDeployException {
122
123 try {
124 doInvokeDeploy(hotDeployEvent);
125 }
126 catch (Throwable t) {
127 throwHotDeployException(
128 hotDeployEvent, "Error registering portlets for ", t);
129 }
130 }
131
132 @Override
133 public void invokeUndeploy(HotDeployEvent hotDeployEvent)
134 throws HotDeployException {
135
136 try {
137 doInvokeUndeploy(hotDeployEvent);
138 }
139 catch (Throwable t) {
140 throwHotDeployException(
141 hotDeployEvent, "Error unregistering portlets for ", t);
142 }
143 }
144
145 protected void bindDataSource(String servletContextName) throws Exception {
146 if (ServerDetector.isGlassfish() || ServerDetector.isJOnAS()) {
147 return;
148 }
149
150 if (_log.isDebugEnabled()) {
151 _log.debug("Dynamically binding the Liferay data source");
152 }
153
154 DataSource dataSource = InfrastructureUtil.getDataSource();
155
156 if (dataSource == null) {
157 if (_log.isDebugEnabled()) {
158 _log.debug(
159 "Abort dynamically binding the Liferay data source " +
160 "because it is not available");
161 }
162
163 return;
164 }
165
166 Context context = new InitialContext();
167
168 try {
169 try {
170 context.lookup(_JNDI_JDBC);
171 }
172 catch (NamingException ne) {
173 context.createSubcontext(_JNDI_JDBC);
174 }
175
176 try {
177 context.lookup(_JNDI_JDBC_LIFERAY_POOL);
178 }
179 catch (NamingException ne) {
180 context.bind(_JNDI_JDBC_LIFERAY_POOL, dataSource);
181 }
182
183 _dataSourceBindStates.put(servletContextName, true);
184 }
185 catch (Exception e) {
186 if (_log.isWarnEnabled()) {
187 _log.warn(
188 "Unable to dynamically bind the Liferay data source: " +
189 e.getMessage());
190 }
191 }
192 }
193
194 protected void destroyPortlet(Portlet portlet, Set<String> portletIds)
195 throws Exception {
196
197 PortletApp portletApp = portlet.getPortletApp();
198
199 Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
200
201 for (PortletFilter portletFilter : portletFilters) {
202 PortletFilterFactory.destroy(portletFilter);
203 }
204
205 Set<PortletURLListener> portletURLListeners =
206 portletApp.getPortletURLListeners();
207
208 for (PortletURLListener portletURLListener : portletURLListeners) {
209 PortletURLListenerFactory.destroy(portletURLListener);
210 }
211
212 List<Indexer> indexers = portlet.getIndexerInstances();
213
214 for (Indexer indexer : indexers) {
215 IndexerRegistryUtil.unregister(indexer);
216 }
217
218 if (PropsValues.SCHEDULER_ENABLED) {
219 List<SchedulerEntry> schedulerEntries =
220 portlet.getSchedulerEntries();
221
222 if ((schedulerEntries != null) && !schedulerEntries.isEmpty()) {
223 for (SchedulerEntry schedulerEntry : schedulerEntries) {
224 SchedulerEngineHelperUtil.unschedule(
225 schedulerEntry, StorageType.MEMORY_CLUSTERED);
226 }
227 }
228 }
229
230 List<StagedModelDataHandler<?>> stagedModelDataHandlers =
231 portlet.getStagedModelDataHandlerInstances();
232
233 if (stagedModelDataHandlers != null) {
234 StagedModelDataHandlerRegistryUtil.unregister(
235 stagedModelDataHandlers);
236 }
237
238 PollerProcessorUtil.deletePollerProcessor(portlet.getPortletId());
239
240 POPServerUtil.deleteListener(portlet.getPopMessageListenerInstance());
241
242 List<SocialActivityInterpreter> socialActivityInterpreters =
243 portlet.getSocialActivityInterpreterInstances();
244
245 if (socialActivityInterpreters != null) {
246 for (SocialActivityInterpreter socialActivityInterpreter :
247 socialActivityInterpreters) {
248
249 SocialActivityInterpreterLocalServiceUtil.
250 deleteActivityInterpreter(socialActivityInterpreter);
251 }
252 }
253
254 SocialRequestInterpreterLocalServiceUtil.deleteRequestInterpreter(
255 portlet.getSocialRequestInterpreterInstance());
256
257 UserNotificationManagerUtil.deleteUserNotificationDefinitions(
258 portlet.getPortletId());
259
260 List<UserNotificationHandler> userNotificationHandlers =
261 portlet.getUserNotificationHandlerInstances();
262
263 if (userNotificationHandlers != null) {
264 for (UserNotificationHandler userNotificationHandler :
265 userNotificationHandlers) {
266
267 UserNotificationManagerUtil.deleteUserNotificationHandler(
268 userNotificationHandler);
269 }
270 }
271
272 WebDAVUtil.deleteStorage(portlet.getWebDAVStorageInstance());
273
274 XmlRpcServlet.unregisterMethod(portlet.getXmlRpcMethodInstance());
275
276 List<AssetRendererFactory> assetRendererFactories =
277 portlet.getAssetRendererFactoryInstances();
278
279 if (assetRendererFactories != null) {
280 AssetRendererFactoryRegistryUtil.unregister(assetRendererFactories);
281 }
282
283 List<AtomCollectionAdapter<?>> atomCollectionAdapters =
284 portlet.getAtomCollectionAdapterInstances();
285
286 if (atomCollectionAdapters != null) {
287 AtomCollectionAdapterRegistryUtil.unregister(
288 atomCollectionAdapters);
289 }
290
291 List<TrashHandler> trashHandlers = portlet.getTrashHandlerInstances();
292
293 if (trashHandlers != null) {
294 TrashHandlerRegistryUtil.unregister(trashHandlers);
295 }
296
297 List<WorkflowHandler> workflowHandlers =
298 portlet.getWorkflowHandlerInstances();
299
300 if (workflowHandlers != null) {
301 WorkflowHandlerRegistryUtil.unregister(workflowHandlers);
302 }
303
304 PortletInstanceFactoryUtil.destroy(portlet);
305
306 portletIds.add(portlet.getPortletId());
307 }
308
309 protected void doInvokeDeploy(HotDeployEvent hotDeployEvent)
310 throws Exception {
311
312 ServletContext servletContext = hotDeployEvent.getServletContext();
313
314 String servletContextName = servletContext.getServletContextName();
315
316 if (_log.isDebugEnabled()) {
317 _log.debug("Invoking deploy for " + servletContextName);
318 }
319
320 String[] xmls = new String[] {
321 HttpUtil.URLtoString(
322 servletContext.getResource(
323 "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_STANDARD)),
324 HttpUtil.URLtoString(
325 servletContext.getResource(
326 "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_CUSTOM)),
327 HttpUtil.URLtoString(
328 servletContext.getResource("/WEB-INF/liferay-portlet.xml")),
329 HttpUtil.URLtoString(servletContext.getResource("/WEB-INF/web.xml"))
330 };
331
332 if ((xmls[0] == null) && (xmls[1] == null)) {
333 return;
334 }
335
336 if (_log.isInfoEnabled()) {
337 _log.info("Registering portlets for " + servletContextName);
338 }
339
340 List<Portlet> portlets = PortletLocalServiceUtil.initWAR(
341 servletContextName, servletContext, xmls,
342 hotDeployEvent.getPluginPackage());
343
344 boolean portletAppInitialized = false;
345
346 boolean phpPortlet = false;
347 boolean strutsBridges = false;
348
349 PortletBagFactory portletBagFactory = new PortletBagFactory();
350
351 ClassLoader classLoader = hotDeployEvent.getContextClassLoader();
352
353 portletBagFactory.setClassLoader(classLoader);
354
355 portletBagFactory.setServletContext(servletContext);
356 portletBagFactory.setWARFile(true);
357
358 Iterator<Portlet> itr = portlets.iterator();
359
360 while (itr.hasNext()) {
361 Portlet portlet = itr.next();
362
363 PortletBag portletBag = portletBagFactory.create(portlet);
364
365 if (portletBag == null) {
366 itr.remove();
367 }
368 else {
369 if (!portletAppInitialized) {
370 initPortletApp(
371 servletContextName, servletContext, classLoader,
372 portlet);
373
374 portletAppInitialized = true;
375 }
376
377 javax.portlet.Portlet portletInstance =
378 portletBag.getPortletInstance();
379
380 if (ClassUtil.isSubclass(
381 portletInstance.getClass(),
382 PHPPortlet.class.getName())) {
383
384 phpPortlet = true;
385
386 }
387
388 if (ClassUtil.isSubclass(
389 portletInstance.getClass(),
390 StrutsPortlet.class.getName())) {
391
392 strutsBridges = true;
393 }
394 }
395 }
396
397 if (phpPortlet) {
398 bindDataSource(servletContextName);
399 }
400
401 if (!strutsBridges) {
402 strutsBridges = GetterUtil.getBoolean(
403 servletContext.getInitParameter(
404 "struts-bridges-context-provider"));
405 }
406
407 if (strutsBridges) {
408 servletContext.setAttribute(
409 ServletContextProvider.STRUTS_BRIDGES_CONTEXT_PROVIDER,
410 new LiferayServletContextProvider());
411 }
412
413 String xml = HttpUtil.URLtoString(
414 servletContext.getResource("/WEB-INF/liferay-display.xml"));
415
416 PortletCategory newPortletCategory =
417 PortletLocalServiceUtil.getWARDisplay(servletContextName, xml);
418
419 long[] companyIds = PortalInstances.getCompanyIds();
420
421 for (long companyId : companyIds) {
422 PortletCategory portletCategory = (PortletCategory)WebAppPool.get(
423 companyId, WebKeys.PORTLET_CATEGORY);
424
425 if (portletCategory != null) {
426 portletCategory.merge(newPortletCategory);
427 }
428 else {
429 _log.error(
430 "Unable to register portlet for company " + companyId +
431 " because it does not exist");
432 }
433 }
434
435 processPortletProperties(servletContextName, classLoader);
436
437 for (Portlet portlet : portlets) {
438 List<String> modelNames =
439 ResourceActionsUtil.getPortletModelResources(
440 portlet.getPortletId());
441
442 List<String> portletActions =
443 ResourceActionsUtil.getPortletResourceActions(
444 portlet.getPortletId());
445
446 ResourceActionLocalServiceUtil.checkResourceActions(
447 portlet.getPortletId(), portletActions);
448
449 for (String modelName : modelNames) {
450 List<String> modelActions =
451 ResourceActionsUtil.getModelResourceActions(modelName);
452
453 ResourceActionLocalServiceUtil.checkResourceActions(
454 modelName, modelActions);
455 }
456
457 for (long companyId : companyIds) {
458 Portlet curPortlet = PortletLocalServiceUtil.getPortletById(
459 companyId, portlet.getPortletId());
460
461 PortletLocalServiceUtil.checkPortlet(curPortlet);
462 }
463 }
464
465 for (Portlet portlet : portlets) {
466 boolean ready = GetterUtil.getBoolean(
467 servletContext.getInitParameter(
468 "portlets-ready-by-default"), true);
469
470 portlet.setReady(ready);
471 }
472
473 registerClpMessageListeners(servletContext, classLoader);
474
475 JavadocManagerUtil.load(servletContextName, classLoader);
476
477 DirectServletRegistryUtil.clearServlets();
478
479 _portlets.put(servletContextName, portlets);
480
481 servletContext.setAttribute(WebKeys.PLUGIN_PORTLETS, portlets);
482
483 if (_log.isInfoEnabled()) {
484 if (portlets.size() == 1) {
485 _log.info(
486 "1 portlet for " + servletContextName +
487 " is available for use");
488 }
489 else {
490 _log.info(
491 portlets.size() + " portlets for " + servletContextName +
492 " are available for use");
493 }
494 }
495 }
496
497 protected void doInvokeUndeploy(HotDeployEvent hotDeployEvent)
498 throws Exception {
499
500 ServletContext servletContext = hotDeployEvent.getServletContext();
501
502 String servletContextName = servletContext.getServletContextName();
503
504 if (_log.isDebugEnabled()) {
505 _log.debug("Invoking undeploy for " + servletContextName);
506 }
507
508 List<Portlet> portlets = _portlets.remove(servletContextName);
509
510 if (portlets == null) {
511 return;
512 }
513
514 Set<String> portletIds = new HashSet<String>();
515
516 if (portlets != null) {
517 if (_log.isInfoEnabled()) {
518 _log.info("Unregistering portlets for " + servletContextName);
519 }
520
521 for (Portlet portlet : portlets) {
522 destroyPortlet(portlet, portletIds);
523 }
524 }
525
526 ServletContextPool.remove(servletContextName);
527
528 if (!portletIds.isEmpty()) {
529 long[] companyIds = PortalInstances.getCompanyIds();
530
531 for (long companyId : companyIds) {
532 PortletCategory portletCategory =
533 (PortletCategory)WebAppPool.get(
534 companyId, WebKeys.PORTLET_CATEGORY);
535
536 portletCategory.separate(portletIds);
537 }
538 }
539
540 PortletContextBagPool.remove(servletContextName);
541 PortletResourceBundles.remove(servletContextName);
542
543 unbindDataSource(servletContextName);
544
545 unregisterClpMessageListeners(servletContext);
546
547 JavadocManagerUtil.unload(servletContextName);
548
549 DirectServletRegistryUtil.clearServlets();
550
551 if (_log.isInfoEnabled()) {
552 if (portlets.size() == 1) {
553 _log.info(
554 "1 portlet for " + servletContextName +
555 " was unregistered");
556 }
557 else {
558 _log.info(
559 portlets.size() + " portlets for " + servletContextName +
560 " was unregistered");
561 }
562 }
563 }
564
565 protected void initPortletApp(
566 String servletContextName, ServletContext servletContext,
567 ClassLoader classLoader, Portlet portlet)
568 throws Exception {
569
570 PortletContextBag portletContextBag = new PortletContextBag(
571 servletContextName);
572
573 PortletContextBagPool.put(servletContextName, portletContextBag);
574
575 PortletApp portletApp = portlet.getPortletApp();
576
577 servletContext.setAttribute(PortletServlet.PORTLET_APP, portletApp);
578
579 Map<String, String> customUserAttributes =
580 portletApp.getCustomUserAttributes();
581
582 for (Map.Entry<String, String> entry :
583 customUserAttributes.entrySet()) {
584
585 String attrCustomClass = entry.getValue();
586
587 CustomUserAttributes customUserAttributesInstance =
588 (CustomUserAttributes)classLoader.loadClass(
589 attrCustomClass).newInstance();
590
591 portletContextBag.getCustomUserAttributes().put(
592 attrCustomClass, customUserAttributesInstance);
593 }
594
595 Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
596
597 for (PortletFilter portletFilter : portletFilters) {
598 javax.portlet.filter.PortletFilter portletFilterInstance =
599 (javax.portlet.filter.PortletFilter)newInstance(
600 classLoader,
601 new Class<?>[] {
602 javax.portlet.filter.ActionFilter.class,
603 javax.portlet.filter.EventFilter.class,
604 javax.portlet.filter.PortletFilter.class,
605 javax.portlet.filter.RenderFilter.class,
606 javax.portlet.filter.ResourceFilter.class
607 },
608 portletFilter.getFilterClass());
609
610 portletContextBag.getPortletFilters().put(
611 portletFilter.getFilterName(), portletFilterInstance);
612 }
613
614 InvokerPortlet invokerPortlet = PortletInstanceFactoryUtil.create(
615 portlet, servletContext);
616
617 invokerPortlet.setPortletFilters();
618
619 Set<PortletURLListener> portletURLListeners =
620 portletApp.getPortletURLListeners();
621
622 for (PortletURLListener portletURLListener : portletURLListeners) {
623 PortletURLGenerationListener portletURLListenerInstance =
624 (PortletURLGenerationListener)newInstance(
625 classLoader, PortletURLGenerationListener.class,
626 portletURLListener.getListenerClass());
627
628 portletContextBag.getPortletURLListeners().put(
629 portletURLListener.getListenerClass(),
630 portletURLListenerInstance);
631
632 PortletURLListenerFactory.create(portletURLListener);
633 }
634 }
635
636 protected void processPortletProperties(
637 String servletContextName, ClassLoader classLoader)
638 throws Exception {
639
640 Configuration portletPropertiesConfiguration = null;
641
642 try {
643 portletPropertiesConfiguration =
644 ConfigurationFactoryUtil.getConfiguration(
645 classLoader, "portlet");
646 }
647 catch (Exception e) {
648 if (_log.isDebugEnabled()) {
649 _log.debug("Unable to read portlet.properties");
650 }
651
652 return;
653 }
654
655 Properties portletProperties =
656 portletPropertiesConfiguration.getProperties();
657
658 if (portletProperties.size() == 0) {
659 return;
660 }
661
662 String languageBundleName = portletProperties.getProperty(
663 "language.bundle");
664
665 if (Validator.isNotNull(languageBundleName)) {
666 Locale[] locales = LanguageUtil.getAvailableLocales();
667
668 for (Locale locale : locales) {
669 ResourceBundle resourceBundle = ResourceBundle.getBundle(
670 languageBundleName, locale, classLoader);
671
672 PortletResourceBundles.put(
673 servletContextName, LocaleUtil.toLanguageId(locale),
674 resourceBundle);
675 }
676 }
677
678 String[] resourceActionConfigs = StringUtil.split(
679 portletProperties.getProperty(PropsKeys.RESOURCE_ACTIONS_CONFIGS));
680
681 for (String resourceActionConfig : resourceActionConfigs) {
682 ResourceActionsUtil.read(
683 servletContextName, classLoader, resourceActionConfig);
684 }
685 }
686
687 protected void unbindDataSource(String servletContextName) {
688 Boolean dataSourceBindState = _dataSourceBindStates.remove(
689 servletContextName);
690
691 if (dataSourceBindState == null) {
692 return;
693 }
694
695 try {
696 if (_log.isDebugEnabled()) {
697 _log.debug("Dynamically unbinding the Liferay data source");
698 }
699
700 Context context = new InitialContext();
701
702 try {
703 context.lookup(_JNDI_JDBC_LIFERAY_POOL);
704
705 context.unbind(_JNDI_JDBC_LIFERAY_POOL);
706 }
707 catch (NamingException ne) {
708 }
709
710 try {
711 context.lookup(_JNDI_JDBC);
712
713 context.destroySubcontext(_JNDI_JDBC);
714 }
715 catch (NamingException ne) {
716 }
717 }
718 catch (Exception e) {
719 if (_log.isWarnEnabled()) {
720 _log.warn(
721 "Unable to dynamically unbind the Liferay data source: " +
722 e.getMessage());
723 }
724 }
725 }
726
727 private static final String _JNDI_JDBC = "java_liferay:jdbc";
728
729 private static final String _JNDI_JDBC_LIFERAY_POOL =
730 _JNDI_JDBC + "/LiferayPool";
731
732 private static Log _log = LogFactoryUtil.getLog(
733 PortletHotDeployListener.class);
734
735 private static Map<String, Boolean> _dataSourceBindStates =
736 new HashMap<String, Boolean>();
737 private static Map<String, List<Portlet>> _portlets =
738 new HashMap<String, List<Portlet>>();
739
740 }