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/05/11 22:37:49 UTC

svn commit: r943285 [2/3] - in /incubator/river/jtsk/trunk: ./ qa/ qa/harness/trust/ qa/src/com/sun/jini/qa/harness/ qa/src/com/sun/jini/qa/resources/ src/com/sun/jini/tool/ src/net/jini/core/lookup/ src/net/jini/discovery/ src/net/jini/lease/ src/net/...

Added: incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/ConcurrentPolicyFile.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/ConcurrentPolicyFile.java?rev=943285&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/ConcurrentPolicyFile.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/ConcurrentPolicyFile.java Tue May 11 20:37:47 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.imp.security.policy.se;
+
+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.imp.security.policy.util.DefaultPolicyParser;
+import org.apache.river.imp.security.policy.util.PolicyEntry;
+import org.apache.river.imp.security.policy.util.PolicyParser;
+import org.apache.river.imp.security.policy.util.PolicyUtils;
+import org.apache.river.imp.util.ConcurrentWeakIdentityMap;
+
+
+/**
+ * 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 ConcurrentWeakIdentityMap<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/imp/security/policy/concurrent/ConcurrentPolicyFile.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/DynamicConcurrentPolicyProvider.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/DynamicConcurrentPolicyProvider.java?rev=943285&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/DynamicConcurrentPolicyProvider.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/DynamicConcurrentPolicyProvider.java Tue May 11 20:37:47 2010
@@ -0,0 +1,489 @@
+
+
+package org.apache.river.imp.security.policy.se;
+
+import java.security.AccessController;
+import java.security.AllPermission;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.security.Provider;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.logging.LoggingPermission;
+import net.jini.security.GrantPermission;
+import net.jini.security.policy.DynamicPolicy;
+import net.jini.security.policy.PolicyInitializationException;
+import org.apache.river.api.security.RevokePermission;
+import org.apache.river.imp.security.policy.spi.RevokeableDynamicPolicySpi;
+import org.apache.river.api.security.RevokeablePolicy;
+import org.apache.river.imp.security.policy.util.PolicyEntry;
+import org.apache.river.imp.security.policy.util.PolicyUtils;
+import org.apache.river.imp.util.ConcurrentWeakIdentityMap;
+
+/**
+ * <p>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.</p>
+ * 
+ * <p>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:</p>
+ * 
+ * <p>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. </p>
+ * 
+ * <p>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:</p>
+ * <p>
+ * getPermissions(Codesource source) or
+ * getPermissions(ProtectionDomain domain)
+ * </p>
+ * <p>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.</p>
+ * <p>
+ * 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.</p>
+ * <p>
+ * This may cause some undesireable side effects in existing programs.
+ * </p><p>
+ * 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.
+ * </p><p>
+ * To make the best utilisation of this Policy provider, set the System property:
+ * </p>,<p>
+ * net.jini.security.policy.PolicyFileProvider.basePolicyClass = 
+ * org.apache.river.security.concurrent.ConcurrentPolicyFile
+ * </p>
+ * @author Peter Firmstone
+ * @version 1
+ * @since 2.2
+ * @see ProtectionDomain
+ * @see Policy
+ * @see ConcurrentPolicyFile
+ * @see net.jini.security.policy.PolicyFileProvider
+ * @see ConcurrentPermissionCollection
+ */
+
+public class DynamicConcurrentPolicyProvider implements RevokeableDynamicPolicySpi {
+    private static final ProtectionDomain sysDomain = 
+	AccessController.doPrivileged(new PrivilegedAction<ProtectionDomain>() {
+	    public ProtectionDomain run() { return Object.class.getProtectionDomain(); }
+	});
+    
+    // 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; // Don't use cache if true.
+    private volatile boolean revokeable;
+    private volatile boolean initialized = false;
+    private Logger logger;
+    private volatile boolean loggable;
+    // do something about some domain permissions for this domain so we can 
+    // avoid dead locks due to bug 4911907
+    
+    
+    public DynamicConcurrentPolicyProvider(){
+        rwl = new ReentrantReadWriteLock();
+        rl = rwl.readLock();
+        wl = rwl.writeLock();
+        dynamicGrants = new HashSet<PolicyEntry>(30);
+        basePolicy = null;
+        cache = new ConcurrentWeakIdentityMap<ProtectionDomain, PermissionCollection>();
+        basePolicyIsDynamic = false;
+        revokeable = true;
+        logger = Logger.getLogger("net.jini.security.policy");
+        loggable = logger.isLoggable(Level.INFO);
+    }
+    
+    /**
+     * Idempotent method.
+     * @param basePolicy
+     * @return
+     */
+    public boolean basePolicy(Policy basePolicy) {
+        if (initialized == true) return false;
+        this.basePolicy = basePolicy;
+        return true;
+    }
+
+    /** 
+     * Idempotent method. 
+     * @throws net.jini.security.policy.PolicyInitializationException 
+     */
+    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) {
+            DynamicPolicy dp = (DynamicPolicy) basePolicy;
+            basePolicyIsDynamic = dp.grantSupported();
+            revokeable = false;
+            if (basePolicy instanceof RevokeablePolicy ) {
+                RevokeablePolicy rp = (RevokeablePolicy) basePolicy;
+                revokeable = rp.revokeSupported();
+            }
+        }
+        initialized = true;
+    }
+
+    /**
+     * 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() {
+        if (initialized == false) throw new RuntimeException("Object not initialized");
+        // Investigate bug 4911907, do we need to do anything more here? Is this sufficient.
+        if (sysDomain == null ) System.out.println("System Domain is null");
+        implies(sysDomain, new AllPermission());
+    }
+
+    public void revoke(Class cl, Principal[] principals, Permission[] permissions) {
+        if (initialized == false) throw new RuntimeException("Object not initialized");
+        if (permissions == null) return;
+        SecurityManager sm = System.getSecurityManager();
+	if (sm != null) {
+	    sm.checkPermission(new RevokePermission());
+	}
+        if (basePolicyIsDynamic){
+            // Revoke not supported unless the base policy supports it.
+            if (revokeable){
+                RevokeablePolicy rp = (RevokeablePolicy) basePolicy;
+                rp.revoke(cl, principals, permissions);
+            }
+            return;
+        }
+        /* 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();
+        if (principals == null){
+            principals = new Principal[0];
+        }
+        if (principals.length > 0) {
+	    principals = principals.clone();
+	    checkNullElements(principals);
+	}
+        permissions = permissions.clone();
+	checkNullElements(permissions);        
+        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.impliesProtectionDomain(domain)
+                    && 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(domain.toString());
+        /* 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 revokeable;
+    }
+
+    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");
+        return basePolicy.getPermissions(codesource);
+//      The following code breaks revoke.
+//        Collection<Permission> dynamicallyGrantedPermissions = getGrants(codesource, null);
+//        PermissionCollection pc = null;
+//        pc = basePolicy.getPermissions(codesource);
+//        if (pc == null) pc = new Permissions();       
+//        Iterator<Permission> dgpi = dynamicallyGrantedPermissions.iterator();
+//        while (dgpi.hasNext()){
+//            pc.add(dgpi.next());
+//        }
+//        return pc;      
+    }
+
+    public PermissionCollection getPermissions(ProtectionDomain domain) {
+        if (initialized == false) throw new RuntimeException("Object not initialized");
+        return basePolicy.getPermissions(domain);
+//      The following code breaks revoke.      
+//        CodeSource cs = (domain == null ? null : domain.getCodeSource());
+//        Principal[] pals = (domain == null ? null : domain.getPrincipals());
+//        Collection<Permission> dynamicallyGrantedPermissions = getGrants(cs, pals);
+//        PermissionCollection pc = null;
+//        pc = cache.get(domain); // saves new object creation.
+//        if (pc == null){
+//            pc = basePolicy.getPermissions(domain);
+//            //if (pc == null) pc = new ConcurrentPermissions();
+//            if (pc == null) pc = new Permissions();
+////            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());
+//        }
+//        return pc;
+    }
+
+    public boolean implies(ProtectionDomain domain, Permission permission) {
+        if (initialized == false) throw new RuntimeException("Object not initialized");
+        // First check the our cache if the basePolicy is not dynamic.
+        if (!basePolicyIsDynamic) {
+            PermissionCollection pc = cache.get(domain);
+            if ( pc != null){
+                if (pc.implies(permission)) return true;
+            }
+        }
+        // Then check the base policy
+        if (basePolicy.implies(domain, permission)) return true;
+        if (basePolicyIsDynamic) return false;
+        if (loggable){
+            logger.log(Level.INFO, domain + permission.toString() + 
+                    ": Base policy is not dynamic and returned false" );
+        }
+        // If it doesn't then we should check for dynamic grants
+        Principal[] pals = (domain == null ? null : domain.getPrincipals());
+        CodeSource cs = ( domain == null ? null : domain.getCodeSource());
+        Collection<Permission> dynamicallyGrantedPermissions = getGrants(domain, cs, pals);
+        if (loggable) {
+            logger.log(Level.INFO, "Grants: " + dynamicallyGrantedPermissions.toString());
+        }
+        if (dynamicallyGrantedPermissions.isEmpty()) return false;
+        // Operation starts to get expensive
+        PermissionCollection pc = null;
+        pc = cache.get(domain); // saves new object creation.
+        if (pc == null){
+            pc = basePolicy.getPermissions(domain);
+            if (pc == null) pc = new ConcurrentPermissions();
+//            if (pc == null) pc = new Permissions();
+            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.
+        if (loggable) {
+            logger.log(Level.INFO, "PermissionCollection: " + pc.toString());
+        }
+        return pc.implies(permission);
+    }
+    
+    /**
+     * Calling refresh doesn't remove any dynamic grant's, it only clears
+     * the cache and refreshes the underlying Policy, it also removes any
+     * grants for ProtectionDomains that no longer exist.
+     */
+    public void refresh() {
+        if (initialized == false) throw new RuntimeException("Object not initialized");
+        cache.clear();
+        basePolicy.refresh();
+        // Clean up any void grants.
+        try {
+            wl.lock();
+            Iterator<PolicyEntry> it = dynamicGrants.iterator();
+            while (it.hasNext()){
+                PolicyEntry pe = it.next();
+                if ( pe.isVoid()){
+                    it.remove();
+                }
+            }
+        } finally {wl.unlock();}
+        
+    }
+
+    public boolean grantSupported() {
+        if (initialized == false) throw new RuntimeException("Object not initialized");
+        return true;
+    }
+
+    public void grant(Class cl, Principal[] principals, Permission[] permissions) {
+        if (initialized == false) throw new RuntimeException("Object not initialized");
+        if (permissions == null || permissions.length == 0) {
+	    return;
+	}
+        if ( basePolicyIsDynamic ){
+            /* Delegate, otherwise, if base policy is an instance of this class, we
+             * may have multi combinations of permissions that together should
+             * be true but become separated as this implementation will not
+             * return any dynamically granted permissions via getPermissions(
+             * because doing so would mean loosing revoke ability.
+             */
+            DynamicPolicy dp = (DynamicPolicy) basePolicy;
+            dp.grant(cl, principals, permissions);
+            return;
+        }
+        if (principals == null){
+            principals = new Principal[0];
+        }
+        if (principals.length > 0) {
+	    principals = principals.clone();
+	    checkNullElements(principals);
+	}
+        permissions = permissions.clone();
+        checkNullElements(permissions);
+	SecurityManager sm = System.getSecurityManager();
+	if (sm != null) {
+	    sm.checkPermission(new GrantPermission(permissions));
+	}
+        Collection<Principal> pal = Arrays.asList(principals);
+        Collection<Permission> perm = Arrays.asList(permissions);
+        ProtectionDomain domain = null;
+        if ( cl != null){
+            domain = getDomain(cl);
+        }
+        PolicyEntry pe = new PolicyEntry(domain, pal, perm);
+        if (loggable){
+            logger.log(Level.INFO, "Granting: " + pe.toString());
+        }
+        try {
+            wl.lock();
+            dynamicGrants.add(pe);           
+        } finally {wl.unlock();}
+    }
+    
+    // documentation inherited from DynamicPolicy.getGrants
+    public Permission[] getGrants(Class cl, Principal[] principals) {
+        if (initialized == false) throw new RuntimeException("Object not initialized");
+        ProtectionDomain pd = null;
+        CodeSource cs = null;
+        if ( cl != null ) {
+            pd = getDomain(cl);
+            cs = pd.getCodeSource();
+        }
+        // defensive copy array
+        if (principals != null && principals.length > 0) {
+	    principals = principals.clone();
+	    checkNullElements(principals);
+	}
+        Collection<Permission> cperms = getGrants(pd, cs, principals);
+        Permission[] perms = cperms.toArray(new Permission[cperms.size()]);        
+        return perms;
+    }
+    
+    private Collection<Permission> getGrants(ProtectionDomain pd, 
+            CodeSource cs, Principal[] pals){
+        Collection<Permission> dynamicallyGrantedPermissions = new HashSet<Permission>(20);
+        try {
+            rl.lock();
+            Iterator<PolicyEntry> it = dynamicGrants.iterator();
+            while (it.hasNext()) {
+                PolicyEntry ge = it.next();
+                if ( ge.impliesProtectionDomain(pd)
+                        && ge.impliesCodeSource(cs)
+                        && ge.impliesPrincipals(pals)) {
+                    dynamicallyGrantedPermissions.addAll( ge.getPermissions());
+                }
+            }               
+        } finally { rl.unlock(); }
+        return dynamicallyGrantedPermissions;
+    }
+    
+    private static void checkNullElements(Object[] array) {
+        int l = array.length;
+	for (int i = 0; i < l; i++) {
+	    if (array[i] == null) {
+		throw new NullPointerException();
+	    }
+	}
+    }
+       
+    private static ProtectionDomain getDomain(final Class cl) {
+	ProtectionDomain pd = AccessController.doPrivileged(
+	    new PrivilegedAction<ProtectionDomain>() {
+		public ProtectionDomain run() { return cl.getProtectionDomain(); }
+	    });
+	if (pd != sysDomain && pd.getClassLoader() == null) {
+	    throw new UnsupportedOperationException(
+		"ungrantable protection domain");
+	}
+            return pd;
+    }  
+
+}

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

