Author: markt Date: Mon Feb 26 10:00:12 2018 New Revision: 1825351 URL: http://svn.apache.org/viewvc?rev=1825351&view=rev Log: Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=43866 Add additional attributes to the Manager to provide control over which listeners are called when an attribute is added to the session when it has already been added under the same name. This is to aid clustering scenarios where setAttribute() is often called to signal that the attribute value has been mutated and needs to be replicated but it may not be required, or even desired, for the the associated listeners to be triggered. The default behaviour has not been changed.
Modified: tomcat/trunk/java/org/apache/catalina/Manager.java tomcat/trunk/java/org/apache/catalina/session/ManagerBase.java tomcat/trunk/java/org/apache/catalina/session/StandardSession.java tomcat/trunk/webapps/docs/changelog.xml tomcat/trunk/webapps/docs/config/manager.xml Modified: tomcat/trunk/java/org/apache/catalina/Manager.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/Manager.java?rev=1825351&r1=1825350&r2=1825351&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/Manager.java (original) +++ tomcat/trunk/java/org/apache/catalina/Manager.java Mon Feb 26 10:00:12 2018 @@ -351,4 +351,73 @@ public interface Manager { * otherwise {@code false} */ public boolean willAttributeDistribute(String name, Object value); + + + /** + * When an attribute that is already present in the session is added again + * under the same name and the attribute implements {@link + * javax.servlet.http.HttpSessionBindingListener}, should + * {@link javax.servlet.http.HttpSessionBindingListener#valueUnbound(javax.servlet.http.HttpSessionBindingEvent)} + * be called followed by + * {@link javax.servlet.http.HttpSessionBindingListener#valueBound(javax.servlet.http.HttpSessionBindingEvent)}? + * <p> + * The default value is {@code false}. + * + * @return {@code true} if the listener will be notified, {@code false} if + * it will not + */ + public default boolean getNotifyBindingListenerOnUnchangedValue() { + return false; + } + + + /** + * Configure if + * {@link javax.servlet.http.HttpSessionBindingListener#valueUnbound(javax.servlet.http.HttpSessionBindingEvent)} + * be called followed by + * {@link javax.servlet.http.HttpSessionBindingListener#valueBound(javax.servlet.http.HttpSessionBindingEvent)} + * when an attribute that is already present in the session is added again + * under the same name and the attribute implements {@link + * javax.servlet.http.HttpSessionBindingListener}. + * + * @param notifyBindingListenerOnUnchangedValue {@code true} the listener + * will be called, {@code + * false} it will not + */ + public void setNotifyBindingListenerOnUnchangedValue( + boolean notifyBindingListenerOnUnchangedValue); + + + /** + * When an attribute that is already present in the session is added again + * under the same name and a {@link + * javax.servlet.http.HttpSessionAttributeListener} is configured for the + * session should + * {@link javax.servlet.http.HttpSessionAttributeListener#attributeReplaced(javax.servlet.http.HttpSessionBindingEvent)} + * be called? + * <p> + * The default value is {@code true}. + * + * @return {@code true} if the listener will be notified, {@code false} if + * it will not + */ + public default boolean getNotifyAttributeListenerOnUnchangedValue() { + return true; + } + + + /** + * Configure if + * {@link javax.servlet.http.HttpSessionAttributeListener#attributeReplaced(javax.servlet.http.HttpSessionBindingEvent)} + * when an attribute that is already present in the session is added again + * under the same name and a {@link + * javax.servlet.http.HttpSessionAttributeListener} is configured for the + * session. + * + * @param notifyAttributeListenerOnUnchangedValue {@code true} the listener + * will be called, {@code + * false} it will not + */ + public void setNotifyAttributeListenerOnUnchangedValue( + boolean notifyAttributeListenerOnUnchangedValue); } Modified: tomcat/trunk/java/org/apache/catalina/session/ManagerBase.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/session/ManagerBase.java?rev=1825351&r1=1825350&r2=1825351&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/session/ManagerBase.java (original) +++ tomcat/trunk/java/org/apache/catalina/session/ManagerBase.java Mon Feb 26 10:00:12 2018 @@ -193,6 +193,10 @@ public abstract class ManagerBase extend private boolean warnOnSessionAttributeFilterFailure; + private boolean notifyBindingListenerOnUnchangedValue; + + private boolean notifyAttributeListenerOnUnchangedValue = true; + // ------------------------------------------------------------ Constructors @@ -209,6 +213,31 @@ public abstract class ManagerBase extend // -------------------------------------------------------------- Properties + @Override + public boolean getNotifyAttributeListenerOnUnchangedValue() { + return notifyAttributeListenerOnUnchangedValue; + } + + + + @Override + public void setNotifyAttributeListenerOnUnchangedValue(boolean notifyAttributeListenerOnUnchangedValue) { + this.notifyAttributeListenerOnUnchangedValue = notifyAttributeListenerOnUnchangedValue; + } + + + @Override + public boolean getNotifyBindingListenerOnUnchangedValue() { + return notifyBindingListenerOnUnchangedValue; + } + + + @Override + public void setNotifyBindingListenerOnUnchangedValue(boolean notifyBindingListenerOnUnchangedValue) { + this.notifyBindingListenerOnUnchangedValue = notifyBindingListenerOnUnchangedValue; + } + + /** * Obtain the regular expression used to filter session attribute based on * attribute name. The regular expression is anchored so it must match the Modified: tomcat/trunk/java/org/apache/catalina/session/StandardSession.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/session/StandardSession.java?rev=1825351&r1=1825350&r2=1825351&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/session/StandardSession.java (original) +++ tomcat/trunk/java/org/apache/catalina/session/StandardSession.java Mon Feb 26 10:00:12 2018 @@ -1424,8 +1424,9 @@ public class StandardSession implements // Call the valueBound() method if necessary if (notify && value instanceof HttpSessionBindingListener) { // Don't call any notification if replacing with the same value + // unless configured to do so Object oldValue = attributes.get(name); - if (value != oldValue) { + if (value != oldValue || manager.getNotifyBindingListenerOnUnchangedValue()) { event = new HttpSessionBindingEvent(getSession(), name, value); try { ((HttpSessionBindingListener) value).valueBound(event); @@ -1440,14 +1441,18 @@ public class StandardSession implements Object unbound = attributes.put(name, value); // Call the valueUnbound() method if necessary - if (notify && (unbound instanceof HttpSessionBindingListener) && (unbound != value)) { - try { - ((HttpSessionBindingListener) unbound).valueUnbound( - new HttpSessionBindingEvent(getSession(), name)); - } catch (Throwable t) { - ExceptionUtils.handleThrowable(t); - manager.getContext().getLogger().error( - sm.getString("standardSession.bindingEvent"), t); + if (notify && unbound instanceof HttpSessionBindingListener) { + // Don't call any notification if replacing with the same value + // unless configured to do so + if (unbound != value || manager.getNotifyBindingListenerOnUnchangedValue()) { + try { + ((HttpSessionBindingListener) unbound).valueUnbound + (new HttpSessionBindingEvent(getSession(), name)); + } catch (Throwable t) { + ExceptionUtils.handleThrowable(t); + manager.getContext().getLogger().error + (sm.getString("standardSession.bindingEvent"), t); + } } } @@ -1468,12 +1473,14 @@ public class StandardSession implements HttpSessionAttributeListener listener = (HttpSessionAttributeListener) listeners[i]; try { if (unbound != null) { - context.fireContainerEvent("beforeSessionAttributeReplaced", listener); - if (event == null) { - event = new HttpSessionBindingEvent(getSession(), name, unbound); + if (unbound != value || manager.getNotifyAttributeListenerOnUnchangedValue()) { + context.fireContainerEvent("beforeSessionAttributeReplaced", listener); + if (event == null) { + event = new HttpSessionBindingEvent(getSession(), name, unbound); + } + listener.attributeReplaced(event); + context.fireContainerEvent("afterSessionAttributeReplaced", listener); } - listener.attributeReplaced(event); - context.fireContainerEvent("afterSessionAttributeReplaced", listener); } else { context.fireContainerEvent("beforeSessionAttributeAdded", listener); if (event == null) { @@ -1486,7 +1493,10 @@ public class StandardSession implements ExceptionUtils.handleThrowable(t); try { if (unbound != null) { - context.fireContainerEvent("afterSessionAttributeReplaced", listener); + if (unbound != value || + manager.getNotifyAttributeListenerOnUnchangedValue()) { + context.fireContainerEvent("afterSessionAttributeReplaced", listener); + } } else { context.fireContainerEvent("afterSessionAttributeAdded", listener); } Modified: tomcat/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1825351&r1=1825350&r2=1825351&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ tomcat/trunk/webapps/docs/changelog.xml Mon Feb 26 10:00:12 2018 @@ -48,6 +48,16 @@ <subsection name="Catalina"> <changelog> <fix> + <bug>43866</bug>: Add additional attributes to the Manager to provide + control over which listeners are called when an attribute is added to + the session when it has already been added under the same name. This is + to aid clustering scenarios where <code>setAttribute()</code> is often + called to signal that the attribute value has been mutated and needs to + be replicated but it may not be required, or even desired, for the the + associated listeners to be triggered. The default behaviour has not been + changed. (markt) + </fix> + <fix> Minor optimization when calling class transformers. (rjung) </fix> <add> Modified: tomcat/trunk/webapps/docs/config/manager.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/manager.xml?rev=1825351&r1=1825350&r2=1825351&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/config/manager.xml (original) +++ tomcat/trunk/webapps/docs/config/manager.xml Mon Feb 26 10:00:12 2018 @@ -73,6 +73,23 @@ (e.g. with <code>HttpServletRequest.getSession()</code> call) will fail with an <code>IllegalStateException</code>.</p> </attribute> + + <attribute name="notifyAttributeListenerOnUnchangedValue" required="false"> + <p>If an attribute is added to the session and that attribute is already + present in the session under the same name will any + <code>HttpSessionAttributeListener</code> be notified that the attribute + has been replaced. If not specified, the default value of + <code>true</code> will be used.</p> + </attribute> + + <attribute name="notifyBindingListenerOnUnchangedValue" required="false"> + <p>If an attribute is added to the session, that attribute is already + present in the session under the same name and the attribute implements + <code>HttpSessionBindingListener</code>, will the listener be notified + that the attribute has been unbound and bound again. If not specified, + the default value of <code>false</code> will be used.</p> + </attribute> + </attributes> </subsection> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org