Portal开源实现-Liferay的Portlet Session处理

一、规范中的SESSION描述

(PortletSession objects must be scoped at the portlet application context level. Each portlet application has its own distinct PortletSession object per user session. The portlet container must not share the PortletSession object or the attributes stored in it among different portlet applications or among different user sessions.)
上面这 段话是portlet规范里的一段。很明白的可以看出,每个Portlet Application应该在Process Action和Render的时候应该拥有自己私有的Session对象,来为当前用户服务。也就是说,如果某一个用户在一个PORTAL系统中操作不同 的PORTLET,而且这些PORTLET属于不同的PORTLET APPLICATION,则,这个用户将操作多个SESSION对象,用户在每个PORTLET中操作SESSION时,这个SESSION都将是属于该 PORTLET所在的上下文的私有SESSION 对象。比如,用户当前页面有三个PORTLET,每个PORTLET都属于不同的PORTLET APPLICATION。则当该用户在第一个PORTLET里面有对SESSION的操作后,该PORTLET所属的APPLICATION将为这个用户 生成一个SESSION;当该用户又操作第二个PORTLET中的SESSION时,该上下文有会对此用户产生一个新的SESSION对象;第三个依然如 此。加上PORTAL系统的SESSION,也就是该用户实际和四个SESSION在大交道。

另外要说明一点的是,PORTLET APPLICATION和WEB APPLICATION的关系。规范中有如下的定义:
(Portlets, servlets and JSPs are bundled in an extended web application called portlet application. Portlets, servlets and JSPs within the same portlet application share class loader, application context and session. )
这说明PORTLET APPLICATION其实就是一个WEB APPLICATION。规范中还有一段话更是说明了这个问题,同时也强调了PORTLET SESSION 和普通的该APPLICATION的SESSION的关系:
(A Portlet Application is also a Web Application. The Portlet Application may contain servlets and JSPs in addition to portlets. Portlets, servlets and JSPs may share information through their session. The PortletSession must store all attributes in the HttpSession of the portlet application. A direct consequence of this is that data stored in the HttpSession by servlets or JSPs is accessible to portlets through the PortletSession in the portlet application scope. Conversely, data stored by portlets in the PortletSession in the portlet application scope is accessible to servlets and JSPs through the HttpSession. If the HttpSession object is invalidated, the PortletSession object must also be invalidated by the portlet container. If the PortletSession object is invalidated by a portlet, the portlet container must invalidate the associated HttpSession object.)

