Return-Path: Delivered-To: apmail-incubator-shiro-dev-archive@www.apache.org Received: (qmail 10070 invoked from network); 17 May 2010 19:45:40 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 17 May 2010 19:45:40 -0000 Received: (qmail 89341 invoked by uid 500); 17 May 2010 19:18:59 -0000 Delivered-To: apmail-incubator-shiro-dev-archive@incubator.apache.org Received: (qmail 89311 invoked by uid 500); 17 May 2010 19:18:59 -0000 Mailing-List: contact shiro-dev-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: shiro-dev@incubator.apache.org Delivered-To: mailing list shiro-dev@incubator.apache.org Received: (qmail 89303 invoked by uid 99); 17 May 2010 19:18:59 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 17 May 2010 19:18:59 +0000 X-ASF-Spam-Status: No, hits=0.7 required=10.0 tests=SPF_NEUTRAL X-Spam-Check-By: apache.org Received-SPF: neutral (nike.apache.org: local policy) Received: from [209.85.160.175] (HELO mail-gy0-f175.google.com) (209.85.160.175) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 17 May 2010 19:18:52 +0000 Received: by gya1 with SMTP id 1so2217032gya.6 for ; Mon, 17 May 2010 12:17:59 -0700 (PDT) MIME-Version: 1.0 Received: by 10.150.251.17 with SMTP id y17mr6378919ybh.283.1274123868716; Mon, 17 May 2010 12:17:48 -0700 (PDT) Sender: les.hazlewood@anjinllc.com Received: by 10.151.149.18 with HTTP; Mon, 17 May 2010 12:17:48 -0700 (PDT) In-Reply-To: <20100517185939.C3DEE23889E5@eris.apache.org> References: <20100517185939.C3DEE23889E5@eris.apache.org> Date: Mon, 17 May 2010 12:17:48 -0700 X-Google-Sender-Auth: uzFmE9PJSlhVQErguprLSWiA3UU Message-ID: Subject: Re: svn commit: r945310 - /incubator/shiro/trunk/core/src/main/java/org/apache/shiro/util/ThreadContext.java From: Les Hazlewood To: shiro-dev@incubator.apache.org Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-Virus-Checked: Checked by ClamAV on apache.org Looks good to me! (good catch on the null value!) There are a few very minor JavaDoc issues that I can fix - I'll do that sho= rtly. Thanks! Les On Mon, May 17, 2010 at 11:59 AM, wrote: > Author: kaosko > Date: Mon May 17 18:59:39 2010 > New Revision: 945310 > > URL: http://svn.apache.org/viewvc?rev=3D945310&view=3Drev > Log: > Incomplete - issue SHIRO-161: No SecurityManager accessible to the callin= g code > https://issues.apache.org/jira/browse/SHIRO-161 > The root cause of this issue was "resources =3D null;" in line 261 of rem= ove() in r944585. The ThreadLocal attribute itself should *never* be nullif= ied as that'll remove ThreadLocal variables for all threads. There's no nee= d to create ThreadLocal lazily, so therefore there's no need for the create= ThreadLocal() method either. Since the ThreadLocal is created at class load= ing time, there's no need for "if (resources =3D=3D null)" checks either, s= o I've removed them in order to simplify the code. The usage of ThreadLocal= was somewhat odd with the cast to Map; while it technically works, the pro= per way of accessing the threadlocal variable is always with ThreadLocal.ge= t() so I changed all the occurrences to use that format. Finally, I don't s= ee any benefit in doing clean() in remove() before get().remove() so I remo= ved the clean() call and I also removed the whole operation since it wasn't= being used anymore and I don't see any use case where it could be used. We= can always add it in l > =C2=A0ater. Issue is fixed barring code review and possibly re-adding som= e of the removed code if there's a validated need for it. There are no new = test cases added because it'd be difficult to write a comprehensive unit te= st for the case, so we need to rely on code review. > > Modified: > =C2=A0 =C2=A0incubator/shiro/trunk/core/src/main/java/org/apache/shiro/ut= il/ThreadContext.java > > Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/util/= ThreadContext.java > URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/jav= a/org/apache/shiro/util/ThreadContext.java?rev=3D945310&r1=3D945309&r2=3D94= 5310&view=3Ddiff > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/util/Thread= Context.java (original) > +++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/util/Thread= Context.java Mon May 17 18:59:39 2010 > @@ -53,7 +53,7 @@ public abstract class ThreadContext { > =C2=A0 =C2=A0 public static final String SECURITY_MANAGER_KEY =3D ThreadC= ontext.class.getName() + "_SECURITY_MANAGER_KEY"; > =C2=A0 =C2=A0 public static final String SUBJECT_KEY =3D ThreadContext.cl= ass.getName() + "_SUBJECT_KEY"; > > - =C2=A0 =C2=A0protected static ThreadLocal> resource= s; > + =C2=A0 =C2=A0private static final ThreadLocal> reso= urces =3D new InheritableThreadLocalMap>(); > > =C2=A0 =C2=A0 /** > =C2=A0 =C2=A0 =C2=A0* Default no-argument constructor. > @@ -62,50 +62,6 @@ public abstract class ThreadContext { > =C2=A0 =C2=A0 } > > =C2=A0 =C2=A0 /** > - =C2=A0 =C2=A0 * Returns the {@link ThreadLocal} resource {@code Map}. = =C2=A0If it does not yet exist, one is created, > - =C2=A0 =C2=A0 * bound to the thread, and then returned. > - =C2=A0 =C2=A0 * > - =C2=A0 =C2=A0 * @return the ThreadLocal resource {@code Map}, possibly = lazily-created. > - =C2=A0 =C2=A0 * @since 1.0 > - =C2=A0 =C2=A0 */ > - =C2=A0 =C2=A0protected static Map getResourcesLazy() { > - =C2=A0 =C2=A0 =C2=A0 =C2=A0if (resources =3D=3D null) { > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0resources =3D createThreadLoca= l(); > - =C2=A0 =C2=A0 =C2=A0 =C2=A0} > - =C2=A0 =C2=A0 =C2=A0 =C2=A0return resources.get(); > - =C2=A0 =C2=A0} > - > - =C2=A0 =C2=A0/** > - =C2=A0 =C2=A0 * Creates a new {@link ThreadLocal} instance containing a= {@link Map} to hold arbitrary key-value pairs. > - =C2=A0 =C2=A0 * > - =C2=A0 =C2=A0 * @return a new {@link ThreadLocal} instance containing a= {@link Map} to hold arbitrary key-value pairs. > - =C2=A0 =C2=A0 * @since 1.0 > - =C2=A0 =C2=A0 */ > - =C2=A0 =C2=A0private static ThreadLocal> createThre= adLocal() { > - =C2=A0 =C2=A0 =C2=A0 =C2=A0return new InheritableThreadLocal>() { > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0protected Map = initialValue() { > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return new HashM= ap(); > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > - > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/** > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 * This implementation was add= ed to address a > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 * > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 * user-reported issue. > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 * @param parentValue the pare= nt value, a HashMap as defined in the {@link #initialValue()} method. > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 * @return the HashMap to be u= sed by any parent-spawned child threads (a clone of the parent HashMap). > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 */ > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0@SuppressWarnings({"unchecked"= }) > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0protected Map = childValue(Map parentValue) { > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (parentValue = !=3D null) { > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0re= turn (Map) ((HashMap) parentValue).clone(); > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} else { > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0re= turn null; > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > - =C2=A0 =C2=A0 =C2=A0 =C2=A0}; > - =C2=A0 =C2=A0} > - > - =C2=A0 =C2=A0/** > =C2=A0 =C2=A0 =C2=A0* Returns the ThreadLocal Map. This Map is used inter= nally to bind objects > =C2=A0 =C2=A0 =C2=A0* to the current thread by storing each object under = a unique key. > =C2=A0 =C2=A0 =C2=A0* > @@ -123,13 +79,12 @@ public abstract class ThreadContext { > =C2=A0 =C2=A0 =C2=A0* @param resources the resources to replace the exist= ing {@link #getResources() resources}. > =C2=A0 =C2=A0 =C2=A0* @since 1.0 > =C2=A0 =C2=A0 =C2=A0*/ > - =C2=A0 =C2=A0public static void setResources(Map resour= ces) { > - =C2=A0 =C2=A0 =C2=A0 =C2=A0if (CollectionUtils.isEmpty(resources)) { > + =C2=A0 =C2=A0public static void setResources(Map newRes= ources) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (CollectionUtils.isEmpty(newResources)) { > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return; > =C2=A0 =C2=A0 =C2=A0 =C2=A0 } > - =C2=A0 =C2=A0 =C2=A0 =C2=A0Map existing =3D getResource= sLazy(); > - =C2=A0 =C2=A0 =C2=A0 =C2=A0existing.clear(); > - =C2=A0 =C2=A0 =C2=A0 =C2=A0existing.putAll(resources); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0resources.get().clear(); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0resources.get().putAll(newResources); > =C2=A0 =C2=A0 } > > =C2=A0 =C2=A0 /** > @@ -142,9 +97,6 @@ public abstract class ThreadContext { > =C2=A0 =C2=A0 =C2=A0* @since 1.0 > =C2=A0 =C2=A0 =C2=A0*/ > =C2=A0 =C2=A0 private static Object getValue(Object key) { > - =C2=A0 =C2=A0 =C2=A0 =C2=A0if (resources =3D=3D null) { > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return null; > - =C2=A0 =C2=A0 =C2=A0 =C2=A0} > =C2=A0 =C2=A0 =C2=A0 =C2=A0 return resources.get().get(key); > =C2=A0 =C2=A0 } > > @@ -196,7 +148,7 @@ public abstract class ThreadContext { > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return; > =C2=A0 =C2=A0 =C2=A0 =C2=A0 } > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0getResourcesLazy().put(key, value); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0resources.get().put(key, value); > > =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (log.isTraceEnabled()) { > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 String msg =3D "Bound value of = type [" + value.getClass().getName() + "] for key [" + > @@ -214,9 +166,6 @@ public abstract class ThreadContext { > =C2=A0 =C2=A0 =C2=A0* =C2=A0 =C2=A0 =C2=A0 =C2=A0 under the specified key name. > =C2=A0 =C2=A0 =C2=A0*/ > =C2=A0 =C2=A0 public static Object remove(Object key) { > - =C2=A0 =C2=A0 =C2=A0 =C2=A0if (resources =3D=3D null) { > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return null; > - =C2=A0 =C2=A0 =C2=A0 =C2=A0} > =C2=A0 =C2=A0 =C2=A0 =C2=A0 Object value =3D resources.get().remove(key); > > =C2=A0 =C2=A0 =C2=A0 =C2=A0 if ((value !=3D null) && log.isTraceEnabled()= ) { > @@ -229,23 +178,6 @@ public abstract class ThreadContext { > =C2=A0 =C2=A0 } > > =C2=A0 =C2=A0 /** > - =C2=A0 =C2=A0 * Clears all values bound to this ThreadContext,= which includes any Subject, Session, or InetAddress > - =C2=A0 =C2=A0 * that may be bound by these respective objects' convenie= nce methods, as well as all values bound by your > - =C2=A0 =C2=A0 * application code. > - =C2=A0 =C2=A0 *