Added: incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/MultiReadPermissionCollection.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/MultiReadPermissionCollection.java?rev=943285&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/MultiReadPermissionCollection.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/MultiReadPermissionCollection.java Tue May 11 20:37:47 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.imp.security.policy.se;
+
+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;
+
+
+/**
+ * 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
+ */
+public 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/imp/security/policy/concurrent/MultiReadPermissionCollection.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/PermissionPendingResolution.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/PermissionPendingResolution.java?rev=943285&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/PermissionPendingResolution.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/PermissionPendingResolution.java Tue May 11 20:37:47 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.imp.security.policy.se;
+
+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/imp/security/policy/concurrent/PermissionPendingResolution.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/PermissionPendingResolutionCollection.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/PermissionPendingResolutionCollection.java?rev=943285&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/PermissionPendingResolutionCollection.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/PermissionPendingResolutionCollection.java Tue May 11 20:37:47 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.imp.security.policy.se;
+
+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/imp/security/policy/concurrent/PermissionPendingResolutionCollection.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/RevokeablePermissionCollection.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/RevokeablePermissionCollection.java?rev=943285&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/RevokeablePermissionCollection.java (added)
+++ incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/concurrent/RevokeablePermissionCollection.java Tue May 11 20:37:47 2010
@@ -0,0 +1,89 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.apache.river.imp.security.policy.se;
+
+import java.security.Permission;
+import java.util.Enumeration;
+
+/**
+ *
+ * @author Peter Firmstone
+ * @see PermissionCollection
+ * @see Permission
+ */
+public interface RevokeablePermissionCollection {
+    /**
+     * This method is slow and to be used only when correctness is perferred
+     * over performance.
+     * 
+     * In fact revokeAll() followed by add() is the preferred method.
+     * 
+     * However when the new Permission set depends upon the old and there is
+     * a possibility that the old set may be updated with an add during processing
+     * this method will fail and as such not loose a particular required permission.
+     * 
+     * Partial success may occur in which case some of the permissions will be
+     * revoked and others not. However only a subset of those permissions that 
+     * are requested to be revoked, shall be.  This should not be a problem as
+     * the required permissions will still exist in the set and a simple retry
+     * should suffice if the return was 0.
+     * 
+     * Attempt to revoke a Permission, if an intervening write occurs an
+     * integer value of 0 is returned, the suggested strategy is to try again,
+     * however if several attempts are likely to fail use revokeAll instead.
+     * 
+     * A return value of -1 indicates that the Permission cannot be revoked
+     * from the collection.  In this case use revokeAll.  It may be possible
+     * to correct this condition by utilising a finer grained permission set.
+     * 
+     * A return value of 1 indicates success.
+     * 
+     * @param permissions
+     * @return result, 0 for intervening write, -1 failed not possible, 1 for true
+     */
+    public int revoke(Permission ... permissions);
+
+    /**
+     * Due to the overlapping nature of Permission's, attempts to revoke
+     * a permission may fail, in wich case it is best to remove all
+     * permissions related by class and later add the required Permissions.
+     * This method should always succeed.
+     * 
+     * This method should only revoke Permission's related to an individual
+     * class type.
+     * 
+     * @param permission 
+     */
+    public void revokeAll(Permission permission);
+    
+    /**
+     * @see PermissionCollection.add(Permission permission)
+     * @param permission
+     */
+    public void add(Permission permission);
+    /**
+     * @see PermissionCollection.elements()
+     * @return
+     */
+    public Enumeration<Permission> elements();
+    /**
+     * @see PermissionCollection.implies()
+     * @param permission
+     * @return
+     */
+    public boolean implies(Permission permission);
+    /**
+     * @see PermissionCollection.isReadOnly()
+     * @return true or false
+     */
+    public boolean isReadOnly();
+    /**
+     * @see PermissionCollection.setReadOnly()
+     */
+    public void setReadOnly();
+    @Override
+    public String toString();
+}

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