最后一点要说明的是怎样得到PORTLET SESSION对象。规范中有这样一个例子:
PortletSession session = request.getSession(true);
URL url = new URL(“http://www.foo.com“);
session.setAttribute(“home.url”,url,PortletSession.APPLICATION_SCOPE);
session.setAttribute(“bkg.color”,”RED”,PortletSession.PORTLET_SCOPE);


 

二、LIFERAY中的实现

LIFERAY在构建ActionRequestImpl和RenderRequestImpl时,会设置PORTLET SESSION,如下代码所示:

public  RenderRequestImpl(HttpServletRequest req, Portlet portlet,
        CachePortlet cachePortlet,
        PortletContext portletCtx,
        WindowState windowState, PortletMode portletMode,
        PortletPreferences prefs, String layoutId) 
{
   ...
  _req 
= dynamicReq;
  _portlet 
= portlet;
  _cachePortlet 
= cachePortlet;
  _portalCtx 
= new PortalContextImpl();
  _portletCtx 
= portletCtx;
  _windowState 
= windowState;
  _portletMode 
= portletMode;
  _prefs 
= prefs;
  _ses 
= new PortletSessionImpl(
   _req.getSession(), _portletName, _portletCtx);
   ...
 }

从兰色的部分(  _ses = new PortletSessionImpl(_req.getSession(),_portletName, _portletCtx);  )我们可以看到,这个PORTLET SESSION其实就是PORTAL SYSTEM的 SESSION 对象。
所以无论request调用 getSession()或者getPortletSession()都将获取Portal 系统的SESSION 对象,而无论该PORTLET  是或者不是属于PORTAL SYSTEM上下文。而且即使不同PORTAL APPLICATION的PORTLET也将使用同一个SESSION 对象(PORTAL 系统)。
也就是说,对于某一个PORTLET来说,如果有对其的SESSION进行的操作,并没有真正的在该APPLICATION上下文中的SESSION进行操作,而是在PORTAL系统上下文的SESSION中进行操作。

而且LIFERAY提供getPortletSession来获取PortletSession对象,而不是getSession()方法,所以即 使getPortletSession()可以获取正确的Session对象,开发人员由于习惯问题,也因使用getSession()而得不到。

另外如果调用request.getSession(true)还可能会出现错误,因为LIFERAY在包含某一个PORTLET内容是,调用 PortletRequestDispatcherImpl.include()方法,该方法将生成PortletServletRequest 和PortletServletResponse,请见如下代码:

 

PortletServletRequest portletServletReq  =   new  PortletServletRequest(
    httpReq, reqImpl, pathInfo, queryString, requestURI,
    servletPath);

   PortletServletResponse portletServletRes 
=
    
new  PortletServletResponse(
     resImpl.getHttpServletResponse(), resImpl);
而PortletServletRequest的构造函数是如下定义的:
public  PortletServletRequest(HttpServletRequest req,
         RenderRequest renderRequest, String pathInfo,
         String queryString, String requestURI,
         String servletPath) 
{

  
super(req);

  _ses 
= req.getSession();
  _renderRequest 
= renderRequest;
  _pathInfo 
= pathInfo;
  _queryString 
= queryString;
  _requestURI 
= requestURI;
  _servletPath 
= servletPath;
 }


所以其SESSION依然是PORTAL系统上下文的。然后问题就出在这里,PortletServletRequest实现了 getSession()方法,但是没有实现getSession(boolen create)方法,如果用户在此阶段调用getSession(true)的话,在某些情况下就会抛出NullPointerException

原因见如下代码(请注意我添加的注释部分)
//ApplicationHttpRequest:  

 

  public  HttpSession getSession( boolean  create)  {

        
if (crossContext) {
            
            
// There cannot be a session if no context has been assigned yet
            if (context == null)
                
return (null);

            
// Return the current session if it exists and is valid
            if (session != null)
                
return (session.getSession());
     
// 我的注释:这里将获取PORTAL系统的SESSION对象。
            HttpSession other = super.getSession(false);
            
if (create && (other == null)) {
                
// First create a session in the first context: the problem is
                
// that the top level request is the only one which can 
                
// create the cookie safely
                other = super.getSession(true);
            }

            
if (other != null{
                Session localSession 
= null;
                
try {
                    
// 我的注释:this context did not have the session with session id. It can just be found in the Portal
                    
// context. So here it will return a null value.
                    localSession =
                        context.getManager().findSession(other.getId());
                    localSession.access(); 
//我的注释:Here, localSession is null. So it throws a NullPointException.
                }
 catch (IOException e) {
                    
// Ignore
                }

                
if (localSession == null{
                    localSession 
= context.getManager().createEmptySession();
                    localSession.setNew(
true);
                    localSession.setValid(
true);
                    localSession.setCreationTime(System.currentTimeMillis());
                    localSession.setMaxInactiveInterval
                        (context.getManager().getMaxInactiveInterval());
                    localSession.setId(other.getId());
                }

                session 
= localSession;
                
return session.getSession();
            }

            
return null;

        }
 else {
            
return super.getSession(create);
        }


    }


三、问题
由于上述原因,LIFERAY可能面临如下问题:
- 用户本来是想保存私有的数据到本应用的SESSION中,但是实际上却保存到PORTAL系统的SESSION对象中了
- 其他应用的可以随意的访问不属于本应用的SESSION 数据
- 其他系统可以随意访问PORTAL系统的SESSION数据
- 不同的应用不能使用相同的KEY来保存数据,如果这样做,则会相互覆盖数据。

以上是我对LIFERAY的一点分析拙见,请高手多多指教!

 

转载自:http://blog.csdn.net/daryl715/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值