二、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);
}
}