Copied: incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/spi/RevokeableDynamicPolicySpi.java (from r933907, 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/imp/security/policy/spi/RevokeableDynamicPolicySpi.java?p2=incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/spi/RevokeableDynamicPolicySpi.java&p1=incubator/river/jtsk/trunk/src/org/apache/river/security/policy/spi/RevokeableDynamicPolicySpi.java&r1=933907&r2=943285&rev=943285&view=diff
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/policy/spi/RevokeableDynamicPolicySpi.java (original)
+++ incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/spi/RevokeableDynamicPolicySpi.java Tue May 11 20:37:47 2010
@@ -3,8 +3,9 @@
  * and open the template in the editor.
  */
 
-package org.apache.river.security.policy.spi;
+package org.apache.river.imp.security.policy.spi;
 
+import org.apache.river.api.security.RevokeablePolicy;
 import java.security.CodeSource;
 import java.security.Permission;
 import java.security.PermissionCollection;

Copied: incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/DefaultPolicyParser.java (from r933907, incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/DefaultPolicyParser.java)
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/DefaultPolicyParser.java?p2=incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/DefaultPolicyParser.java&p1=incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/DefaultPolicyParser.java&r1=933907&r2=943285&rev=943285&view=diff
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/DefaultPolicyParser.java (original)
+++ incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/DefaultPolicyParser.java Tue May 11 20:37:47 2010
@@ -20,7 +20,7 @@
 * @version $Revision$
 */
 
-package org.apache.river.security.policy.util;
+package org.apache.river.imp.security.policy.util;
 
 import java.io.BufferedReader;
 import java.io.InputStream;
@@ -46,10 +46,10 @@ import java.util.Properties;
 import java.util.Set;
 import java.util.StringTokenizer;
 
-import org.apache.river.security.policy.util.DefaultPolicyScanner.GrantEntry;
-import org.apache.river.security.policy.util.DefaultPolicyScanner.KeystoreEntry;
-import org.apache.river.security.policy.util.DefaultPolicyScanner.PermissionEntry;
-import org.apache.river.security.policy.util.DefaultPolicyScanner.PrincipalEntry;
+import org.apache.river.imp.security.policy.util.DefaultPolicyScanner.GrantEntry;
+import org.apache.river.imp.security.policy.util.DefaultPolicyScanner.KeystoreEntry;
+import org.apache.river.imp.security.policy.util.DefaultPolicyScanner.PermissionEntry;
+import org.apache.river.imp.security.policy.util.DefaultPolicyScanner.PrincipalEntry;
 
 
 /**

Copied: incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/DefaultPolicyScanner.java (from r933907, incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/DefaultPolicyScanner.java)
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/DefaultPolicyScanner.java?p2=incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/DefaultPolicyScanner.java&p1=incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/DefaultPolicyScanner.java&r1=933907&r2=943285&rev=943285&view=diff
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/DefaultPolicyScanner.java (original)
+++ incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/DefaultPolicyScanner.java Tue May 11 20:37:47 2010
@@ -20,7 +20,7 @@
 * @version $Revision$
 */
 
-package org.apache.river.security.policy.util;
+package org.apache.river.imp.security.policy.util;
 
 import java.io.IOException;
 import java.io.Reader;

Copied: incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/Messages.java (from r933907, incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/Messages.java)
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/Messages.java?p2=incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/Messages.java&p1=incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/Messages.java&r1=933907&r2=943285&rev=943285&view=diff
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/Messages.java (original)
+++ incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/Messages.java Tue May 11 20:37:47 2010
@@ -21,7 +21,7 @@
  * if this tool runs again. Better make changes in the template file.
  */
 
-package org.apache.river.security.policy.util;
+package org.apache.river.imp.security.policy.util;
 
 
 import java.security.AccessController;

Copied: incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/NullPolicyParser.java (from r933907, incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/NullPolicyParser.java)
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/NullPolicyParser.java?p2=incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/NullPolicyParser.java&p1=incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/NullPolicyParser.java&r1=933907&r2=943285&rev=943285&view=diff
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/NullPolicyParser.java (original)
+++ incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/NullPolicyParser.java Tue May 11 20:37:47 2010
@@ -3,7 +3,7 @@
  * and open the template in the editor.
  */
 
-package org.apache.river.security.policy.util;
+package org.apache.river.imp.security.policy.util;
 
 import java.net.URL;
 import java.util.Collection;

Copied: incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/PolicyEntry.java (from r941176, incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyEntry.java)
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/PolicyEntry.java?p2=incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/PolicyEntry.java&p1=incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyEntry.java&r1=941176&r2=943285&rev=943285&view=diff
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyEntry.java (original)
+++ incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/PolicyEntry.java Tue May 11 20:37:47 2010
@@ -21,13 +21,15 @@
 * @version $Revision$
 */
 
-package org.apache.river.security.policy.util;
+package org.apache.river.imp.security.policy.util;
 
+import java.lang.ref.WeakReference;
 import java.net.URL;
 import java.security.CodeSigner;
 import java.security.CodeSource;
 import java.security.Permission;
 import java.security.Principal;
+import java.security.ProtectionDomain;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -50,6 +52,9 @@ public final class PolicyEntry {
 
     // Store CodeSource
     private final CodeSource cs;
+    
+    private final WeakReference<ProtectionDomain> domain;
+    private final boolean hasDomain;
 
     // Array of principals 
     private final List<Principal> principals;
@@ -78,16 +83,72 @@ public final class PolicyEntry {
             this.permissions = new HashSet<Permission>(permissions.size());
             this.permissions.addAll(permissions);
         }
+        domain = null;
+        hasDomain = false;
         /* Effectively immutable, this will make any hash this is contained in perform.
          * May need to consider Serializable for this class yet, we'll see.
          */ 
         if (this.cs == null){
-            hashcode = (principals.hashCode() + this.permissions.hashCode())/2;
+            hashcode = (principals.hashCode() + this.permissions.hashCode()
+                    - Boolean.valueOf(hasDomain).hashCode());
         } else {
-        hashcode = (this.cs.hashCode() + principals.hashCode() + this.permissions.hashCode())/3;
+        hashcode = (this.cs.hashCode() + principals.hashCode() 
+                + this.permissions.hashCode() 
+                - Boolean.valueOf(hasDomain).hashCode());
         }
     }
 
+    
+    public PolicyEntry(ProtectionDomain pd, Collection<? extends Principal> prs,
+            Collection<? extends Permission> permissions ){
+        CodeSource cs = null;
+        if (pd != null){
+            cs = pd.getCodeSource();
+        }
+        this.cs = (cs != null) ? normalizeCodeSource(cs) : null;
+        if ( prs == null || prs.isEmpty()) {
+            this.principals = Collections.emptyList(); // Java 1.5
+        }else{
+            this.principals = new ArrayList<Principal>(prs.size());
+            this.principals.addAll(prs);
+        }
+        if (permissions == null || permissions.isEmpty()) {
+            this.permissions = Collections.emptySet(); // Java 1.5
+        }else{
+            this.permissions = new HashSet<Permission>(permissions.size());
+            this.permissions.addAll(permissions);
+        }
+        domain = new WeakReference<ProtectionDomain>(pd);
+        hasDomain = ( pd != null);
+        /* Effectively immutable, this will make any hash this is contained in perform.
+         * May need to consider Serializable for this class yet, we'll see.
+         */
+        if (pd == null){
+            hashcode = (principals.hashCode() + this.permissions.hashCode() 
+                    - Boolean.valueOf(hasDomain).hashCode());
+        } else {
+            int codeBaseHash = 0;
+            if (cs != null){
+                codeBaseHash = cs.hashCode();
+            }
+            hashcode = (pd.hashCode() + principals.hashCode() 
+                + this.permissions.hashCode() + codeBaseHash 
+                - Boolean.valueOf(hasDomain).hashCode());
+        }
+    }
+    
+    /**
+     * Checks if passed ProtectionDomain matches this PolicyEntry. Null ProtectionDomain of
+     * PolicyEntry implies any ProtectionDomain; non-null ProtectionDomain is
+     * compared with equals();
+     */
+    public boolean impliesProtectionDomain(ProtectionDomain pd) {
+        if (hasDomain == false) return true;
+        if (pd == null) return false;       
+        if (domain.get() == null ) return false; // hasDomain already true
+        return pd.equals(domain.get()); // pd not null
+    }
+
     /**
      * Checks if passed CodeSource matches this PolicyEntry. Null CodeSource of
      * PolicyEntry implies any CodeSource; non-null CodeSource forwards to its
@@ -142,7 +203,9 @@ public final class PolicyEntry {
      * Returns true if this PolicyEntry defines no Permissions, false otherwise.
      */
     public boolean isVoid() {
-        return permissions.size() == 0;
+        if (permissions.size() == 0 ) return true;
+        if (hasDomain == true && domain.get() == null) return true;
+        return false;
     }
     
     @Override
@@ -150,8 +213,12 @@ public final class PolicyEntry {
         if (this == o) return true;
         if ( !(o instanceof PolicyEntry)) return false;
         PolicyEntry pe = (PolicyEntry) o;
-        if ( (cs == pe.cs || cs.equals(pe.cs)) && principals.equals(pe.principals) 
-                && permissions.equals(pe.permissions) ) return true;
+        if ( hasDomain == pe.hasDomain
+                && (domain == pe.domain || domain.get().equals(pe.domain.get()))
+                && (cs == pe.cs || cs.equals(pe.cs)) 
+                && principals.equals(pe.principals) 
+                && permissions.equals(pe.permissions) ) 
+            return true;
         return false;
     }
     
@@ -159,4 +226,18 @@ public final class PolicyEntry {
     public int hashCode(){
         return hashcode;        
     }
+    
+    @Override
+    public String toString(){
+        String domainString = ( domain == null || domain.get() == null) 
+                ?  "" : domain.get().toString();
+        String csString = (cs == null)?  "": cs.toString();
+        String prinStr = principals.toString();
+        String permStr = permissions.toString();
+        int size = domainString.length()+ csString.length() 
+                + prinStr.length() + permStr.length();
+        StringBuilder sb = new StringBuilder(size);
+        sb.append(domainString).append(csString).append(prinStr).append(permStr);
+        return sb.toString();
+    }
 }

Copied: incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/PolicyParser.java (from r933907, incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyParser.java)
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/PolicyParser.java?p2=incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/PolicyParser.java&p1=incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyParser.java&r1=933907&r2=943285&rev=943285&view=diff
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyParser.java (original)
+++ incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/PolicyParser.java Tue May 11 20:37:47 2010
@@ -3,7 +3,7 @@
  * and open the template in the editor.
  */
 
-package org.apache.river.security.policy.util;
+package org.apache.river.imp.security.policy.util;
 
 import java.net.URL;
 import java.util.Collection;

Copied: incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/PolicyUtils.java (from r933907, incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyUtils.java)
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/PolicyUtils.java?p2=incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/PolicyUtils.java&p1=incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyUtils.java&r1=933907&r2=943285&rev=943285&view=diff
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/PolicyUtils.java (original)
+++ incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/PolicyUtils.java Tue May 11 20:37:47 2010
@@ -21,7 +21,7 @@
 * @version $Revision$
 */
 
-package org.apache.river.security.policy.util;
+package org.apache.river.imp.security.policy.util;
 
 import java.io.File;
 import java.io.InputStream;
@@ -41,8 +41,7 @@ import java.util.Enumeration;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Properties;
-
-import org.apache.river.security.concurrent.ConcurrentPermissions;
+import org.apache.river.imp.security.policy.se.ConcurrentPermissions;
 
 /**
  * This class consist of a number of static methods, which provide a common functionality 

Copied: incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/UnresolvedPrincipal.java (from r933907, incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/UnresolvedPrincipal.java)
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/UnresolvedPrincipal.java?p2=incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/UnresolvedPrincipal.java&p1=incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/UnresolvedPrincipal.java&r1=933907&r2=943285&rev=943285&view=diff
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/UnresolvedPrincipal.java (original)
+++ incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/UnresolvedPrincipal.java Tue May 11 20:37:47 2010
@@ -20,7 +20,7 @@
 * @version $Revision$
 */
 
-package org.apache.river.security.policy.util;
+package org.apache.river.imp.security.policy.util;
 
 import java.security.Principal;
 

Copied: incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/Util.java (from r933907, incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/Util.java)
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/Util.java?p2=incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/Util.java&p1=incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/Util.java&r1=933907&r2=943285&rev=943285&view=diff
==============================================================================
--- incubator/river/jtsk/trunk/src/org/apache/river/security/policy/util/Util.java (original)
+++ incubator/river/jtsk/trunk/src/org/apache/river/imp/security/policy/util/Util.java Tue May 11 20:37:47 2010
@@ -15,7 +15,7 @@
  *  limitations under the License.
  */
 
-package org.apache.river.security.policy.util;
+package org.apache.river.imp.security.policy.util;
 
 public class Util {