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 if (ClassUtil.isSubclass(
388 portletInstance.getClass(),
389 StrutsPortlet.class.getName())) {
390
391 strutsBridges = true;
392 }
393 }
394 }
395
396 if (phpPortlet) {
397 bindDataSource(servletContextName);
398 }
399
400 if (!strutsBridges) {
401 strutsBridges = GetterUtil.getBoolean(
402 servletContext.getInitParameter(
403 "struts-bridges-context-provider"));
404 }
405
406 if (strutsBridges) {
407 servletContext.setAttribute(
408 ServletContextProvider.STRUTS_BRIDGES_CONTEXT_PROVIDER,
409 new LiferayServletContextProvider());
410 }
411
412 String xml = HttpUtil.URLtoString(
413 servletContext.getResource("/WEB-INF/liferay-display.xml"));
414
415 PortletCategory newPortletCategory =
416 PortletLocalServiceUtil.getWARDisplay(servletContextName, xml);
417
418 long[] companyIds = PortalInstances.getCompanyIds();
419
420 for (long companyId : companyIds) {
421 PortletCategory portletCategory = (PortletCategory)WebAppPool.get(
422 companyId, WebKeys.PORTLET_CATEGORY);
423
424 if (portletCategory != null) {
425 portletCategory.merge(newPortletCategory);
426 }
427 else {
428 _log.error(
429 "Unable to register portlet for company " + companyId +
430 " because it does not exist");
431 }
432 }
433
434 processPortletProperties(servletContextName, classLoader);
435
436 for (Portlet portlet : portlets) {
437 List<String> modelNames =
438 ResourceActionsUtil.getPortletModelResources(
439 portlet.getPortletId());
440
441 List<String> portletActions =
442 ResourceActionsUtil.getPortletResourceActions(
443 portlet.getPortletId());
444
445 ResourceActionLocalServiceUtil.checkResourceActions(
446 portlet.getPortletId(), portletActions);
447
448 for (String modelName : modelNames) {
449 List<String> modelActions =
450 ResourceActionsUtil.getModelResourceActions(modelName);
451
452 ResourceActionLocalServiceUtil.checkResourceActions(
453 modelName, modelActions);
454 }
455
456 for (long companyId : companyIds) {
457 Portlet curPortlet = PortletLocalServiceUtil.getPortletById(
458 companyId, portlet.getPortletId());
459
460 PortletLocalServiceUtil.checkPortlet(curPortlet);
461 }
462 }
463
464 for (Portlet portlet : portlets) {
465 boolean ready = GetterUtil.getBoolean(
466 servletContext.getInitParameter(
467 "portlets-ready-by-default"), true);
468
469 portlet.setReady(ready);
470 }
471
472 registerClpMessageListeners(servletContext, classLoader);
473
474 JavadocManagerUtil.load(servletContextName, classLoader);
475
476 DirectServletRegistryUtil.clearServlets();
477
478 _portlets.put(servletContextName, portlets);
479
480 servletContext.setAttribute(WebKeys.PLUGIN_PORTLETS, portlets);
481
482 if (_log.isInfoEnabled()) {
483 if (portlets.size() == 1) {
484 _log.info(
485 "1 portlet for " + servletContextName +
486 " is available for use");
487 }
488 else {
489 _log.info(
490 portlets.size() + " portlets for " + servletContextName +
491 " are available for use");
492 }
493 }
494 }
495
496 protected void doInvokeUndeploy(HotDeployEvent hotDeployEvent)
497 throws Exception {
498
499 ServletContext servletContext = hotDeployEvent.getServletContext();
500
501 String servletContextName = servletContext.getServletContextName();
502
503 if (_log.isDebugEnabled()) {
504 _log.debug("Invoking undeploy for " + servletContextName);
505 }
506
507 List<Portlet> portlets = _portlets.remove(servletContextName);
508
509 if (portlets == null) {
510 return;
511 }
512
513 Set<String> portletIds = new HashSet<String>();
514
515 if (portlets != null) {
516 if (_log.isInfoEnabled()) {
517 _log.info("Unregistering portlets for " + servletContextName);
518 }
519
520 for (Portlet portlet : portlets) {
521 destroyPortlet(portlet, portletIds);
522 }
523 }
524
525 ServletContextPool.remove(servletContextName);
526
527 if (!portletIds.isEmpty()) {
528 long[] companyIds = PortalInstances.getCompanyIds();
529
530 for (long companyId : companyIds) {
531 PortletCategory portletCategory =
532 (PortletCategory)WebAppPool.get(
533 companyId, WebKeys.PORTLET_CATEGORY);
534
535 portletCategory.separate(portletIds);
536 }
537 }
538
539 PortletContextBagPool.remove(servletContextName);
540 PortletResourceBundles.remove(servletContextName);
541
542 unbindDataSource(servletContextName);
543
544 unregisterClpMessageListeners(servletContext);
545
546 JavadocManagerUtil.unload(servletContextName);
547
548 DirectServletRegistryUtil.clearServlets();
549
550 if (_log.isInfoEnabled()) {
551 if (portlets.size() == 1) {
552 _log.info(
553 "1 portlet for " + servletContextName +
554 " was unregistered");
555 }
556 else {
557 _log.info(
558 portlets.size() + " portlets for " + servletContextName +
559 " were unregistered");
560 }
561 }
562 }
563
564 protected void initPortletApp(
565 String servletContextName, ServletContext servletContext,
566 ClassLoader classLoader, Portlet portlet)
567 throws Exception {
568
569 PortletContextBag portletContextBag = new PortletContextBag(
570 servletContextName);
571
572 PortletContextBagPool.put(servletContextName, portletContextBag);
573
574 PortletApp portletApp = portlet.getPortletApp();
575
576 servletContext.setAttribute(PortletServlet.PORTLET_APP, portletApp);
577
578 Map<String, String> customUserAttributes =
579 portletApp.getCustomUserAttributes();
580
581 for (Map.Entry<String, String> entry :
582 customUserAttributes.entrySet()) {
583
584 String attrCustomClass = entry.getValue();
585
586 CustomUserAttributes customUserAttributesInstance =
587 (CustomUserAttributes)classLoader.loadClass(
588 attrCustomClass).newInstance();
589
590 portletContextBag.getCustomUserAttributes().put(
591 attrCustomClass, customUserAttributesInstance);
592 }
593
594 Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
595
596 for (PortletFilter portletFilter : portletFilters) {
597 javax.portlet.filter.PortletFilter portletFilterInstance =
598 (javax.portlet.filter.PortletFilter)newInstance(
599 classLoader,
600 new Class<?>[] {
601 javax.portlet.filter.ActionFilter.class,
602 javax.portlet.filter.EventFilter.class,
603 javax.portlet.filter.PortletFilter.class,
604 javax.portlet.filter.RenderFilter.class,
605 javax.portlet.filter.ResourceFilter.class
606 },
607 portletFilter.getFilterClass());
608
609 portletContextBag.getPortletFilters().put(
610 portletFilter.getFilterName(), portletFilterInstance);
611 }
612
613 InvokerPortlet invokerPortlet = PortletInstanceFactoryUtil.create(
614 portlet, servletContext);
615
616 invokerPortlet.setPortletFilters();
617
618 Set<PortletURLListener> portletURLListeners =
619 portletApp.getPortletURLListeners();
620
621 for (PortletURLListener portletURLListener : portletURLListeners) {
622 PortletURLGenerationListener portletURLListenerInstance =
623 (PortletURLGenerationListener)newInstance(
624 classLoader, PortletURLGenerationListener.class,
625 portletURLListener.getListenerClass());
626
627 portletContextBag.getPortletURLListeners().put(
628 portletURLListener.getListenerClass(),
629 portletURLListenerInstance);
630
631 PortletURLListenerFactory.create(portletURLListener);
632 }
633 }
634
635 protected void processPortletProperties(
636 String servletContextName, ClassLoader classLoader)
637 throws Exception {
638
639 Configuration portletPropertiesConfiguration = null;
640
641 try {
642 portletPropertiesConfiguration =
643 ConfigurationFactoryUtil.getConfiguration(
644 classLoader, "portlet");
645 }
646 catch (Exception e) {
647 if (_log.isDebugEnabled()) {
648 _log.debug("Unable to read portlet.properties");
649 }
650
651 return;
652 }
653
654 Properties portletProperties =
655 portletPropertiesConfiguration.getProperties();
656
657 if (portletProperties.size() == 0) {
658 return;
659 }
660
661 String languageBundleName = portletProperties.getProperty(
662 "language.bundle");
663
664 if (Validator.isNotNull(languageBundleName)) {
665 Locale[] locales = LanguageUtil.getAvailableLocales();
666
667 for (Locale locale : locales) {
668 ResourceBundle resourceBundle = ResourceBundle.getBundle(
669 languageBundleName, locale, classLoader);
670
671 PortletResourceBundles.put(
672 servletContextName, LocaleUtil.toLanguageId(locale),
673 resourceBundle);
674 }
675 }
676
677 String[] resourceActionConfigs = StringUtil.split(
678 portletProperties.getProperty(PropsKeys.RESOURCE_ACTIONS_CONFIGS));
679
680 for (String resourceActionConfig : resourceActionConfigs) {
681 ResourceActionsUtil.read(
682 servletContextName, classLoader, resourceActionConfig);
683 }
684 }
685
686 protected void unbindDataSource(String servletContextName) {
687 Boolean dataSourceBindState = _dataSourceBindStates.remove(
688 servletContextName);
689
690 if (dataSourceBindState == null) {
691 return;
692 }
693
694 try {
695 if (_log.isDebugEnabled()) {
696 _log.debug("Dynamically unbinding the Liferay data source");
697 }
698
699 Context context = new InitialContext();
700
701 try {
702 context.lookup(_JNDI_JDBC_LIFERAY_POOL);
703
704 context.unbind(_JNDI_JDBC_LIFERAY_POOL);
705 }
706 catch (NamingException ne) {
707 }
708
709 try {
710 context.lookup(_JNDI_JDBC);
711
712 context.destroySubcontext(_JNDI_JDBC);
713 }
714 catch (NamingException ne) {
715 }
716 }
717 catch (Exception e) {
718 if (_log.isWarnEnabled()) {
719 _log.warn(
720 "Unable to dynamically unbind the Liferay data source: " +
721 e.getMessage());
722 }
723 }
724 }
725
726 private static final String _JNDI_JDBC = "java_liferay:jdbc";
727
728 private static final String _JNDI_JDBC_LIFERAY_POOL =
729 _JNDI_JDBC + "/LiferayPool";
730
731 private static Log _log = LogFactoryUtil.getLog(
732 PortletHotDeployListener.class);
733
734 private static Map<String, Boolean> _dataSourceBindStates =
735 new HashMap<String, Boolean>();
736 private static Map<String, List<Portlet>> _portlets =
737 new HashMap<String, List<Portlet>>();
738
739 }