You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@river.apache.org by pe...@apache.org on 2010/08/14 06:39:27 UTC

svn commit: r985427 - in /incubator/river/jtsk/trunk/src: net/jini/security/policy/ org/apache/river/api/security/ org/apache/river/imp/security/policy/cdc/ org/apache/river/imp/security/policy/se/

Author: peter_firmstone
Date: Sat Aug 14 04:39:26 2010
New Revision: 985427

URL: http://svn.apache.org/viewvc?rev=985427&view=rev
Log:
ExecutionContextManager implementation for the RevokableDynamicPolicy, please review.

Added:
    incubator/river/jtsk/trunk/src/org/apache/river/api/security/Reaper.java   (with props)
    incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/se/ECM.java   (with props)
Removed:
    incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/se/Controller.java
Modified:
    incubator/river/jtsk/trunk/src/net/jini/security/policy/DynamicPolicyProvider.java
    incubator/river/jtsk/trunk/src/org/apache/river/api/security/ExecutionContextManager.java
    incubator/river/jtsk/trunk/src/org/apache/river/api/security/PermissionGrant.java
    incubator/river/jtsk/trunk/src/org/apache/river/api/security/RevokeableDynamicPolicy.java
    incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/cdc/DynamicPolicyProviderImpl.java
    incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/se/DynamicConcurrentPolicyProvider.java

Modified: incubator/river/jtsk/trunk/src/net/jini/security/policy/DynamicPolicyProvider.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/net/jini/security/policy/DynamicPolicyProvider.java?rev=985427&r1=985426&r2=985427&view=diff
==============================================================================
--- incubator/river/jtsk/trunk/src/net/jini/security/policy/DynamicPolicyProvider.java (original)
+++ incubator/river/jtsk/trunk/src/net/jini/security/policy/DynamicPolicyProvider.java Sat Aug 14 04:39:26 2010
@@ -325,7 +325,7 @@ public class DynamicPolicyProvider exten
         return instance.getPermissionGrants();
     }
 
-    public ExecutionContextManager getExecutionContextManager(Permission p) {
-	return instance.getExecutionContextManager(p);
+    public ExecutionContextManager getExecutionContextManager() {
+	return instance.getExecutionContextManager();
     }
 }

Modified: incubator/river/jtsk/trunk/src/org/apache/river/api/security/ExecutionContextManager.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/api/security/ExecutionContextManager.java?rev=985427&r1=985426&r2=985427&view=diff
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/api/security/ExecutionContextManager.java (original)
+++ incubator/river/jtsk/trunk/src/org/apache/river/api/security/ExecutionContextManager.java Sat Aug 14 04:39:26 2010
@@ -28,14 +28,30 @@ import java.util.Set;
  * </p><p>
  * The ExecutionContextManager will only call 
  * AccessControlContext.checkPermission(Permission) once, for each context.  This
- * ensures that checkPermission isn't called again until the context changes, or
+ * ensures checkPermission isn't re called, until the context changes, or
  * the Permission checked by this ExecutionContextManager experiences a 
- * revoke for any ProtectionDomain by the RevokeableDynamicPolicy.
+ * revoke for any ProtectionDomain via a RevokeableDynamicPolicy.
  * </p><p>
- * A Runnable may be submitted to the ExecutionContextManager to be executed
+ * A Reaper may be submitted to the ExecutionContextManager to be executed
  * when a Permission Revocation matching the stored Permission occurs.
  * </p><p>
  * Use of this class is not limited to Revokeable Permission's.
+ * </p><p>
+ * Typical usage:
+ * </p>
+ * <code>
+ * ecm.begin(reaper);
+ * try{
+ *	    ecm.checkPermission(permissionA);
+ *	    ecm.checkPermission(permissionB);
+ *	    // do something
+ *	    return;
+ * } finally {
+ *	    ecm.end();
+ * }
+ * </code>
+ * <p>
+ * When protecting method's, the method must return from the try block.
  * </p>
  * @author Peter Firmstone
  * @see RevokeableDynamicPolicy
