2018-02-26 19:00 GMT+09:00 <ma...@apache.org>: > 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); > } > > Hi,
In cluster environment, I think that primary sessions behave as expected. However, non-primary sessions do not behave as expected. The if(unbound != value) always returns true. Therefore, listeners are always notified regardless of the value of notifyAttributeListenerOnUnchangedValue or notifyBindingListenerOnUnchangedValue. > 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 > > -- > Keiichi.Fujino > <dev-h...@tomcat.apache.org> <dev-h...@tomcat.apache.org>