WICKET-5508 Memory model improvements for Session fields
Project: http://git-wip-us.apache.org/repos/asf/wicket/repo Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/c78379f4 Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/c78379f4 Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/c78379f4 Branch: refs/heads/sandbox/component-queueing-2 Commit: c78379f4ba3fdd58c574a610db3e85e616860d10 Parents: 87df7f4 Author: Martin Tzvetanov Grigorov <[email protected]> Authored: Tue Feb 18 10:13:20 2014 +0200 Committer: Martin Tzvetanov Grigorov <[email protected]> Committed: Tue Feb 18 10:13:20 2014 +0200 ---------------------------------------------------------------------- .../main/java/org/apache/wicket/Session.java | 86 +++++++++++++------- 1 file changed, 55 insertions(+), 31 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/wicket/blob/c78379f4/wicket-core/src/main/java/org/apache/wicket/Session.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/Session.java b/wicket-core/src/main/java/org/apache/wicket/Session.java index 37de3f3..147351b 100644 --- a/wicket-core/src/main/java/org/apache/wicket/Session.java +++ b/wicket-core/src/main/java/org/apache/wicket/Session.java @@ -23,6 +23,8 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import org.apache.wicket.application.IClassResolver; import org.apache.wicket.authorization.IAuthorizationStrategy; @@ -40,6 +42,7 @@ import org.apache.wicket.session.ISessionStore; import org.apache.wicket.util.IProvider; import org.apache.wicket.util.LazyInitializer; import org.apache.wicket.util.io.IClusterable; +import org.apache.wicket.util.lang.Args; import org.apache.wicket.util.lang.Objects; import org.apache.wicket.util.time.Duration; import org.slf4j.Logger; @@ -114,10 +117,10 @@ public abstract class Session implements IClusterable, IEventSink public static final String SESSION_ATTRIBUTE_NAME = "session"; /** a sequence used for whenever something session-specific needs a unique value */ - private int sequence = 1; + private final AtomicInteger sequence = new AtomicInteger(1); /** a sequence used for generating page IDs */ - private int pageId = 0; + private final AtomicInteger pageId = new AtomicInteger(0); /** synchronize page's access by session */ private final IProvider<PageAccessSynchronizer> pageAccessSynchronizer; @@ -174,7 +177,7 @@ public abstract class Session implements IClusterable, IEventSink protected ClientInfo clientInfo; /** True if session state has been changed */ - private transient boolean dirty = false; + private transient volatile boolean dirty = false; /** feedback messages */ private final FeedbackMessages feedbackMessages = new FeedbackMessages(); @@ -183,13 +186,13 @@ public abstract class Session implements IClusterable, IEventSink private String id = null; /** The locale to use when loading resources for this session. */ - private Locale locale; + private final AtomicReference<Locale> locale; /** Application level meta data. */ private MetaDataEntry<?>[] metaData; /** True, if session has been invalidated */ - private transient boolean sessionInvalidated = false; + private transient volatile boolean sessionInvalidated = false; /** * Temporary instance of the session store. Should be set on each request as it is not supposed @@ -198,7 +201,7 @@ public abstract class Session implements IClusterable, IEventSink private transient ISessionStore sessionStore; /** Any special "skin" style to use when loading resources. */ - private String style; + private final AtomicReference<String> style = new AtomicReference<>(); /** * Holds attributes for sessions that are still temporary/ not bound to a session store. Only @@ -219,12 +222,13 @@ public abstract class Session implements IClusterable, IEventSink */ public Session(Request request) { - locale = request.getLocale(); + Locale locale = request.getLocale(); if (locale == null) { throw new IllegalStateException( "Request#getLocale() cannot return null, request has to have a locale set on it"); } + this.locale = new AtomicReference<>(locale); pageAccessSynchronizer = new PageAccessSynchronizerProvider(); } @@ -402,7 +406,7 @@ public abstract class Session implements IClusterable, IEventSink */ public Locale getLocale() { - return locale; + return locale.get(); } /** @@ -443,7 +447,7 @@ public abstract class Session implements IClusterable, IEventSink */ public final String getStyle() { - return style; + return style.get(); } /** @@ -565,15 +569,13 @@ public abstract class Session implements IClusterable, IEventSink */ public Session setLocale(final Locale locale) { - if (locale == null) - { - throw new IllegalArgumentException("Argument 'locale' must not be null"); - } - if (!Objects.equal(this.locale, locale)) + Args.notNull(locale, "locale"); + + if (!Objects.equal(getLocale(), locale)) { + this.locale.set(locale); dirty(); } - this.locale = locale; return this; } @@ -605,8 +607,11 @@ public abstract class Session implements IClusterable, IEventSink */ public final Session setStyle(final String style) { - this.style = style; - dirty(); + if (!Objects.equal(getStyle(), style)) + { + this.style.set(style); + dirty(); + } return this; } @@ -682,11 +687,36 @@ public abstract class Session implements IClusterable, IEventSink } /** - * Marks session state as dirty so that it will be flushed at the end of the request. + * Marks session state as dirty so that it will be (re)stored in the ISessionStore + * at the end of the request. + * <strong>Note</strong>: binds the session if it is temporary */ public final void dirty() { - dirty = true; + dirty(true); + } + + /** + * Marks session state as dirty so that it will be re-stored in the ISessionStore + * at the end of the request. + * + * @param forced + * A flag indicating whether the session should be marked as dirty even + * when it is temporary. If {@code true} the Session will be bound. + */ + public final void dirty(boolean forced) + { + if (isTemporary()) + { + if (forced) + { + dirty = true; + } + } + else + { + dirty = true; + } } /** @@ -839,26 +869,20 @@ public abstract class Session implements IClusterable, IEventSink * * @return session-unique value */ - public synchronized int nextSequenceValue() + public int nextSequenceValue() { - if (isTemporary() == false) - { - dirty(); - } - return sequence++; + dirty(false); + return sequence.getAndIncrement(); } /** * * @return the next page id */ - public synchronized int nextPageId() + public int nextPageId() { - if (isTemporary() == false) - { - dirty(); - } - return pageId++; + dirty(false); + return pageId.getAndIncrement(); } /**