@@ -43,6 +59,32 @@ import java.util.Set;
  * @see AccessControlContext
  */
 public interface ExecutionContextManager {
+    
+    /**
+     * <p>
+     * Marks the beginning of Management of the Execution context, of the
+     * AccessControlContext and submits a reaper to intercept and clean up
+     * in the event of a revocation during the execution of the try finally
+     * block.  This method may be omitted if a Reaper is not required.  The
+     * consequence of there being no reaper, is that a call in progress during
+     * revocation will return normally immediately after revocation has 
+     * occurred, the permission will have been checked prior to revocation
+     * however and any further permission checks, if they have been revoked
+     * will throw an AccessControlException.
+     * <p></p>
+     * This links the current Thread to a Runnable
+     * Reaper.  The checkPermission() call places the Thread and
+     * AccessControlContext into the execution cache.
+     * <p></p>
+     * The execution cache is used to monitor methods or protected blocks that
+     * must be intercepted 
+     * </p>
+     * @param r - Reaper provided to clean up if Revocation occurs during
+     * the execution that follows this call, until the try block exits, 
+     * the current thread is not interrupted, rather the reaper is expected
+     * to know what resources need to be closed.
+     */
+    void begin(Reaper r);
 
     /**
      * <p>
@@ -68,27 +110,37 @@ public interface ExecutionContextManager
      * </p><p>
      * ExecutionContextManager should be used sparingly, the more generic
      * or widely applicable the Permission, the more efficient the 
-     * ExecutionContextManager is in memory usage terms.
-     * </p><p>
-     * This method also add's the current context to the current execution 
-     * cache, it is not removed from that cache until after the addAction 
-     * Runnable has been run, or accessControlExit() has been called.
+     * ExecutionContextManager is in memory usage terms.  Clients using
+     * the ECM, should be careful to release references to their permission
+     * objects, used permission checks, since garbage collection is relied
+     * upon to clean up cached AccessControlContext's, conversely, the
+     * permission shouldn't be created in the checkPermission(permission) call,
+     * since this would cause the object to be created on every invocation
+     * and probably garbage collected between invocations.
+     * </p><p>
+     * This method also add's the current thread and context to the execution 
+     * cache, it is not removed from that cache until after end() 
+     * has been called.
      * </p>
      * 
-     * @throws java.security.AccessControlException 
+     * @param p Permission to be checked, if result not already in cache.
+     * @throws java.security.AccessControlException
      */
-    public void checkPermission() throws AccessControlException;
+    public void checkPermission(Permission p) throws AccessControlException;
     
     /**
      * <p>
      * This method is to advise the ExecutionContextManager that the
      * current method or protected region has returned, it must
      * always follow the checkPermission() call, in response,
-     * the ECM removes the current context from the execution context cache.
+     * the ECM removes the current context from the execution context cache
+     * and releases the reference to the Runnable reaper.
      * </p><p>
      * If the execution context is still in the cache at the time of 
-     * revocation, the Runnable added by addAction will be run only if 
-     * affected directly by the revocation.  This is determined by
+     * revocation, the reaper will be run only if affected directly by the 
+     * revocation, the thread may be asked to wait for a short period, to
+     * allow the determination to be made. 
+     * Revocation applicability is determined by
      * AccessControlContext.checkPermission(Permission p) where p is the 
      * Permission affected.
      * </p><p>
@@ -96,44 +148,18 @@ public interface ExecutionContextManager
      * which always executes in the event of an exception or normal return.
      * </p>
      * <code>
+     * ecm.begin(reaper);
      * try{
-     *	    ecm.checkPermission();
+     *	    ecm.checkPermission(permission);
      *	    // do something
      *	    return;
-     * } catch (AccessControlException e) {
-     *	    throw new SecurityException("Method blah caused an...", e);
      * } finally {
-     *	    ecm.accessControlExit();
+     *	    ecm.end();
      * }
      * </code>
      * <p>
      * This should not be confused with AccessController.doPrivileged blocks
      * </p>
      */
-    public void accessControlExit();
-
-    /**
-     * Get the Permission monitored by this ExecutionContextManager.
-     * @return Permission monitored by the ExecutionContextManager
-     */
-    public Permission getPermission();
-
-    /**
-     * <p>
-     * Action to be taken in event that the Permission monitored by this
-     * ExecutionContextManager has experienced a revocation event.  This
-     * allows Sockets to be closed, or any clean up to occur or any other
-     * task that must be performed to reset state.
-     * </p><p>
-     * This may not be the only action performed, since the same
-     * ExecutionContextManager may be used by multiple clients, the Runnable
-     * is only weakly referenced, garbage collection is relied upon for its
-     * removal.
-     * </p><p>
-     * The implementer must have the Permission's required for
-     * execution, no privileges are assigned.
-     * </p>
-     * @param r - Clean up task to be performed.
-     */
-    public void addAction(Runnable r);
-}
+    void end();
+}
\ No newline at end of file