> - =C2=A0 =C2=A0 *

This operation is meant as a clean-up operation that= may be called at the end of > - =C2=A0 =C2=A0 * thread execution to prevent data corruption in a pooled= thread environment. > - =C2=A0 =C2=A0 */ > - =C2=A0 =C2=A0public static void clear() { > - =C2=A0 =C2=A0 =C2=A0 =C2=A0if (resources !=3D null) { > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0resources.get().clear(); > - =C2=A0 =C2=A0 =C2=A0 =C2=A0} > - =C2=A0 =C2=A0 =C2=A0 =C2=A0if (log.isTraceEnabled()) { > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0log.trace("Removed all ThreadC= ontext values from thread [" + Thread.currentThread().getName() + "]"); > - =C2=A0 =C2=A0 =C2=A0 =C2=A0} > - =C2=A0 =C2=A0} > - > - =C2=A0 =C2=A0/** > =C2=A0 =C2=A0 =C2=A0* First {@link #clear clears} the {@code ThreadContex= t} values and then > =C2=A0 =C2=A0 =C2=A0* {@link ThreadLocal#remove removes} the underlying {= @link ThreadLocal ThreadLocal} from the thread. > =C2=A0 =C2=A0 =C2=A0*

> @@ -255,11 +187,7 @@ public abstract class ThreadContext { > =C2=A0 =C2=A0 =C2=A0* @since 1.0 > =C2=A0 =C2=A0 =C2=A0*/ > =C2=A0 =C2=A0 public static void remove() { > - =C2=A0 =C2=A0 =C2=A0 =C2=A0if (resources !=3D null) { > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0clear(); > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0resources.remove(); > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0resources =3D null; > - =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0resources.remove(); > =C2=A0 =C2=A0 } > > =C2=A0 =C2=A0 /** > @@ -379,5 +307,27 @@ public abstract class ThreadContext { > =C2=A0 =C2=A0 public static Subject unbindSubject() { > =C2=A0 =C2=A0 =C2=A0 =C2=A0 return (Subject) remove(SUBJECT_KEY); > =C2=A0 =C2=A0 } > + > + =C2=A0 =C2=A0private static final class InheritableThreadLocalMap> extends InheritableThreadLocal> { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0protected Map initialValue()= { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return new HashMap(); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0/** > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 * This implementation was added to address = a > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 * > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 * user-reported issue. > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 * @param parentValue the parent value, a Ha= shMap as defined in the {@link #initialValue()} method. > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 * @return the HashMap to be used by any par= ent-spawned child threads (a clone of the parent HashMap). > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0@SuppressWarnings({"unchecked"}) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0protected Map childValue(Map= parentValue) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (parentValue !=3D null) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (Map) ((HashMap) parentValue).clone(); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return null; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} > =C2=A0} > > > >