river-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From peter_firmst...@apache.org
Subject svn commit: r928394 [3/6] - in /incubator/river/jtsk/trunk: ./ qa/ qa/harness/policy/ qa/jtreg/net/jini/jeri/kerberos/UnitTests/ qa/jtreg/net/jini/jeri/transport/multihomed/ qa/jtreg/unittestlib/ qa/src/com/sun/jini/qa/harness/ qa/src/com/sun/jini/qa/r...
Date Sun, 28 Mar 2010 12:57:05 GMT
Added: incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/ConcurrentPolicyFile.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/ConcurrentPolicyFile.java?rev=928394&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/ConcurrentPolicyFile.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/ConcurrentPolicyFile.java Sun Mar 28 12:57:03 2010
@@ -0,0 +1,317 @@
+/*
+ *  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.
+ */
+
+ /**
+  * Default Policy implementation taken from Apache Harmony, refactored for
+  * concurrency.
+  * 
+  * @author Alexey V. Varlamov
+  * @author Peter Firmstone
+  * @version $Revision$
+  */
+
+package org.apache.river.security.concurrent;
+
+import org.apache.river.security.policy.util.DefaultPolicyParser;
+import org.apache.river.security.policy.util.PolicyUtils;
+import java.io.File;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Policy;
+import java.security.ProtectionDomain;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
+import org.apache.river.security.policy.util.PolicyEntry;
+import org.apache.river.security.policy.util.PolicyParser;
+import org.apache.river.util.concurrent.WeakIdentityMap;
+
+
+/**
+ * Concurrent Policy implementation based on policy configuration files,
+ * it is intended to provide concurrent implies() for greatly improved
+ * throughput at the expense of memory usage.
+ * 
+ * Set the following system properties to use this Policy instead of the
+ * built in Java sun.security.provider.PolicyFile:
+ *  
+ * net.jini.security.policy.PolicyFileProvider.basePolicyClass = 
+ * org.apache.river.security.concurrent.ConcurrentPolicyFile
+ * 
+ * 
+ * This
+ * implementation recognizes text files, consisting of clauses with the
+ * following syntax:
+ * 
+ * <pre>
+ * keystore &quot;some_keystore_url&quot; [, &quot;keystore_type&quot;];
+ * </pre>
+ <pre>
+ * grant [SignedBy &quot;signer_names&quot;] [, CodeBase &quot;URL&quot;]
+ *  [, Principal [principal_class_name] &quot;principal_name&quot;]
+ *  [, Principal [principal_class_name] &quot;principal_name&quot;] ... {
+ *  permission permission_class_name [ &quot;target_name&quot; ] [, &quot;action&quot;] 
+ *  [, SignedBy &quot;signer_names&quot;];
+ *  permission ...
+ *  };
+ *  
+ * </pre>
+ * 
+ * The <i>keystore </i> clause specifies reference to a keystore, which is a
+ * database of private keys and their associated digital certificates. The
+ * keystore is used to look up the certificates of signers specified in the
+ * <i>grant </i> entries of the file. The policy file can contain any number of
+ * <i>keystore </i> entries which can appear at any ordinal position. However,
+ * only the first successfully loaded keystore is used, others are ignored. The
+ * keystore must be specified if some grant clause refers to a certificate's
+ * alias. <br>
+ * The <i>grant </i> clause associates a CodeSource (consisting of an URL and a
+ * set of certificates) of some executable code with a set of Permissions which
+ * should be granted to the code. So, the CodeSource is defined by values of
+ * <i>CodeBase </i> and <i>SignedBy </i> fields. The <i>CodeBase </i> value must
+ * be in URL format, while <i>SignedBy </i> value is a (comma-separated list of)
+ * alias(es) to keystore certificates. These fields can be omitted to denote any
+ * codebase and any signers (including case of unsigned code), respectively.
+ * <br>
+ * Also, the code may be required to be executed on behalf of some Principals
+ * (in other words, code's ProtectionDomain must have the array of Principals
+ * associated) in order to possess the Permissions. This fact is indicated by
+ * specifying one or more <i>Principal </i> fields in the <i>grant </i> clause.
+ * Each Principal is specified as class/name pair; name and class can be either
+ * concrete value or wildcard <i>* </i>. As a special case, the class value may
+ * be omitted and then the name is treated as an alias to X.509 Certificate, and
+ * the Principal is assumed to be javax.security.auth.x500.X500Principal with a
+ * name of subject's distinguished name from the certificate. <br>
+ * The order between the <i>CodeBase </i>, <i>SignedBy </i>, and <i>Principal
+ * </i> fields does not matter. The policy file can contain any number of grant
+ * clauses. <br>
+ * Each <i>grant </i> clause must contain one or more <i>permission </i> entry.
+ * The permission entry consist of a fully qualified class name along with
+ * optional <i>name </i>, <i>actions </i> and <i>signedby </i> values. Name and
+ * actions are arguments to the corresponding constructor of the permission
+ * class. SignedBy value represents the keystore alias(es) to certificate(s)
+ * used to sign the permission class. That is, this permission entry is
+ * effective (i.e., access control permission will be granted based on this
+ * entry) only if the bytecode implementation of permission class is verified to
+ * be correctly signed by the said alias(es). <br>
+ * <br>
+ * The policy content may be parameterized via property expansion. Namely,
+ * expressions like <i>${key} </i> are replaced by values of corresponding
+ * system properties. Also, the special <i>slash </i> key (i.e. ${/}) is
+ * supported, it is a shortcut to &quot;file.separator&quot; key. Property
+ * expansion is performed anywhere a double quoted string is allowed in the
+ * policy file. However, this feature is controlled by security properties and
+ * should be turned on by setting &quot;policy.expandProperties&quot; property
+ * to <i>true </i>. <br>
+ * If property expansion fails (due to a missing key), a corresponding entry is
+ * ignored. For fields of <i>keystore </i> and <i>grant </i> clauses, the whole
+ * clause is ignored, and for <i>permission </i> entry, only that entry is
+ * ignored. <br>
+ * <br>
+ * The policy also supports generalized expansion in permissions names, of
+ * expressions like <i>${{protocol:data}} </i>. Currently the following
+ * protocols supported:
+ * <dl>
+ * <dt>self
+ * <dd>Denotes substitution to a principal information of the parental Grant
+ * entry. Replaced by a space-separated list of resolved Principals (including
+ * wildcarded), each formatted as <i>class &quot;name&quot; </i>. If parental
+ * Grant entry has no Principals, the permission is ignored.
+ * <dt>alias: <i>name </i>
+ * <dd>Denotes substitution of a KeyStore alias. Namely, if a KeyStore has an
+ * X.509 certificate associated with the specified name, then replaced by
+ * <i>javax.security.auth.x500.X500Principal &quot; <i>DN </i>&quot; </i>
+ * string, where <i>DN </i> is a certificate's subject distinguished name.
+ * </dl>
+ * <br>
+ * <br>
+ * This implementation is thread-safe. The policy caches sets of calculated
+ * permissions for the requested objects (ProtectionDomains and CodeSources) via
+ * WeakHashMap; the cache is cleaned either explicitly during refresh()
+ * invocation, or naturally by garbage-collecting the corresponding objects.
+ * 
+ * @see org.apache.harmony.security.PolicyUtils#getPolicyURLs(Properties, String,
+ *      String)
+ */
+
+public class ConcurrentPolicyFile extends Policy {
+
+    /**
+     * System property for dynamically added policy location.
+     */
+    public static final String JAVA_SECURITY_POLICY = "java.security.policy"; //$NON-NLS-1$
+
+    /**
+     * Prefix for numbered Policy locations specified in security.properties.
+     */
+    public static final String POLICY_URL_PREFIX = "policy.url."; //$NON-NLS-1$
+
+    // A set of PolicyEntries constituting this Policy.
+    private final ReentrantReadWriteLock rwl;
+    private final ReadLock rl;
+    private final WriteLock wl;
+    
+    private Set<PolicyEntry> grants = new HashSet<PolicyEntry>(); // protected by rwl
+
+    // Calculated Permissions cache, organized as
+    // Map{Object->Collection&lt;Permission&gt;}.
+    // The Object is a ProtectionDomain, a CodeSource or
+    // any other permissions-granted entity.
+    private final ConcurrentMap<Object, Collection<Permission>> cache = 
+            new WeakIdentityMap<Object, Collection<Permission>>();
+
+    // A specific parser for a particular policy file format.
+    private final PolicyParser parser;
+    
+    /**
+     * Default constructor, equivalent to
+     * <code>ConcurrentPolicyFile(new DefaultPolicyParser())</code>.
+     */
+    public ConcurrentPolicyFile() {
+        this(new DefaultPolicyParser());
+    }
+
+    /**
+     * Extension constructor for plugging-in a custom parser.
+     * @param dpr 
+     */
+    public ConcurrentPolicyFile(PolicyParser dpr) {
+        parser = dpr;
+        rwl = new ReentrantReadWriteLock();
+        rl = rwl.readLock();
+        wl = rwl.writeLock();
+        refresh();
+    }
+
+    /**
+     * Returns collection of permissions allowed for the domain 
+     * according to the policy. The evaluated characteristics of the 
+     * domain are it's codesource and principals; they are assumed
+     * to be <code>null</code> if the domain is <code>null</code>.
+     * @param pd ProtectionDomain
+     * @see ProtectionDomain
+     */
+    @Override
+    public PermissionCollection getPermissions(ProtectionDomain pd) {
+        CodeSource cs = pd.getCodeSource();
+        Collection<Permission> pc = cache.get(cs); // saves new object creation.
+        if (pc == null){
+            // Just because the new object is contained within a ConcurrentMap
+            // doesn't mean it doesn't need to be synchronized!
+            pc = Collections.synchronizedSet( new HashSet<Permission>() );
+            Collection<Permission> existed = cache.putIfAbsent(cs, pc);
+            if ( !(existed == null) ){ pc = existed;}
+        }
+        try {
+            rl.lock();
+            Iterator<PolicyEntry> it = grants.iterator();
+            while (it.hasNext()) {
+                PolicyEntry ge = it.next();
+                if (ge.impliesPrincipals(pd == null ? null : pd.getPrincipals())
+                    && ge.impliesCodeSource(pd == null ? null : pd.getCodeSource())) {
+                    pc.addAll(ge.getPermissions());
+                }
+            }               
+        } finally { rl.unlock(); }        
+        return PolicyUtils.toPermissionCollection(pc);
+    }
+
+    /**
+     * Returns collection of permissions allowed for the codesource 
+     * according to the policy. 
+     * The evaluation assumes that current principals are undefined.
+     * @param cs CodeSource
+     * @see CodeSource
+     */
+    @Override
+    public PermissionCollection getPermissions(CodeSource cs) {
+        Collection<Permission> pc = cache.get(cs); // saves new object creation.
+        if (pc == null){
+            // Just because the new object is contained within a ConcurrentMap
+            // doesn't mean it doesn't need to be synchronized!
+            pc = Collections.synchronizedSet( new HashSet<Permission>() );
+            Collection<Permission> existed = cache.putIfAbsent(cs, pc);
+            if ( !(existed == null) ){ pc = existed;}
+        }
+        try {
+            rl.lock();
+            Iterator<PolicyEntry> it = grants.iterator();
+            while (it.hasNext()) {
+                PolicyEntry ge = it.next();
+                if (ge.impliesPrincipals(null)
+                    && ge.impliesCodeSource(cs)) {
+                    pc.addAll(ge.getPermissions()); // we still hold a reference
+                }
+            }     
+        } finally { rl.unlock(); }
+        return PolicyUtils.toPermissionCollection(pc);
+    }
+    
+    @Override
+    public boolean implies(ProtectionDomain domain, Permission permission) {
+	PermissionCollection pc = getPermissions(domain);
+	if (pc == null) {
+	    return false;
+	}
+	return pc.implies(permission);
+    }
+
+    /**
+     * Gets fresh list of locations and tries to load all of them in sequence;
+     * failed loads are ignored. After processing all locations, old policy
+     * settings are discarded and new ones come into force. <br>
+     * 
+     * @see PolicyUtils#getPolicyURLs(Properties, String, String)
+     */
+    @Override
+    public void refresh() {
+        Set<PolicyEntry> fresh = new HashSet<PolicyEntry>();
+        Properties system = new Properties(AccessController
+                .doPrivileged(new PolicyUtils.SystemKit()));
+        system.setProperty("/", File.separator); //$NON-NLS-1$
+        URL[] policyLocations = PolicyUtils.getPolicyURLs(system,
+                                                          JAVA_SECURITY_POLICY,
+                                                          POLICY_URL_PREFIX);
+        for (int i = 0; i < policyLocations.length; i++) {
+            try {
+                //TODO debug log
+                //System.err.println("Parsing policy file: " + policyLocations[i]);
+                Collection<PolicyEntry> pc = parser.parse(policyLocations[i], system);
+                fresh.addAll(pc);
+            } catch (Exception e) {
+                // TODO log warning
+                //System.err.println("Ignoring policy file: " 
+                //                 + policyLocations[i] + ". Reason:\n"+ e);
+            }
+        }
+        try {
+            wl.lock();
+            grants = fresh;
+            cache.clear();
+        }finally {wl.unlock();}
+    }
+}

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