Modified: incubator/river/jtsk/trunk/src/org/apache/river/api/security/PermissionGrant.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/api/security/PermissionGrant.java?rev=985427&r1=985426&r2=985427&view=diff
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/api/security/PermissionGrant.java (original)
+++ incubator/river/jtsk/trunk/src/org/apache/river/api/security/PermissionGrant.java Sat Aug 14 04:39:26 2010
@@ -77,7 +77,7 @@ public interface PermissionGrant {
 
     /**
      * Returns an array of permissions defined by this PermissionGrant, array
-     * may be null, but non null array must not contain any null elements.
+     * may be null, but array must not contain null elements.
      * @return
      */
     Permission[] getPermissions();

Added: incubator/river/jtsk/trunk/src/org/apache/river/api/security/Reaper.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/api/security/Reaper.java?rev=985427&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/api/security/Reaper.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/api/security/Reaper.java Sat Aug 14 04:39:26 2010
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.river.api.security;
+
+/**
+ * A Reaper is used to clean up or alter execution.
+ * @author Peter Firmstone.
+ * @see ExecutionContextManager
+ */
+public interface Reaper extends Runnable {
+    
+    void put(Thread t);
+
+}

Propchange: incubator/river/jtsk/trunk/src/org/apache/river/api/security/Reaper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/river/jtsk/trunk/src/org/apache/river/api/security/RevokeableDynamicPolicy.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/api/security/RevokeableDynamicPolicy.java?rev=985427&r1=985426&r2=985427&view=diff
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/api/security/RevokeableDynamicPolicy.java (original)
+++ incubator/river/jtsk/trunk/src/org/apache/river/api/security/RevokeableDynamicPolicy.java Sat Aug 14 04:39:26 2010
@@ -51,8 +51,9 @@ public interface RevokeableDynamicPolicy
      * Revokes can only be performed synchronuously with other Revokes.
      * 
      * @param grants
+     * @throws java.lang.Exception if revoke unsuccessful.
      */
-    public void revoke(List<PermissionGrant> grants);
+    public void revoke(List<PermissionGrant> grants) throws Exception;
     /**
      * Get a List copy of the current PermissionGrant's in force.
      * @return
@@ -84,7 +85,7 @@ public interface RevokeableDynamicPolicy
      * @param p Permission the ExecutionContextManager will check.
      * @return a new ExecutionContextManager instance.
      */
-    public ExecutionContextManager getExecutionContextManager(Permission p);
+    public ExecutionContextManager getExecutionContextManager();
     /**
      * 
      * @return true if Revoke supported.

Modified: incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/cdc/DynamicPolicyProviderImpl.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/cdc/DynamicPolicyProviderImpl.java?rev=985427&r1=985426&r2=985427&view=diff
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/cdc/DynamicPolicyProviderImpl.java (original)
+++ incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/cdc/DynamicPolicyProviderImpl.java Sat Aug 14 04:39:26 2010
@@ -583,7 +583,7 @@ public class DynamicPolicyProviderImpl e
         throw new UnsupportedOperationException("Not supported.");
     }
 
-    public ExecutionContextManager getExecutionContextManager(Permission p) {
+    public ExecutionContextManager getExecutionContextManager() {
 	throw new UnsupportedOperationException("Not supported yet.");
     }
 }

Modified: incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/se/DynamicConcurrentPolicyProvider.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/se/DynamicConcurrentPolicyProvider.java?rev=985427&r1=985426&r2=985427&view=diff
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/se/DynamicConcurrentPolicyProvider.java (original)
+++ incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/se/DynamicConcurrentPolicyProvider.java Sat Aug 14 04:39:26 2010
@@ -162,6 +162,7 @@ public class DynamicConcurrentPolicyProv
 //    private final WriteLock dwl;
 //    private final Set<Denied> denied;
 //    private volatile boolean checkDenied;
+    private final ECM execControlManager;
     
     
     public DynamicConcurrentPolicyProvider(){
@@ -179,6 +180,7 @@ public class DynamicConcurrentPolicyProv
 //        denied = new HashSet<Denied>(30);
 //        checkDenied = false;
 	grantLock = new Object();
+	execControlManager = new ECM();
     }
     
     /**
@@ -529,7 +531,7 @@ public class DynamicConcurrentPolicyProv
 	}
     }
 
-    public void revoke(List<PermissionGrant> grants) {
+    public void revoke(List<PermissionGrant> grants) throws Exception {
         if (initialized == false) throw new RuntimeException("Object not initialized");
         if (basePolicyIsDynamic && revokeable){
             RevokeableDynamicPolicy bp = (RevokeableDynamicPolicy) basePolicy;
@@ -537,7 +539,7 @@ public class DynamicConcurrentPolicyProv
             return;
         }
         AccessController.checkPermission(new RevokePermission());
-	HashSet<Class> removed = new HashSet<Class>();
+	HashSet<Permission> removed = new HashSet<Permission>();
 	List<Runnable> jobs = null;
 	HashSet<PermissionGrant> holder = new HashSet<PermissionGrant>(pGrants.length);
 	synchronized (grantLock){
@@ -549,7 +551,7 @@ public class DynamicConcurrentPolicyProv
 		    Permission [] perms = grantCache.get(pGrants[i]);
 		    int len = perms.length;
 		    for ( int c =0; c < len ; c++ ){
-			removed.add(perms[c].getClass());
+			removed.add(perms[c]);
 		    }
 		    continue;
 		}
@@ -557,10 +559,8 @@ public class DynamicConcurrentPolicyProv
 	    }
 	    PermissionGrant[] updated = new PermissionGrant[holder.size()];
 	    pGrants = holder.toArray(updated);
-	    jobs = Controller.revoke(removed);
+	    execControlManager.revoke(removed);
 	}
-	//TODO jobs to tidy up after revocation.
-	
     }
 
     public List<PermissionGrant> getPermissionGrants() {
@@ -577,9 +577,8 @@ public class DynamicConcurrentPolicyProv
 	return grants;
     }
 
-
-    public ExecutionContextManager getExecutionContextManager(Permission p) {
-	return Controller.getECManager(p);
+    public ExecutionContextManager getExecutionContextManager() {
+	return execControlManager;
     }
 
 }

Added: incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/se/ECM.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/se/ECM.java?rev=985427&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/se/ECM.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/se/ECM.java Sat Aug 14 04:39:26 2010
@@ -0,0 +1,254 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.river.imp.security.policy.se;
+
+import java.security.AccessControlContext;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.Permission;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import org.apache.river.api.security.ExecutionContextManager;
+import org.apache.river.api.security.Reaper;
+import org.apache.river.imp.util.ConcurrentWeakIdentityMap;
+
+/**
+ * Only a Single instance of ECM is required per policy, it is threadsafe.
+ * Threads will wait until revoke is complete.
+ * 
+ * @author Peter Firmstone
+ */
+class ECM implements ExecutionContextManager{
+    
+    private final ConcurrentMap<Permission,Set<AccessControlContext>> checkedCache;
+    private final ConcurrentMap<AccessControlContext, Set<Thread>> executionCache;
+    private final ConcurrentMap<Thread, Set<AccessControlContext>> threadAssociation;
+    private final ConcurrentMap<Thread, Reaper> association;
+    private final ExecutorService executor;
+    private final ReadWriteLock blockLock;
+    private final Lock rl; // This lock is held briefly by callers of begin and end.
+    private final Lock wl; // This lock is held by revocation.
+    
+    ECM(){
+	/* The clients control garbage collection, the Permission objects
+	 * are those passed by clients.*/
+	checkedCache = new ConcurrentWeakIdentityMap<Permission, Set<AccessControlContext>>();
+	/* The thread association controls the removal of AccessContolContext
+	 * keys from the executionCache, since the threadAssociation holds a 
+	 * strong reference from the thread, which is removed when end()
+	 * is executed.
+	 */ 
+	executionCache = new ConcurrentWeakIdentityMap<AccessControlContext, Set<Thread>>();
+	threadAssociation = new ConcurrentHashMap<Thread, Set<AccessControlContext>>();
+	/* The association is only made while threads are within the clients
+	 * try finally block.
+	 */ 
+	association = new ConcurrentHashMap<Thread, Reaper>();
+	// TODO: Analyse needs, enable client configuration of thread pool.
+	executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()+1);
+	/* This lock guards revocation */ 
+	blockLock = new ReentrantReadWriteLock();
+	rl = blockLock.readLock();
+	wl = blockLock.writeLock();
+    }
+    
+    void revoke(Set<Permission> perms) throws InterruptedException, ExecutionException{
+	wl.lock();
+	try {
+	    /* This is where we determine what needs to be revoked, we first
+	     * get all the AccessControlContexts for the Permission class,
+	     * these are removed from the checkedCache, then we narrow
+	     * down the AccessControlContext's to only those in the
+	     * execution cache, each AccessControlContext in the execution cache
+	     * has checkPermission(Permission) called for each permission
+	     * with a Class identical to one of the revoked permission's.  
+	     * Any AccessControlContext's that throw AccessControlException will be
+	     * caught and have a Reaper run, when it exists, for all Threads referenced
+	     * from that AccessControlContext.
+	     * 
+	     * The RevokeableDynamicPolicy will have updated the current
+	     * Permission's after revocation, so the ProtectionDomain's in
+	     * the AccessControlContext will now throw an AccessControlException
+	     * if the revocation applied to them.
+	     * 
+	     * The wl lock will be released, any threads that were interrupted
+	     * will exit through the finally block and remove themselves
+	     * from the execution cache.  Those that aren't may throw
+	     * an exception and bubble up the stack, due to closing sockets
+	     * etc.
+	     * 
+	     * The execution cache is comprised of the following fields:
+	     * executionCache
+	     * threadAssociation
+	     */ 
+	    // Identify Permission's with matching class files to those revoked.
+	    Set<Class> permClasses = new HashSet<Class>();
+	    Iterator<Permission> itp = perms.iterator();
+	    while (itp.hasNext()){
+		permClasses.add(itp.next().getClass());
+	    }
+	    // Remove Permission's and AccessControlContexts from the checked cache.
+	    Map<Permission, Set<AccessControlContext>> removed = 
+		    new HashMap<Permission, Set<AccessControlContext>>();
+	    Iterator<Permission> keysIt = checkedCache.keySet().iterator();
+	    while (keysIt.hasNext()){
+		Permission p = keysIt.next();
+		if (permClasses.contains(p.getClass())){
+		    Set<AccessControlContext> a = checkedCache.get(p);
+		    keysIt.remove();
+		    removed.put(p, a);
+		}		
+	    }
+	    // Match the AccessControlContexts with the execution cache;
+	    Set<AccessControlContext> exCache = executionCache.keySet();
+	    // Get the AccessControlContext's in the execution cache that fail.
+	    Set<AccessControlContext> accFails = new HashSet<AccessControlContext>();
+	    Iterator<Permission> retests = removed.keySet().iterator();
+	    while (retests.hasNext()){
+		Permission p = retests.next();
+		Set<AccessControlContext> rechecks = removed.get(p);
+		Iterator<AccessControlContext> recheck = rechecks.iterator();
+		while (recheck.hasNext()){
+		    AccessControlContext a = recheck.next();
+		    if (accFails.contains(a)) continue;
+		    // This really narrows down the checks.
+		    if (exCache.contains(a)){
+			try { 
+			    a.checkPermission(p);
+			} catch (AccessControlException e){
+			    accFails.add(a);
+			}
+		    }
+		}
+	    }
+	    // Identify the threads and prepare reapers.
+	    Set<Runnable> reapers = new HashSet<Runnable>();
+	    Iterator<AccessControlContext> failedAcc = accFails.iterator();
+	    while (failedAcc.hasNext()){
+		AccessControlContext fail = failedAcc.next();
+		Set<Thread> threads = executionCache.get(fail);
+		Iterator<Thread> i = threads.iterator();
+		while (i.hasNext()) {
+		    Thread t = i.next();
+		    Reaper r = association.get(t);
+		    if ( r == null ) continue;
+		    r.put(t);
+		    reapers.add(r);
+		}		
+	    }
+	    /* Process the reapers, this requires a thread pool, but we don't
+	     * want to return until all reapers have completed.
+	     */
+	    Iterator<Runnable> reaper = reapers.iterator();
+	    List<Future> results = new ArrayList<Future>(reapers.size());
+	    while ( reaper.hasNext()) {
+		results.add(executor.submit(reaper.next()));
+	    }
+	    Iterator<Future> result = results.iterator();
+	    while (result.hasNext()){
+		// Waits for result.
+		result.next().get();
+	    }
+	    /* We're done, go home & rest */
+	} finally {
+	    wl.unlock();
+	}
+    }
+
+    public void begin(Reaper r) {
+	Thread currentThread = Thread.currentThread();
+	if ( r == null ) return;
+	association.put(currentThread, r);	
+    }
+
+    public void checkPermission(Permission p) throws AccessControlException {
+	Thread currentThread = Thread.currentThread();
+	AccessControlContext executionContext = AccessController.getContext();
+	rl.lock();
+	try {
+	    // execution cache, fast for repeated calls.
+	    Set<Thread> exCacheThreadSet = executionCache.get(executionContext);
+	    if ( exCacheThreadSet == null ){
+		exCacheThreadSet = Collections.synchronizedSet(new HashSet<Thread>());
+		Set<Thread> existed = executionCache.putIfAbsent(executionContext, exCacheThreadSet);
+		if (existed != null){
+		    exCacheThreadSet = existed;
+		}
+	    }
+	    exCacheThreadSet.add(currentThread);// end execution cache.
+	    // thread association, fast for repeated calls.
+	    Set<AccessControlContext> thAssocSet = threadAssociation.get(currentThread);
+	    if ( thAssocSet == null ){
+		thAssocSet = Collections.synchronizedSet(new HashSet<AccessControlContext>());
+		Set<AccessControlContext> existed = threadAssociation.putIfAbsent(currentThread, thAssocSet);
+		if (existed != null){
+		    thAssocSet = existed;
+		}
+	    }
+	    thAssocSet.add(executionContext); // end thread association.
+	    // checkedCache - the permission check, fast for repeated calls.
+	    Set<AccessControlContext> checked = checkedCache.get(p);
+	    if (checked == null ){
+		checked = Collections.synchronizedSet(new HashSet<AccessControlContext>());
+		Set<AccessControlContext> existed = checkedCache.putIfAbsent(p, checked);
+		if (existed != null){
+		    checked = existed;
+		}
+	    }
+	    if ( checked.contains(executionContext)) return; // it's passed before.
+	    executionContext.checkPermission(p); // Throws AccessControlException
+	    // If we get here cache the AccessControlContext.
+	    checked.add(executionContext); // end checkedCache.	    
+	} finally {
+	    rl.unlock();
+	}
+    }
+
+    public void end() {
+	// Removal from execution cache.
+	Thread t = Thread.currentThread();
+	rl.lock();
+	try {
+	    association.remove(t);
+	    Set<AccessControlContext> accSet = threadAssociation.remove(t);
+	    Iterator<AccessControlContext> it = accSet.iterator();
+	    while (it.hasNext()){
+		AccessControlContext acc = it.next();
+		executionCache.get(acc).remove(t);
+	    }
+	}finally {
+	    rl.unlock();
+	}	
+    }
+}

Propchange: incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/se/ECM.java
------------------------------------------------------------------------------
    svn:eol-style = native