WebSessions: backported latests changes from 1.6.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/b07d5c1f Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/b07d5c1f Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/b07d5c1f Branch: refs/heads/ignite-3163 Commit: b07d5c1f3f8f4136bd829360ed78623f298669d2 Parents: 2d2e935 Author: vozerov-gridgain <[email protected]> Authored: Wed May 18 11:06:42 2016 +0300 Committer: vozerov-gridgain <[email protected]> Committed: Wed May 18 11:06:42 2016 +0300 ---------------------------------------------------------------------- .../WebSessionAttributeProcessor.java | 5 +- .../ignite/cache/websession/WebSession.java | 74 +++++++- .../cache/websession/WebSessionFilter.java | 177 ++++++++++++++----- .../ignite/cache/websession/WebSessionV2.java | 74 ++++---- 4 files changed, 250 insertions(+), 80 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/b07d5c1f/modules/core/src/main/java/org/apache/ignite/internal/websession/WebSessionAttributeProcessor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/websession/WebSessionAttributeProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/websession/WebSessionAttributeProcessor.java index 35b4d90..bef42e4 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/websession/WebSessionAttributeProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/websession/WebSessionAttributeProcessor.java @@ -67,9 +67,8 @@ public class WebSessionAttributeProcessor implements EntryProcessor<String, WebS * @param maxInactiveInterval Max inactive interval. * @param maxIntervalChanged {@code True} if max inactive interval should be updated. */ - public WebSessionAttributeProcessor( - final Map<String, byte[]> updatesMap, final long accessTime, final int maxInactiveInterval, - final boolean maxIntervalChanged) { + public WebSessionAttributeProcessor(final Map<String, byte[]> updatesMap, final long accessTime, + final int maxInactiveInterval, final boolean maxIntervalChanged) { this.updatesMap = updatesMap; this.accessTime = accessTime; this.maxInactiveInterval = maxInactiveInterval; http://git-wip-us.apache.org/repos/asf/ignite/blob/b07d5c1f/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSession.java ---------------------------------------------------------------------- diff --git a/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSession.java b/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSession.java index 5734b64..2e43f2f 100644 --- a/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSession.java +++ b/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSession.java @@ -45,6 +45,9 @@ class WebSession implements HttpSession, Externalizable { /** */ private static final long serialVersionUID = 0L; + /** Flag indicating if the session is valid. */ + private volatile transient boolean isValid = true; + /** Empty session context. */ private static final HttpSessionContext EMPTY_SES_CTX = new HttpSessionContext() { @Nullable @Override public HttpSession getSession(String id) { @@ -76,6 +79,7 @@ class WebSession implements HttpSession, Externalizable { @GridToStringExclude private transient ServletContext ctx; + /** Web session filter. */ @GridToStringExclude private transient WebSessionFilter filter; @@ -85,6 +89,9 @@ class WebSession implements HttpSession, Externalizable { /** Updates list. */ private transient Collection<T2<String, Object>> updates; + /** Genuine http session. */ + private transient HttpSession genSes; + /** * Required by {@link Externalizable}. */ @@ -130,6 +137,15 @@ class WebSession implements HttpSession, Externalizable { } /** + * Sets the genuine http session. + * + * @param genSes Genuine http session. + */ + protected void genSes(HttpSession genSes) { + this.genSes = genSes; + } + + /** * @param ctx Servlet context. */ public void servletContext(ServletContext ctx) { @@ -148,6 +164,15 @@ class WebSession implements HttpSession, Externalizable { } /** + * Checks if the session is valid. + * + * @return True is valid, otherwise false. + */ + protected boolean isValid() { + return this.isValid; + } + + /** * Resets updates list. */ public void resetUpdates() { @@ -170,6 +195,15 @@ class WebSession implements HttpSession, Externalizable { return id; } + /** + * Sets a session id. + * + * @param id Session id. + */ + protected void setId(String id) { + this.id = id; + } + /** {@inheritDoc} */ @Override public ServletContext getServletContext() { return ctx; @@ -177,11 +211,17 @@ class WebSession implements HttpSession, Externalizable { /** {@inheritDoc} */ @Override public long getCreationTime() { + if (!isValid) + throw new IllegalStateException("Call on invalidated session!"); + return createTime; } /** {@inheritDoc} */ @Override public long getLastAccessedTime() { + if (!isValid) + throw new IllegalStateException("Call on invalidated session!"); + return accessTime; } @@ -197,26 +237,43 @@ class WebSession implements HttpSession, Externalizable { /** {@inheritDoc} */ @Override public Object getAttribute(String name) { - return attrs.get(name); + if (!isValid) + throw new IllegalStateException("Call on invalidated session!"); + + Object val = attrs.get(name); + + if (val != null && updates != null) + updates.add(new T2<>(name, val)); + + return val; } /** {@inheritDoc} */ @Override public Object getValue(String name) { - return attrs.get(name); + return getAttribute(name); } /** {@inheritDoc} */ @Override public Enumeration<String> getAttributeNames() { + if (!isValid) + throw new IllegalStateException("Call on invalidated session!"); + return Collections.enumeration(attrs.keySet()); } /** {@inheritDoc} */ @Override public String[] getValueNames() { + if (!isValid) + throw new IllegalStateException("Call on invalidated session!"); + return attrs.keySet().toArray(new String[attrs.size()]); } /** {@inheritDoc} */ @Override public void setAttribute(String name, Object val) { + if (!isValid) + throw new IllegalStateException("Call on invalidated session!"); + attrs.put(name, val); if (updates != null) @@ -230,6 +287,9 @@ class WebSession implements HttpSession, Externalizable { /** {@inheritDoc} */ @Override public void removeAttribute(String name) { + if (!isValid) + throw new IllegalStateException("Call on invalidated session!"); + attrs.remove(name); if (updates != null) @@ -243,15 +303,25 @@ class WebSession implements HttpSession, Externalizable { /** {@inheritDoc} */ @Override public void invalidate() { + if (!isValid) + throw new IllegalStateException("Call on invalidated session!"); + attrs.clear(); updates = null; filter.destroySession(id); + + genSes.invalidate(); + + isValid = false; } /** {@inheritDoc} */ @Override public boolean isNew() { + if (!isValid) + throw new IllegalStateException("Call on invalidated session!"); + return isNew; } http://git-wip-us.apache.org/repos/asf/ignite/blob/b07d5c1f/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionFilter.java ---------------------------------------------------------------------- diff --git a/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionFilter.java b/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionFilter.java index c0f62bf..2b7442f 100644 --- a/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionFilter.java +++ b/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionFilter.java @@ -196,8 +196,7 @@ public class WebSessionFilter implements Filter { /** Default retry on fail timeout flag value. */ public static final int DFLT_RETRIES_ON_FAIL_TIMEOUT = 10000; - // TOOD: Minimal JavaDoc. - /** */ + /** Default keep binary flag. */ public static final boolean DFLT_KEEP_BINARY_FLAG = true; /** Cache. */ @@ -416,7 +415,7 @@ public class WebSessionFilter implements Filter { * @param chain Filter chain. * @return Session ID. * @throws IOException In case of I/O error. - * @throws ServletException In case oif servlet error. + * @throws ServletException In case of servlet error. * @throws CacheException In case of other error. */ private String doFilterV1(HttpServletRequest httpReq, ServletResponse res, FilterChain chain) throws IOException, @@ -464,26 +463,30 @@ public class WebSessionFilter implements Filter { cached = createSession(httpReq); } } - else { + else cached = createSession(httpReq); - sesId = cached.getId(); - } - assert cached != null; + sesId = cached.getId(); + cached.servletContext(ctx); cached.filter(this); cached.resetUpdates(); + cached.genSes(httpReq.getSession(false)); httpReq = new RequestWrapper(httpReq, cached); chain.doFilter(httpReq, res); - final Collection<T2<String, Object>> updates = cached.updates(); + HttpSession ses = httpReq.getSession(false); + + if (ses != null && ses instanceof WebSession) { + Collection<T2<String, Object>> updates = ((WebSession) ses).updates(); - if (updates != null) - updateAttributes(transformSessionId(sesId), updates, cached.getMaxInactiveInterval()); + if (updates != null) + updateAttributes(transformSessionId(sesId), updates, ses.getMaxInactiveInterval()); + } return sesId; } @@ -511,11 +514,10 @@ public class WebSessionFilter implements Filter { try { final WebSessionEntity entity = binaryCache.get(sesId); - if (entity != null) { - cached = new WebSessionV2(sesId, null, false, ctx, entity, marshaller); + if (entity != null) + cached = new WebSessionV2(sesId, httpReq.getSession(false), false, ctx, entity, marshaller); - break; - } + break; } catch (CacheException | IgniteException | IllegalStateException e) { handleLoadSessionException(sesId, i, e); @@ -548,23 +550,29 @@ public class WebSessionFilter implements Filter { } } // No session was requested by the client, create new one and put in the request. - else { + else cached = createSessionV2(httpReq); - sesId = cached.getId(); - } - assert cached != null; + sesId = cached.getId(); + httpReq = new RequestWrapperV2(httpReq, cached); chain.doFilter(httpReq, res); - // Update session - if (cached.isValid()) - updateAttributesV2(sesId, cached); + if (!cached.isValid()) + binaryCache.remove(cached.id()); + // Changed session ID. + else if (!cached.getId().equals(sesId)) { + final String oldId = cached.getId(); + + cached.invalidate(); + + binaryCache.remove(oldId); + } else - binaryCache.remove(sesId); + updateAttributesV2(cached.getId(), cached); return sesId; } @@ -604,8 +612,10 @@ public class WebSessionFilter implements Filter { } /** - * @param httpReq HTTP request. - * @return Cached session. + * Creates a new session from http request. + * + * @param httpReq Request. + * @return New session. */ @SuppressWarnings("unchecked") private WebSession createSession(HttpServletRequest httpReq) { @@ -613,11 +623,25 @@ public class WebSessionFilter implements Filter { String sesId = transformSessionId(ses.getId()); - if (log.isDebugEnabled()) - log.debug("Session created: " + sesId); + return createSession(ses, sesId); + } + /** + * Creates a new web session with the specified id. + * + * @param ses Base session. + * @param sesId Session id. + * @return New session. + */ + @SuppressWarnings("unchecked") + private WebSession createSession(HttpSession ses, String sesId) { WebSession cached = new WebSession(sesId, ses, true); + cached.genSes(ses); + + if (log.isDebugEnabled()) + log.debug("Session created: " + sesId); + for (int i = 0; i < retries; i++) { try { final IgniteCache<String, WebSession> cache0 = @@ -664,14 +688,13 @@ public class WebSessionFilter implements Filter { } /** - * @param httpReq HTTP request. - * @return Cached session. + * Creates a new web session with the specified id. + * + * @param ses Base session. + * @param sesId Session id. + * @return New session. */ - private WebSessionV2 createSessionV2(HttpServletRequest httpReq) throws IOException { - final HttpSession ses = httpReq.getSession(true); - - final String sesId = transformSessionId(ses.getId()); - + private WebSessionV2 createSessionV2(final HttpSession ses, final String sesId) throws IOException { if (log.isDebugEnabled()) log.debug("Session created: " + sesId); @@ -687,9 +710,9 @@ public class WebSessionFilter implements Filter { final WebSessionEntity old = cache0.getAndPutIfAbsent(sesId, marshaledEntity); if (old != null) - cached = new WebSessionV2(sesId, null, false, ctx, old, marshaller); + cached = new WebSessionV2(sesId, ses, false, ctx, old, marshaller); else - cached = new WebSessionV2(sesId, null, false, ctx, marshaledEntity, marshaller); + cached = new WebSessionV2(sesId, ses, false, ctx, marshaledEntity, marshaller); break; } @@ -702,6 +725,18 @@ public class WebSessionFilter implements Filter { } /** + * @param httpReq HTTP request. + * @return Cached session. + */ + private WebSessionV2 createSessionV2(HttpServletRequest httpReq) throws IOException { + final HttpSession ses = httpReq.getSession(true); + + final String sesId = transformSessionId(ses.getId()); + + return createSessionV2(ses, sesId); + } + + /** * @param maxInactiveInteval Interval to use in expiry policy. * @param cache Cache. * @param <T> Cached object type. @@ -876,9 +911,9 @@ public class WebSessionFilter implements Filter { /** * Request wrapper. */ - private static class RequestWrapper extends HttpServletRequestWrapper { + private class RequestWrapper extends HttpServletRequestWrapper { /** Session. */ - private final WebSession ses; + private volatile WebSession ses; /** * @param req Request. @@ -894,21 +929,48 @@ public class WebSessionFilter implements Filter { /** {@inheritDoc} */ @Override public HttpSession getSession(boolean create) { + if (!ses.isValid()) { + if (create) { + this.ses = createSession((HttpServletRequest)getRequest()); + this.ses.servletContext(ctx); + this.ses.filter(WebSessionFilter.this); + this.ses.resetUpdates(); + } + else + return null; + } + return ses; } /** {@inheritDoc} */ @Override public HttpSession getSession() { - return ses; + return getSession(true); + } + + /** {@inheritDoc} */ + @Override public String changeSessionId() { + HttpServletRequest req = (HttpServletRequest)getRequest(); + + String newId = req.changeSessionId(); + + this.ses.setId(newId); + + this.ses = createSession(ses, newId); + this.ses.servletContext(ctx); + this.ses.filter(WebSessionFilter.this); + this.ses.resetUpdates(); + + return newId; } } /** * Request wrapper V2. */ - private static class RequestWrapperV2 extends HttpServletRequestWrapper { + private class RequestWrapperV2 extends HttpServletRequestWrapper { /** Session. */ - private final WebSessionV2 ses; + private WebSessionV2 ses; /** * @param req Request. @@ -924,12 +986,45 @@ public class WebSessionFilter implements Filter { /** {@inheritDoc} */ @Override public HttpSession getSession(boolean create) { + if (!ses.isValid()) { + binaryCache.remove(ses.id()); + + if (create) { + try { + ses = createSessionV2((HttpServletRequest) getRequest()); + } + catch (IOException e) { + throw new IgniteException(e); + } + } + else + return null; + } + return ses; } /** {@inheritDoc} */ @Override public HttpSession getSession() { - return ses; + return getSession(true); + } + + /** {@inheritDoc} */ + @Override public String changeSessionId() { + final HttpServletRequest req = (HttpServletRequest) getRequest(); + + final String newId = req.changeSessionId(); + + if (!F.eq(newId, ses.getId())) { + try { + ses = createSessionV2(ses, newId); + } + catch (IOException e) { + throw new IgniteException(e); + } + } + + return newId; } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/b07d5c1f/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionV2.java ---------------------------------------------------------------------- diff --git a/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionV2.java b/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionV2.java index 9f2e24a..b6540b2 100644 --- a/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionV2.java +++ b/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionV2.java @@ -66,9 +66,6 @@ class WebSessionV2 implements HttpSession { /** Attributes. */ protected Map<String, Object> attrs; - /** Attributes waiting for update in cache. */ - private Map<String, Object> updatesMap; - /** Timestamp that shows when this object was created. (Last access time from user request) */ private final long accessTime; @@ -87,6 +84,9 @@ class WebSessionV2 implements HttpSession { /** Grid marshaller. */ private final Marshaller marshaller; + /** Original session to delegate invalidation. */ + private final HttpSession genuineSes; + /** * @param id Session ID. * @param ses Session. @@ -102,6 +102,7 @@ class WebSessionV2 implements HttpSession { this.marshaller = marshaller; this.ctx = ctx; this.isNew = isNew; + this.genuineSes = ses; accessTime = System.currentTimeMillis(); @@ -134,8 +135,13 @@ class WebSessionV2 implements HttpSession { /** {@inheritDoc} */ @Override public String getId() { - assertValid(); + return entity.id(); + } + /** + * @return Session ID without throwing exception. + */ + public String id() { return entity.id(); } @@ -185,21 +191,20 @@ class WebSessionV2 implements HttpSession { if (attr == REMOVED_ATTR) return null; - if (attr != null) - return attr; + if (attr == null) { + final byte[] bytes = entity.attributes().get(name); - final byte[] bytes = entity.attributes().get(name); + if (bytes != null) { + // deserialize + try { + attr = unmarshal(bytes); + } + catch (IOException e) { + throw new IgniteException(e); + } - if (bytes != null) { - // deserialize - try { - attr = unmarshal(bytes); - } - catch (IOException e) { - throw new IgniteException(e); + attributes().put(name, attr); } - - attributes().put(name, attr); } return attr; @@ -214,9 +219,10 @@ class WebSessionV2 implements HttpSession { @Override public void setAttribute(final String name, final Object val) { assertValid(); - attributes().put(name, val); - - updatesMap().put(name, val); + if (val == null) + removeAttribute(name); + else + attributes().put(name, val); } /** {@inheritDoc} */ @@ -265,8 +271,6 @@ class WebSessionV2 implements HttpSession { assertValid(); attributes().put(name, REMOVED_ATTR); - - updatesMap().put(name, null); } /** {@inheritDoc} */ @@ -278,6 +282,15 @@ class WebSessionV2 implements HttpSession { @Override public void invalidate() { assertValid(); + if (genuineSes != null) { + try { + genuineSes.invalidate(); + } + catch (IllegalStateException e) { + // Already invalidated, keep going. + } + } + invalidated = true; } @@ -293,15 +306,18 @@ class WebSessionV2 implements HttpSession { * @throws IOException */ public Map<String, byte[]> binaryUpdatesMap() throws IOException { - final Map<String, Object> map = updatesMap; + final Map<String, Object> map = attributes(); if (F.isEmpty(map)) return Collections.emptyMap(); final Map<String, byte[]> res = new HashMap<>(map.size()); - for (final Map.Entry<String, Object> entry : map.entrySet()) - res.put(entry.getKey(), marshal(entry.getValue())); + for (final Map.Entry<String, Object> entry : map.entrySet()) { + Object val = entry.getValue() == REMOVED_ATTR ? null : entry.getValue(); + + res.put(entry.getKey(), marshal(val)); + } return res; } @@ -371,16 +387,6 @@ class WebSessionV2 implements HttpSession { } /** - * @return Updates map. - */ - private Map<String, Object> updatesMap() { - if (updatesMap == null) - updatesMap = new HashMap<>(); - - return updatesMap; - } - - /** * @return {@code True} if session wasn't invalidated. */ public boolean isValid() {