Added: incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/DyanamicConcurrentPolicyProvider.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/DyanamicConcurrentPolicyProvider.java?rev=928394&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/DyanamicConcurrentPolicyProvider.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/DyanamicConcurrentPolicyProvider.java Sun Mar 28 12:57:03 2010
@@ -0,0 +1,283 @@
+
+
+package org.apache.river.security.concurrent;
+
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Policy;
+import java.security.Principal;
+import java.security.ProtectionDomain;
+import java.security.Provider;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
+import net.jini.security.policy.DynamicPolicy;
+import net.jini.security.policy.PolicyInitializationException;
+import org.apache.river.security.policy.spi.RevokeableDynamicPolicySpi;
+import org.apache.river.security.policy.util.PolicyEntry;
+import org.apache.river.security.policy.util.PolicyUtils;
+import org.apache.river.util.concurrent.WeakIdentityMap;
+
+/**
+ * This is a Dynamic Policy Provider that supports concurrent access,
+ * for instances where a Policy provider is used for a distributed network
+ * of computers, or where there is a large number of ProtectionDomains and
+ * hence the opportunity for concurrency exists, concurrency comes with a 
+ * cost however, that of increased memory usage.
+ * 
+ * Due to the Java 2 Security system's static design, a Policy Provider
+ * can only augment the policy files utilised, that is it can only relax security
+ * by granting additional permissions, this implementation adds an experimental 
+ * feature for revoking permissions, however there are some caveats:
+ * 
+ * Firstly if the Policy.refresh() method is called, followed by the 
+ * ProtectionDomain.toString() method, the ProtectionDomain
+ * merge the permissions, from the policy with those in the ProtectionDomain, 
+ * a ProtectionDomain cannot have Permissions
+ * removed, only additional merged. 
+ * 
+ * So in order to prevent dynamic grants from finding
+ * their way into a ProtectionDomain's private PermissionCollection,
+ * one would have to ensure that no dynamically grantable permissions are 
+ * returned via the methods:
+ * 
+ * getPermissions(Codesource source) or
+ * getPermissions(ProtectionDomain domain)
+ * 
+ * This is different to the behaviour of the existing Jini 2.0
+ * DynamicPolicyProvider implementation where dynamically granted Permissions
+ * are added.
+ * 
+ * However when a Policy is checked via implies(ProtectionDomain d, Permission p)
+ * this implementation checks the dynamic grants.
+ * 
+ * This means that if a DynamicPolicy is utilised as the base Policy class
+ * and if it returns dynamically granted permissions, then those permissions
+ * cannot be revoked.
+ * 
+ * It is thus reccommeded that Static policy files only be used for files
+ * where the level of trust is relatively static.  This is the only implementation
+ * where a dyanamic grant can be removed.  In the case of Proxy trust, a proxy
+ * is no longer trusted when it has lost contact with it's Principal (server)
+ * because the server cannot be asked if it trusts it's proxy and the proxy
+ * cannot be given a thread of control to find it's server because it has
+ * already attained too many Permissions.  In this new implementation it should
+ * be possible to revoke AllPermission and grant Permissions dynamically as 
+ * trust is gained.
+ * 
+ * This may cause some undesireable side effects in existing programs.
+ * 
+ * There is one final reccommendation and that is adopting / utilising an OSGi
+ * Framework to enable far greater control over dynamic Permissions than this hack
+ * implementation provides.
+ * 
+ * To make the best utilisation of this Policy provider, set the System property:
+ * 
+ * net.jini.security.policy.PolicyFileProvider.basePolicyClass = 
+ * org.apache.river.security.concurrent.ConcurrentPolicyFile
+ * 
+ * @author Peter Firmstone
+ * @version 1
+ * @since 2.2
+ * @see ProtectionDomain
+ * @see Policy
+ * @see ConcurrentPolicyFile
+ * @see net.jini.security.policy.PolicyFileProvider
+ * @see ConcurrentPermissionCollection
+ */
+
+public class DyanamicConcurrentPolicyProvider implements RevokeableDynamicPolicySpi {
+    
+    // A set of PolicyEntries constituting this Policy.
+    // PolicyEntry is lighter weight than PermissionCollection.
+    private final ReentrantReadWriteLock rwl;
+    private final ReadLock rl;
+    private final WriteLock wl;    
+    private final Set<PolicyEntry> dynamicGrants; // protected by rwl    
+    private volatile Policy basePolicy; // effectively final looks after its own sync
+    private final ConcurrentMap<ProtectionDomain, PermissionCollection> cache;
+    private volatile boolean basePolicyIsDynamic;
+    private boolean initialized = false;
+    // do something about some domain permissions for this domain so we can 
+    // avoid dead locks due to bug 4911907
+    
+    
+    public DyanamicConcurrentPolicyProvider(){
+        rwl = new ReentrantReadWriteLock();
+        rl = rwl.readLock();
+        wl = rwl.writeLock();
+        dynamicGrants = new HashSet<PolicyEntry>();
+        basePolicy = null;
+        cache = new WeakIdentityMap<ProtectionDomain, PermissionCollection>();
+        basePolicyIsDynamic = false;
+    }
+    
+    /**
+     * Idempotent method.
+     * @param basePolicy
+     * @return
+     */
+    public boolean basePolicy(Policy basePolicy) {
+        if (initialized == true) return false;
+        this.basePolicy = basePolicy;
+        return true;
+    }
+
+    /** 
+     * Idempotent method. 
+     */ 
+    public void initialize() throws PolicyInitializationException {
+        if (basePolicy == null) throw new PolicyInitializationException("Base Policy hasn't " +
+                "been set cannot initialize", new Exception("Failed to initialize"));
+        if (basePolicy instanceof DynamicPolicy) basePolicyIsDynamic = true;
+        initialized = true;
+    }
+
+    public void ensureDependenciesResolved() {
+        if (initialized == false) throw new RuntimeException("Object not initialized");
+    
+    }
+
+    public void revoke(Class cl, Principal[] principals, Permission[] permissions) {
+        if (initialized == false) throw new RuntimeException("Object not initialized");
+        /* The removal begins with removal from the dynamicGrants then the cache
+         * while dynamicGrants is write locked, otherwise it could be added 
+         * again due to a concurrent implies during the removal process.
+         * Actually the decision has been made to release the lock as soon as
+         * possible to prevent possible deadlocks, increase concurrency at the
+         * risk of possible positive implies() the the mean time.
+         */       
+        ProtectionDomain domain = cl.getProtectionDomain();
+        CodeSource codeSource = domain.getCodeSource();
+        Collection<Permission> permToBeRemoved = Arrays.asList(permissions);
+        Collection<Permission> remainingGrants = new HashSet<Permission>();
+        try {
+            wl.lock();
+            Iterator<PolicyEntry> it = dynamicGrants.iterator();
+            while (it.hasNext()) {
+                PolicyEntry ge = it.next();
+                if (ge.impliesPrincipals(domain == null ? null : principals)
+                    && ge.impliesCodeSource(domain == null ? null : codeSource)) {
+                    remainingGrants.addAll( ge.getPermissions());
+                    it.remove();
+                }               
+            }
+            if (remainingGrants.isEmpty()) return; // nothing to do.
+        } finally { wl.unlock(); }
+        /* Now we can remove the PermissionDomain from the cache.
+         * The cache will populate itself again correctly when implies() is
+         * called on that PermissionDomain again.
+         */
+        cache.remove(cl);
+        /* We must re-enter the remaining grants if any exist. */
+        remainingGrants.removeAll(permToBeRemoved);
+        PolicyEntry policyEntry = new PolicyEntry(codeSource, 
+                Arrays.asList(principals), remainingGrants);
+        try {
+            wl.lock();
+            dynamicGrants.add(policyEntry);
+        } finally { wl.unlock(); }
+    }
+
+    public boolean revokeSupported() {
+        if (initialized == false) throw new RuntimeException("Object not initialized");
+        return true;
+    }
+
+    public Provider getProvider() {
+        if (initialized == false) throw new RuntimeException("Object not initialized");
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public String getType() {
+        if (initialized == false) throw new RuntimeException("Object not initialized");
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public PermissionCollection getPermissions(CodeSource codesource) {
+        if (initialized == false) throw new RuntimeException("Object not initialized");
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public PermissionCollection getPermissions(ProtectionDomain domain) {
+        if (initialized == false) throw new RuntimeException("Object not initialized");
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public boolean implies(ProtectionDomain domain, Permission permission) {
+        if (initialized == false) throw new RuntimeException("Object not initialized");
+        //First check the our cache
+        if (basePolicyIsDynamic && cache.get(domain).implies(permission)) return true;
+        // Then check the base policy
+        if (basePolicy.implies(domain, permission)) return true;
+        // If it doesn't then we should check if it has any grants
+        Collection<Permission> dynamicallyGrantedPermissions = null;
+        try {
+            rl.lock();
+            Iterator<PolicyEntry> it = dynamicGrants.iterator();
+            while (it.hasNext()) {
+                PolicyEntry ge = it.next();
+                if (ge.impliesPrincipals(domain == null ? null : domain.getPrincipals())
+                    && ge.impliesCodeSource(domain == null ? null : domain.getCodeSource())) {
+                    dynamicallyGrantedPermissions = ge.getPermissions();
+                }
+            }               
+        } finally { rl.unlock(); }
+        if (dynamicallyGrantedPermissions == null) return false;
+        if (dynamicallyGrantedPermissions.isEmpty()) return false;
+        // Operation starts to get expensive
+        PermissionCollection pc = null;
+        if ( !(basePolicyIsDynamic) ) pc = cache.get(domain); // saves new object creation.
+        if (pc == null){
+            pc = basePolicy.getPermissions(domain);
+            if (pc == null) pc = new ConcurrentPermissions();
+            if (!(pc instanceof ConcurrentPermissions)) {
+                pc = PolicyUtils.toConcurrentPermissions(pc);
+            }           
+            PermissionCollection existed = cache.putIfAbsent(domain, pc);
+            if ( !(existed == null) ){ pc = existed;} //Another thread might have just done it!
+        }        
+        Iterator<Permission> dgpi = dynamicallyGrantedPermissions.iterator();
+        while (dgpi.hasNext()){
+            pc.add(dgpi.next());
+        }
+        // If we get refreshed the cache could be empty, which is more pedantic
+        // however the result may still be true so we'll return it anyway.
+        return pc.implies(permission);
+    }
+
+    public void refresh() {
+        if (initialized == false) throw new RuntimeException("Object not initialized");
+        cache.clear();
+        basePolicy.refresh();
+        
+    }
+
+    public boolean grantSupported() {
+        if (initialized == false) throw new RuntimeException("Object not initialized");
+        return true;
+    }
+
+    public void grant(Class cl, Principal[] principals, Permission[] permissions) {
+        CodeSource cs = cl.getProtectionDomain().getCodeSource();
+        Collection<Principal> pal = Arrays.asList(principals);
+        Collection<Permission> perm = Arrays.asList(permissions);
+        PolicyEntry pe = new PolicyEntry(cs, pal, perm);
+        try {
+            wl.lock();
+            dynamicGrants.add(pe);           
+        } finally {wl.unlock();}
+    }
+
+    public Permission[] getGrants(Class cl, Principal[] principals) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+}

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

Added: incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/Grants.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/Grants.java?rev=928394&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/Grants.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/Grants.java Sun Mar 28 12:57:03 2010
@@ -0,0 +1,123 @@
+package org.apache.river.security.concurrent;
+
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Arrays;
+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.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import org.apache.river.security.concurrent.ConcurrentDynamicPolicyProvider.DomainPermissions;
+
+class Grants {
+
+    private final Map principalGrants = new HashMap();
+    private final WeakGroup scope;
+    private final ReadWriteLock rwlock = new ReentrantReadWriteLock();
+    private final Lock rlock = rwlock.readLock();
+    private final Lock wlock = rwlock.writeLock();
+
+    @SuppressWarnings(value = "unchecked")
+    Grants() {
+        super();
+        PrincipalGrants pg = new PrincipalGrants();
+        principalGrants.put(Collections.EMPTY_SET, pg);
+        scope = pg.scope;
+    }
+
+    @SuppressWarnings(value = "unchecked")
+    void add(Principal[] pra, Permission[] pa) {
+        Set prs = (pra != null && pra.length > 0) ? new HashSet(Arrays.asList(pra)) : Collections.EMPTY_SET;
+        ArrayList l = new ArrayList();
+        wlock.lock();
+        try {
+            PrincipalGrants pg = (PrincipalGrants) principalGrants.get(prs);
+            if (pg == null) {
+                pg = new PrincipalGrants();
+                for (Iterator i = scope.iterator(); i.hasNext();) {
+                    DomainPermissions dp = (DomainPermissions) i.next();
+                    if (containsAll(dp.getPrincipals(), prs)) {
+                        pg.scope.add(dp);
+                    }
+                }
+                principalGrants.put(prs, pg);
+            }
+            for (int i = 0; i < pa.length; i++) {
+                Permission p = pa[i];
+                if (!pg.perms.implies(p)) {
+                    pg.perms.add(p);
+                    l.add(p);
+                }
+            }
+            if (l.size() > 0) {
+                pa = (Permission[]) l.toArray(new Permission[l.size()]);
+                for (Iterator i = pg.scope.iterator(); i.hasNext();) {
+                    ((DomainPermissions) i.next()).add(pa);
+                }
+            }
+        } finally {
+            wlock.unlock();
+        }
+    }
+
+    @SuppressWarnings(value = "unchecked")
+    Permission[] get(Principal[] pra) {
+        Set prs = (pra != null && pra.length > 0) ? new HashSet(Arrays.asList(pra)) : Collections.EMPTY_SET;
+        List l = new ArrayList();
+        rlock.lock();
+        try {
+            for (Iterator i = principalGrants.entrySet().iterator(); i.hasNext();) {
+                Map.Entry me = (Map.Entry) i.next();
+                if (containsAll(prs, (Set) me.getKey())) {
+                    PrincipalGrants pg = (PrincipalGrants) me.getValue();
+                    l.addAll(Collections.list(pg.perms.elements()));
+                }
+            }
+        } finally {
+            rlock.unlock();
+        }
+        return (Permission[]) l.toArray(new Permission[l.size()]);
+    }
+
+    @SuppressWarnings(value = "unchecked")
+    void register(DomainPermissions dp) {
+        Set prs = dp.getPrincipals();
+        wlock.lock();
+        try {
+            for (Iterator i = principalGrants.entrySet().iterator(); i.hasNext();) {
+                Map.Entry me = (Map.Entry) i.next();
+                if (containsAll(prs, (Set) me.getKey())) {
+                    PrincipalGrants pg = (PrincipalGrants) me.getValue();
+                    pg.scope.add(dp);
+                    List l = Collections.list(pg.perms.elements());
+                    dp.add((Permission[]) l.toArray(new Permission[l.size()]));
+                }
+            }
+        } finally {
+            wlock.unlock();
+        }
+    }
+
+    private static boolean containsAll(Set s1, Set s2) {
+        return (s1.size() >= s2.size()) && s1.containsAll(s2);
+    }
+
+    private static class PrincipalGrants {
+
+        final WeakGroup scope = new WeakGroup();
+        final PermissionCollection perms = new Permissions();
+
+        PrincipalGrants() {
+            super();
+        }
+    }
+}

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

Added: incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/MultiReadPermissionCollection.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/MultiReadPermissionCollection.java?rev=928394&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/MultiReadPermissionCollection.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/MultiReadPermissionCollection.java Sun Mar 28 12:57:03 2010
@@ -0,0 +1,340 @@
+/*
+ * 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.security.concurrent;
+
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.UnresolvedPermission;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.apache.river.security.RevokeablePermissionCollection;
+
+/**
+ * MultiReadPermissionCollection is a wrapper class that enables mutliple
+ * reads and RevokablePermissionCollection support.  It only supports
+ * a homogenous class PermissionCollection.
+ * 
+ * TODO Serialization Correctly
+ * @version 0.2 2009/11/14
+ * @author Peter Firmstone
+ */
+final class MultiReadPermissionCollection extends PermissionCollection 
+    implements RevokeablePermissionCollection, Serializable {
+    private final static long serialVersionUID = 1L;
+    private transient PermissionCollection permCl; // all access protected by rwl
+    private final transient ReadWriteLock rwl;
+    private final transient Lock rl;
+    private final transient Lock wl;
+    private transient int writeCounter; // all access protected by rwl
+    private boolean readOnly; // all access protected by rwl
+    private Permission[] permissions; //never instantiate for ide code completion
+
+    MultiReadPermissionCollection(Permission p){
+        permCl = newPermissionCollection(p);
+        rwl = new ReentrantReadWriteLock();
+        rl = rwl.readLock();
+        wl = rwl.writeLock();
+        writeCounter = 0;
+        readOnly = false;
+    }
+    
+    @Override
+    public boolean isReadOnly(){
+        rl.lock();
+        try{  
+            return readOnly;
+        }finally {rl.unlock();}
+    }
+    
+    @Override
+    public void setReadOnly(){
+        wl.lock();
+        try{
+            readOnly = true;
+        }finally {wl.unlock();}
+    }
+    
+    
+    
+    @Override
+    public String toString(){
+        rl.lock();
+        try {
+            return permCl.toString();
+        } finally { rl.unlock();}
+    }
+    
+    @Override
+    public boolean equals(Object obj){
+        if (this == obj) return true;
+        if ( !(obj instanceof MultiReadPermissionCollection)) return false;
+        MultiReadPermissionCollection mrpcObj = (MultiReadPermissionCollection) obj;
+        rl.lock();
+        try {
+            if (permCl.equals(mrpcObj.permCl)) return true;
+        }finally {rl.unlock();}
+        return false;
+    }
+    
+    public int hashCode(){
+        rl.lock();
+        try {
+            return permCl.hashCode();
+        }finally {rl.unlock();}
+    }
+
+    @Override
+    public void add(Permission permission) {
+        if (readOnly) {
+            throw new SecurityException("attempt to add a Permission to a readonly Permissions object");
+        } 
+        wl.lock();
+        try {
+            permCl.add(permission);
+            writeCounter++;
+        }
+        finally {wl.unlock();}
+    }
+
+    @Override
+    public boolean implies(Permission permission) {
+        rl.lock();
+        try {return permCl.implies(permission);}
+        finally {rl.unlock();}
+    }
+
+    @Override
+    public Enumeration<Permission> elements() {
+        rl.lock();
+        try {return permCl.elements();}
+        finally {rl.unlock();}
+    }
+    
+    
+    /* Returns an empty PermissionCollection
+     */ 
+    private PermissionCollection newPermissionCollection(Permission permission){        
+        PermissionCollection pc = permission.newPermissionCollection();
+        if (pc == null){
+            pc = new PermissionHash();
+        }
+        return pc;                    
+    }
+    /**
+     * Permissions may have some overlap, this method will remove any Permission
+     * objects that imply any of the Permission's supplied.
+     * 
+     * If this fails it will be due to the implies method returning true
+     * due to a combination of Permission objects.
+     * 
+     * Permission objects must have the same class and type for this implementation.  
+     * 
+     * @param permissions
+     * @return success
+     */    
+    public int revoke(Permission ... permissions) {       
+            int count = 0; // false
+            HashSet<Permission> permissionSet = new HashSet<Permission>();          
+            rl.lock();
+            try {
+                if (readOnly) {
+                    throw new SecurityException("attempt to remove a Permission from a readonly Permissions object");
+                } 
+                count = writeCounter;
+                Enumeration<Permission> current = elements();
+                while (current.hasMoreElements()) {
+                    permissionSet.add(current.nextElement());
+                }
+            } finally {
+                rl.unlock();
+            }
+            if (permissionSet.size() == 0) {
+                return 1; // true
+            } 
+            Iterator<Permission> itr = permissionSet.iterator();
+            PermissionCollection newCollection = null;
+            int size = permissions.length;
+            PER:
+            while (itr.hasNext() ){
+                Permission p = itr.next();
+                if (newCollection == null) {
+                    newCollection =  p.newPermissionCollection();
+                    if (newCollection == null ){
+                        newCollection = new PermissionHash();
+                    }
+                }
+                for (int i = 0; i < size; i++) {
+                    if (p.implies(permissions[i])) {
+                        continue PER;
+                    }
+                }
+                newCollection.add(p); // if the wrong type is passed in it doesn't matter
+            }          
+            /* Check that our modifications have been effective.
+             */ 
+            for (int i = 0; i < size ; i++){
+                if ( newCollection.implies(permissions[i])) { return -1;} // fail
+            }
+            return updatePermissionCollection(newCollection, count);           
+    }
+
+    /**
+     * Idempotent method to remove all Permissions Contained within a
+     * PermissionCollection.  Method fails if PermissionCollection is
+     * modified during method execution.  This method
+     * creates an empty replacement PermissionCollection.
+     * 
+     * This method also resets setReadOnly() to false;
+     * 
+     * @param permission
+     */
+    public void revokeAll(Permission permission) { 
+        boolean sameClassType = false;
+        int count = 0;
+        rl.lock();
+        try { 
+            Enumeration<Permission> current = elements();
+            Permission currentPerm = null;
+            if (current.hasMoreElements()) {
+                currentPerm = current.nextElement();
+            }
+            if (currentPerm == null) { return; } // idempotent, already empty.
+            if (currentPerm.getClass().equals(permission.getClass())){ sameClassType = true;}
+        } finally { rl.unlock(); }
+        PermissionCollection newCollection = permission.newPermissionCollection();
+        if (newCollection == null) { newCollection = new PermissionHash(); }
+        if (sameClassType == true){
+            updatePermissionCollection(newCollection, count);      
+        }             
+    }
+    
+    private int updatePermissionCollection( PermissionCollection pc, int writeCount ){
+        wl.lock();
+        try {
+            if ( writeCount  == writeCounter || writeCount == 0 ) {
+                permCl = pc;
+                writeCounter = 0; //Reset the counter
+                if (writeCount == 0) {readOnly = false;}
+                return 1;
+            }
+        } finally { 
+            wl.unlock(); 
+        }
+        return 0;
+    }      
+    
+    private static class SerializationProxy implements Serializable {
+        private static final long serialVersionUID = 1L;
+        private final Permission[] permissions;
+        private final boolean readOnly;
+        SerializationProxy(PermissionCollection pc){
+            ArrayList<Permission> collection = new ArrayList<Permission>();
+            Enumeration<Permission> en = pc.elements();
+            while (en.hasMoreElements()){
+                collection.add(en.nextElement());
+            }
+            permissions = new Permission[collection.size()];
+            collection.toArray(permissions);
+            readOnly = pc.isReadOnly();
+        }        
+    }
+    
+    private Object writeReplace(){
+        return new SerializationProxy(this);
+    }
+    
+    private void readObject(ObjectInputStream stream) throws InvalidObjectException {
+        throw new InvalidObjectException("Proxy required");
+    }
+    
+    private Object readResolve() {
+        MultiReadPermissionCollection pc = new MultiReadPermissionCollection(permissions[0]);
+        int length = permissions.length;
+        for ( int i = 0 ; i < length ; i++){
+            pc.add(permissions[i]);
+        }
+        if ( readOnly == true ) {pc.setReadOnly();}
+        return pc;
+    }
+    
+    private static final class PermissionHash extends PermissionCollection {
+        // This class is never serialized.
+        private final static long serialVersionUID = 1L;        
+        private HashSet<Permission> permSet;
+
+        public PermissionHash(){
+            permSet = new HashSet<Permission>();
+        }
+
+        public boolean equals(Object obj){
+            if (this == obj) return true;
+            if (!(obj instanceof PermissionHash)) return false;
+            PermissionHash phObj = (PermissionHash) obj;
+            if (this.permSet.equals(phObj.permSet)) return true;
+            return false;
+        }
+
+        public int hashCode(){
+            return permSet.hashCode();
+        }
+
+        public String toString(){
+            return permSet.toString();
+        }
+
+        @Override
+        public void add(Permission permission) {            
+            permSet.add(permission);            
+        }
+
+        @Override
+        public boolean implies(Permission permission) {           
+            // attempt a fast lookup and implies. If that fails
+            // then enumerate through all the permissions.            
+            if (permSet.contains(permission) 
+                    && !(permission instanceof UnresolvedPermission)) {
+                return true; 
+            }
+            Iterator<Permission> itr = permSet.iterator();
+            while (itr.hasNext()) {
+                Permission p = itr.next();
+                if (p.implies(permission)) {return true;}
+            }
+            return false;            
+        }
+
+        @Override
+        public Enumeration<Permission> elements() {
+            synchronized (this){
+                return Collections.enumeration(permSet);
+            }
+        }      
+    }    
+}

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

Added: incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/PermissionPendingResolution.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/PermissionPendingResolution.java?rev=928394&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/PermissionPendingResolution.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/PermissionPendingResolution.java Sun Mar 28 12:57:03 2010
@@ -0,0 +1,206 @@
+/*
+ *  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.security.concurrent;
+
+import java.lang.reflect.Constructor;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.UnresolvedPermission;
+import java.security.cert.Certificate;
+
+/**
+ *
+ * @author Peter Firmstone
+ */
+class PermissionPendingResolution extends Permission {
+        private static final long serialVersionUID = 1L;
+        private transient String type; //Class name of underlying permission
+        private transient String name; //Target name of underlying permission
+        private transient String actions;
+        /* We have our own array copy of certs, prevents unnecessary 
+         * array creation every time .getUnresolvedCerts() is called.
+         */ 
+        private transient Certificate [] targetCerts;
+        private UnresolvedPermission unresolvedPermission;
+    
+    PermissionPendingResolution(UnresolvedPermission up){
+        super(up.getUnresolvedType());
+        type = up.getUnresolvedType();
+        name = up.getUnresolvedName();
+        actions = up.getUnresolvedActions();
+        // don't need to defensive copy, UnresolvedPermission already does it.
+        targetCerts = up.getUnresolvedCerts();
+        unresolvedPermission = up;
+    }
+    
+    Permission resolve(Class targetType) {
+        // check signers at first
+        if (matchSubset( targetCerts, targetType.getSigners())) {
+            try {
+                 return instantiatePermission(targetType, name, actions);
+            } catch (Exception ignore) {
+                //TODO log warning?
+            }
+        }
+        return null;
+    }
+    
+    Permission resolve(ClassLoader cl){
+        Class<?> targetType = null;
+        try {
+           targetType =  cl.loadClass(type);
+        } catch (ClassNotFoundException e){
+            //TODO log warning?
+            System.err.println(type +" " + name + " " + actions +
+                    ": Cannot be resolved due to ClassNotFoundException");
+            e.printStackTrace();
+        } catch (NullPointerException e){
+            //TODO log warning, this should never happen but if it does
+            //the class will not be resolved.
+            System.err.println(type +" " + name + " " + actions +
+                    ": Cannot be resolved due to ClassLoader null instance");
+            e.printStackTrace();
+        }
+        if ( targetType == null ) {return null;}
+        return resolve(targetType);
+    }
+    
+
+    /**
+     * Code Copied, Courtesey Apache Harmony
+     * 
+     * Checks whether the objects from <code>what</code> array are all
+     * presented in <code>where</code> array.
+     * 
+     * @param what first array, may be <code>null</code> 
+     * @param where  second array, may be <code>null</code>
+     * @return <code>true</code> if the first array is <code>null</code>
+     * or if each and every object (ignoring null values) 
+     * from the first array has a twin in the second array; <code>false</code> otherwise
+     */
+     boolean matchSubset(Object[] what, Object[] where) {
+        if (what == null) {
+            return true;
+        }
+
+        for (int i = 0; i < what.length; i++) {
+            if (what[i] != null) {
+                if (where == null) {
+                    return false;
+                }
+                boolean found = false;
+                for (int j = 0; j < where.length; j++) {
+                    if (what[i].equals(where[j])) {
+                        found = true;
+                        break;
+                    }
+                }
+                if (!found) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+    
+    // Empty set of arguments to default constructor of a Permission.
+    private static final Class[] NO_ARGS = {};
+
+    // One-arg set of arguments to default constructor of a Permission.
+    private static final Class[] ONE_ARGS = { String.class };
+
+    // Two-args set of arguments to default constructor of a Permission.
+    private static final Class[] TWO_ARGS = { String.class, String.class };
+       
+    /**
+     * Code copied, courtsey of Apache Harmony
+     * 
+     * Tries to find a suitable constructor and instantiate a new Permission
+     * with specified parameters.  
+     *
+     * @param targetType class of expected Permission instance
+     * @param targetName name of expected Permission instance
+     * @param targetActions actions of expected Permission instance
+     * @return a new Permission instance
+     * @throws IllegalArgumentException if no suitable constructor found
+     * @throws Exception any exception thrown by Constructor.newInstance()
+     */
+    Permission instantiatePermission(Class<?> targetType,
+            String targetName, String targetActions) throws Exception {
+
+        // let's guess the best order for trying constructors
+        Class[][] argTypes = null;
+        Object[][] args = null;
+        if (targetActions != null) {
+            argTypes = new Class[][] { TWO_ARGS, ONE_ARGS, NO_ARGS };
+            args = new Object[][] { { targetName, targetActions },
+                    { targetName }, {} };
+        } else if (targetName != null) {
+            argTypes = new Class[][] { ONE_ARGS, TWO_ARGS, NO_ARGS };
+            args = new Object[][] { { targetName },
+                    { targetName, targetActions }, {} };
+        } else {
+            argTypes = new Class[][] { NO_ARGS, ONE_ARGS, TWO_ARGS };
+            args = new Object[][] { {}, { targetName },
+                    { targetName, targetActions } };
+        }
+
+        // finally try to instantiate actual permission
+        for (int i = 0; i < argTypes.length; i++) {
+            try {
+                Constructor<?> ctor = targetType.getConstructor(argTypes[i]);
+                return (Permission)ctor.newInstance(args[i]);
+            }
+            catch (NoSuchMethodException ignore) {}
+        }
+        throw new IllegalArgumentException(type + name + actions);//$NON-NLS-1$
+    }
+
+    @Override
+    public boolean implies(Permission permission) {
+        return false;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if ( obj == this ) {return true;}
+        if ( !(obj instanceof PermissionPendingResolution)) {return false;}
+        PermissionPendingResolution ob = (PermissionPendingResolution) obj;
+        if (this.unresolvedPermission.equals(ob.unresolvedPermission)) {return true;}
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return unresolvedPermission.hashCode();
+    }
+
+    @Override
+    public String getActions() {
+        return "";
+    }
+    
+    @Override
+    public PermissionCollection newPermissionCollection(){
+        return new PermissionPendingResolutionCollection();
+    }
+    
+    public UnresolvedPermission asUnresolvedPermission(){
+        return unresolvedPermission;
+    }
+}

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

Added: incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/PermissionPendingResolutionCollection.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/PermissionPendingResolutionCollection.java?rev=928394&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/PermissionPendingResolutionCollection.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/PermissionPendingResolutionCollection.java Sun Mar 28 12:57:03 2010
@@ -0,0 +1,147 @@
+/*
+ *  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.security.concurrent;
+
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ *
+ * @author Peter Firmstone
+ */
+public class PermissionPendingResolutionCollection  extends PermissionCollection {
+    private static final long serialVersionUID = 1L;
+    private ConcurrentHashMap<String,Collection<PermissionPendingResolution>> klasses;
+    private AtomicInteger pending;
+    PermissionPendingResolutionCollection(){
+        klasses = new ConcurrentHashMap<String,Collection<PermissionPendingResolution>>(2);
+        pending = new AtomicInteger(0);
+    }
+    
+    public int awaitingResolution(){
+        return pending.get();
+    }
+            
+
+    public void add(Permission permission) {
+        if (isReadOnly()) {
+            throw new SecurityException("attempt to add a Permission to a readonly Permissions object"); //$NON-NLS-1$
+        }
+        if (permission == null) { throw new IllegalArgumentException("Null Permission");}
+        if ( permission.getClass() != PermissionPendingResolution.class || permission.getClass() != PermissionPendingResolution.class ) {
+            throw new IllegalArgumentException("Not instance of PermissionPendingResolution");
+        }
+        String klass = permission.getName();
+        Collection<PermissionPendingResolution> klassMates = klasses.get(klass);
+        if (klassMates != null){
+            klassMates.add((PermissionPendingResolution) permission);
+            pending.incrementAndGet();
+            return;
+        }
+        Collection<PermissionPendingResolution> klassMatesExists = null;        
+        Set<PermissionPendingResolution> pprs = new HashSet<PermissionPendingResolution>();
+        klassMates = Collections.synchronizedSet(pprs);
+        klassMatesExists  = klasses.putIfAbsent(klass, klassMates);       
+        if (klassMatesExists == null){
+            klassMates.add((PermissionPendingResolution) permission);
+            pending.incrementAndGet();
+        }else{
+            klassMatesExists.add((PermissionPendingResolution) permission);
+            pending.incrementAndGet();
+        }
+    }
+    
+    PermissionCollection resolveCollection(Permission target,
+                                           PermissionCollection holder ){
+        if (pending.get() == 0) { return holder; }
+        String klass = target.getClass().getName();
+        if (klasses.containsKey(klass)) {            
+            Collection<PermissionPendingResolution> klassMates = klasses.get(klass);
+            for (Iterator<PermissionPendingResolution> iter = klassMates.iterator(); iter.hasNext();) {
+                PermissionPendingResolution element = iter.next();
+                Permission resolved = element.resolve(target.getClass());
+                if (resolved != null) {
+                    if (holder == null) {
+                        holder = new MultiReadPermissionCollection(target);                             
+                    }
+                    holder.add(resolved);
+                    iter.remove();
+                    pending.decrementAndGet();
+                }
+            } 
+            // there is no possible way of atomic removal of an empty Collection.           
+        }
+        return holder;
+    }
+    
+    //Should I be performing a privileged action? Or should it run with
+    // the caller thread's privileges?
+    Enumeration<Permission> resolvePermissions(final ProtectionDomain pd){
+        @SuppressWarnings("unchecked")
+        ClassLoader cl = (ClassLoader) AccessController.doPrivileged(
+                new PrivilegedAction(){
+                public Object run(){
+                    ClassLoader cL = pd.getClassLoader();
+                    if (cL == null){
+                        cL = this.getClass().getClassLoader();
+                    }
+                    return cL;
+                }
+        });
+        
+        
+        List<Permission> perms = new ArrayList<Permission>();
+        Enumeration enPending = elements();
+        while (enPending.hasMoreElements()){
+            PermissionPendingResolution pendPerm = 
+                    (PermissionPendingResolution) enPending.nextElement();
+            Permission resolved =  pendPerm.resolve(cl);
+            if ( resolved != null ){
+                perms.add(resolved);
+            }           
+        }
+        return Collections.enumeration(perms);
+    }
+
+    @Override
+    public boolean implies(Permission permission) {
+        return false;
+    }
+
+    @SuppressWarnings("unchecked")
+    public Enumeration<Permission> elements() {
+        Collection all = new ArrayList();
+        for (Iterator iter = klasses.values().iterator(); iter.hasNext();) {
+            all.addAll((Collection)iter.next());
+        }
+        return Collections.enumeration(all);
+    }
+}

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

Added: incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/WeakGroup.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/WeakGroup.java?rev=928394&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/WeakGroup.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/security/concurrent/WeakGroup.java Sun Mar 28 12:57:03 2010
@@ -0,0 +1,114 @@
+package org.apache.river.security.concurrent;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+class WeakGroup {
+
+    private final ReferenceQueue rq = new ReferenceQueue();
+    private final Node head;
+    private final Node tail;
+
+    WeakGroup() {
+        super();
+        head = Node.createEmptyList();
+        tail = head.getNext();
+    }
+
+    void add(Object obj) {
+        if (obj == null) {
+            throw new NullPointerException();
+        }
+        processQueue();
+        Node newNode = new Node(obj, rq);
+        newNode.insertAfter(head);
+    }
+
+    Iterator iterator() {
+        processQueue();
+        return new Iterator() {
+
+            private Node curNode = head.getNext();
+            private Object nextObj = getNext();
+
+            public Object next() {
+                if (nextObj == null) {
+                    throw new NoSuchElementException();
+                }
+                Object obj = nextObj;
+                nextObj = getNext();
+                return obj;
+            }
+
+            public boolean hasNext() {
+                return nextObj != null;
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+
+            private Object getNext() {
+                while (curNode != tail) {
+                    Object obj = curNode.get();
+                    if (obj != null) {
+                        curNode = curNode.getNext();
+                        return obj;
+                    } else {
+                        curNode.enqueue();
+                        curNode = curNode.getNext();
+                    }
+                }
+                return null;
+            }
+        };
+    }
+
+    private void processQueue() {
+        Node n;
+        while ((n = (Node) rq.poll()) != null) {
+            n.remove();
+        }
+    }
+
+    private static class Node extends WeakReference {
+
+        private Node next;
+        private Node prev;
+
+        static Node createEmptyList() {
+            Node head = new Node(null);
+            Node tail = new Node(null);
+            head.next = tail;
+            tail.prev = head;
+            return head;
+        }
+
+        private Node(Object obj) {
+            super(obj);
+        }
+
+        Node(Object obj, ReferenceQueue rq) {
+            super(obj, rq);
+        }
+
+        void insertAfter(Node pred) {
+            Node succ = pred.next;
+            next = succ;
+            prev = pred;
+            pred.next = this;
+            succ.prev = this;
+        }
+
+        void remove() {
+            prev.next = next;
+            next.prev = prev;
+        }
+
+        Node getNext() {
+            return next;
+        }
+    }
+}

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

Added: incubator/river/jtsk/trunk/src/org/apache/river/security/policy/spi/RevokeableDynamicPolicySpi.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/security/policy/spi/RevokeableDynamicPolicySpi.java?rev=928394&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/policy/spi/RevokeableDynamicPolicySpi.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/security/policy/spi/RevokeableDynamicPolicySpi.java Sun Mar 28 12:57:03 2010
@@ -0,0 +1,36 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.apache.river.security.policy.spi;
+
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Policy;
+import java.security.ProtectionDomain;
+import net.jini.security.policy.PolicyInitializationException;
+
+/**
+ * An implementer of this interface isn't required to extend Policy and isn't
+ * required to implement dynamic grants either.
+ * @author Peter Firmstone
+ */
+public interface RevokeableDynamicPolicySpi extends RevokeablePolicy {
+    public boolean basePolicy(Policy basePolicy);
+    public void initialize()throws PolicyInitializationException;
+    /**
+     * Ensures that any classes depended on by this policy provider are
+     * resolved.  This is to preclude lazy resolution of such classes during
+     * operation of the provider, which can result in deadlock as described by
+     * bug 4911907.
+     */
+    public void ensureDependenciesResolved();
+        // All the java.security.Policy methods     
+    public PermissionCollection getPermissions(CodeSource codesource);
+    public PermissionCollection getPermissions(ProtectionDomain domain);
+    public boolean implies(ProtectionDomain domain, Permission permission);        
+    public void refresh();
+
+}

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

Added: incubator/river/jtsk/trunk/src/org/apache/river/security/policy/spi/RevokeablePolicy.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/security/policy/spi/RevokeablePolicy.java?rev=928394&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/policy/spi/RevokeablePolicy.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/security/policy/spi/RevokeablePolicy.java Sun Mar 28 12:57:03 2010
@@ -0,0 +1,26 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.apache.river.security.policy.spi;
+
+import java.security.Permission;
+import java.security.Principal;
+import net.jini.security.policy.DynamicPolicy;
+
+/**
+ * A DynamicPolicy that supports revoking as well as permission grants.
+ * 
+ * All Policy methods are implemented so RevokeableDynamicPolicySpi 
+ * implementions aren't necessarily required to extend Policy.
+ * 
+ * @author Peter Firmstone
+ * @see DynamicPolicy
+ */
+public interface RevokeablePolicy extends DynamicPolicy {
+    
+    public void revoke(Class cl, Principal[] principals, Permission[] permissions)
+            throws UnsupportedOperationException;
+    public boolean revokeSupported();
+}

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



Mime
View raw message