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 2011/12/19 20:42:38 UTC

svn commit: r1220916 [1/2] - in /river/jtsk/skunk/peterConcurrentPolicy: qa/src/com/sun/jini/test/spec/jeri/https/ src/net/jini/security/ src/net/jini/security/policy/ src/org/apache/river/api/delegates/ src/org/apache/river/api/security/ src/org/apach...

Author: peter_firmstone
Date: Mon Dec 19 19:42:37 2011
New Revision: 1220916

URL: http://svn.apache.org/viewvc?rev=1220916&view=rev
Log:
River-323 Stable concurrent DynamicPolicyProvider and ConcurrentPolicyFile with policy parser and other changes including DelegateSecurityManager with an executor to parallelise ProtectionDomain checks.

Added:
    river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/DynamicPermissionCollection.java   (with props)
    river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/PermissionComparator.java   (with props)
    river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/PermissionStringEqualityWrapper.java   (with props)
    river/jtsk/skunk/peterConcurrentPolicy/test/src/net/jini/security/DynamicPermissionCollectionTest.java
      - copied, changed from r1213147, river/jtsk/skunk/peterConcurrentPolicy/test/src/net/jini/security/MultiReadPermissionCollectionTest.java
Modified:
    river/jtsk/skunk/peterConcurrentPolicy/qa/src/com/sun/jini/test/spec/jeri/https/HttpsRobustnessTest.td
    river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/ConcurrentPermissions.java
    river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/GrantPermission.java
    river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/PermissionPendingResolutionCollection.java
    river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/policy/ConcurrentPolicyFile.java
    river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/policy/DynamicPolicyProvider.java
    river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/policy/PolicyFileProvider.java
    river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/delegates/DelegatePermission.java
    river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/CodeSourceSetGrant.java
    river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/DelegateCombinerSecurityManager.java
    river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/PermissionGrantBuilderImp.java
    river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/ProtectionDomainGrant.java
    river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/DefaultPolicyParser.java
    river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/DefaultPolicyScanner.java
    river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/NullPolicyParser.java
    river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/PolicyParser.java
    river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/PolicyUtils.java
    river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/Segment.java
    river/jtsk/skunk/peterConcurrentPolicy/test/src/net/jini/security/ConcurrentPermissionsTest.java
    river/jtsk/skunk/peterConcurrentPolicy/test/src/net/jini/security/GrantPermissionTest.java
    river/jtsk/skunk/peterConcurrentPolicy/test/src/net/jini/security/MultiReadPermissionCollectionTest.java
    river/jtsk/skunk/peterConcurrentPolicy/test/src/org/apache/river/api/security/DelegateCombinerSecurityManagerTest.java
    river/jtsk/skunk/peterConcurrentPolicy/test/src/org/apache/river/impl/security/policy/util/DefaultPolicyParserTest.java
    river/jtsk/skunk/peterConcurrentPolicy/test/src/org/apache/river/impl/security/policy/util/SegmentTest.java

Modified: river/jtsk/skunk/peterConcurrentPolicy/qa/src/com/sun/jini/test/spec/jeri/https/HttpsRobustnessTest.td
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/qa/src/com/sun/jini/test/spec/jeri/https/HttpsRobustnessTest.td?rev=1220916&r1=1220915&r2=1220916&view=diff
==============================================================================
--- river/jtsk/skunk/peterConcurrentPolicy/qa/src/com/sun/jini/test/spec/jeri/https/HttpsRobustnessTest.td (original)
+++ river/jtsk/skunk/peterConcurrentPolicy/qa/src/com/sun/jini/test/spec/jeri/https/HttpsRobustnessTest.td Mon Dec 19 19:42:37 2011
@@ -3,10 +3,10 @@ testCategories=jeri,jeri_spec
 testConfiguration=<url: HttpsServerEndpointTest.config>
 com.sun.jini.qa.harness.runkitserver=false 
 com.sun.jini.qa.harness.runjiniserver=false
-testjvmargs=\
--Xdebug,\
--Xrunjdwp:transport=dt_socket+,address=8000+,server=y+,suspend=y,\
-${testjvmargs}
+#testjvmargs=\
+#-Xdebug,\
+#-Xrunjdwp:transport=dt_socket+,address=8000+,server=y+,suspend=y,\
+#${testjvmargs}
 #-Djava.security.debug=access:failure,\
 #-Dnet.jini.security.policy.PolicyFileProvider.basePolicyClass=net.jini.security.policy.ConcurrentPolicyFile,\
 #-Djava.security.manager=com.sun.jini.tool.ProfilingSecurityManager,\

Modified: river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/ConcurrentPermissions.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/ConcurrentPermissions.java?rev=1220916&r1=1220915&r2=1220916&view=diff
==============================================================================
--- river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/ConcurrentPermissions.java (original)
+++ river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/ConcurrentPermissions.java Mon Dec 19 19:42:37 2011
@@ -24,10 +24,14 @@ import java.security.Permission;
 import java.security.PermissionCollection;
 import java.security.UnresolvedPermission;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -103,17 +107,18 @@ implements Serializable {
             unresolved.add(new PermissionPendingResolution((UnresolvedPermission)permission));            
         }
         // this get saves unnecessary object creation.
-        PermissionCollection pc = permsMap.get(permission.getClass());
+        Class clas = permission.getClass();
+        PermissionCollection pc = permsMap.get(clas);
         if (pc == null){                       
-            pc = new MultiReadPermissionCollection(permission);   
+            pc = new DynamicPermissionCollection(null, clas);   
             PermissionCollection existed = 
-                    permsMap.putIfAbsent(permission.getClass(), pc);
+                    permsMap.putIfAbsent(clas, pc);
             if (existed != null) {
                 pc = existed;
             }
         } 
 	pc.add(permission);
-    }    
+    }
     
     /**
      * Returns true if Permission is implied for this PermissionDomain.
@@ -127,13 +132,14 @@ implements Serializable {
     public boolean implies(Permission permission) {
         if (permission == null){return false;}
         if (allPermission == true){return true;}
-        if (permission instanceof UnresolvedPermission){return false;}        
-        PermissionCollection pc = permsMap.get(permission.getClass()); // To stop unnecessary object creation
+        if (permission instanceof UnresolvedPermission){return false;}
+        Class clas = permission.getClass();
+        PermissionCollection pc = permsMap.get(clas); // To stop unnecessary object creation
         if (pc != null && pc.implies(permission)) { return true;}
         if (unresolved.awaitingResolution() == 0 ) { return false; }
         if (pc == null){
-            pc = new MultiReadPermissionCollection(permission); // once added it cannot be removed atomically.
-            PermissionCollection existed = permsMap.putIfAbsent(permission.getClass(), pc);
+            pc = new DynamicPermissionCollection(null, clas); // once added it cannot be removed atomically.
+            PermissionCollection existed = permsMap.putIfAbsent(clas, pc);
             if (existed != null) pc = existed;
         }
         unresolved.resolveCollection(permission, pc);

Added: river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/DynamicPermissionCollection.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/DynamicPermissionCollection.java?rev=1220916&view=auto
==============================================================================
--- river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/DynamicPermissionCollection.java (added)
+++ river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/DynamicPermissionCollection.java Mon Dec 19 19:42:37 2011
@@ -0,0 +1,191 @@
+/*
+ * 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 net.jini.security;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import org.apache.river.impl.util.CollectionsConcurrent;
+
+/**
+ * This homogenous PermissionCollection is designed to overcome some shortfalls with existing 
+ * PermissionCollection's that block for potentially long durations
+ * on implies(), like SocketPermissionCollection.
+ * 
+ * @author peter
+ */
+final class DynamicPermissionCollection extends PermissionCollection {
+    private static final long serialVersionUID = 1L;
+    
+    private final Collection<Permission> perms;
+    private final Class cl;
+    private final Comparator<Permission> comp;
+    
+    DynamicPermissionCollection(Comparator<Permission> c, Class cl){
+        perms = CollectionsConcurrent.multiReadCollection(new ArrayList<Permission>());
+        this.cl = cl;
+        comp = c;
+    }
+    
+    private DynamicPermissionCollection(Class cl, Comparator<Permission> c){
+        this.cl = cl;
+        comp = c;
+        Collection<Permission> col = new ArrayList<Permission>();
+        perms = CollectionsConcurrent.multiReadCollection(col);
+    }
+
+    @Override
+    public void add(Permission permission) {
+        if ( ! cl.isInstance(permission))
+            throw new IllegalArgumentException("invalid permission: "+ permission);
+        if (isReadOnly()) throw new SecurityException("PermissionCollection is read only");
+        perms.add(permission);
+    }
+
+    @Override
+    public boolean implies(Permission permission) {
+        if ( ! cl.isInstance(permission)) return false;
+        Permission [] p = perms.toArray(new Permission[0]); //perms.size() may change
+        if (comp != null){
+            Arrays.sort(p, comp);
+        }
+        PermissionCollection pc = permission.newPermissionCollection();
+        int l = p.length;
+        if (pc != null) {
+            for ( int i = 0; i < l ; i++ ){
+                pc.add(p[i]);
+            }
+            return pc.implies(permission);
+        }
+        for ( int i = 0; i < l ; i++ ){
+            if (p[i].implies(permission)) return true;
+        }
+        return false;
+    }
+
+    @Override
+    public Enumeration<Permission> elements() {
+        return Collections.enumeration(perms);
+    }
+    
+    private Collection<Permission> getPermissions(){
+        return perms;
+    }
+    
+    private void readObject(ObjectInputStream stream) throws 
+                InvalidObjectException, IOException, ClassNotFoundException {
+            throw new InvalidObjectException("Serialization Proxy required");
+    }
+    
+    private Object writeReplace(){
+            PermissionCollection pc = 
+                new SerializationProxy(cl, comp, this);
+            if (isReadOnly()) pc.setReadOnly();
+            return pc;
+    }
+    
+    /**
+     * A serialization proxy has been provided to allow the fields in DynamicPermissionCollection
+     * to be final.
+     * 
+     * The serialization proxy extends PermissionCollection for cases where
+     * it may contain a Permission that refers to it, eg a DelegatePermission.
+     * To fix the readResolve bug.
+     * 
+     * This has been provided to implement Serialization, it is better to
+     * avoid serializing a PermissionCollection.
+     */
+    private final static class SerializationProxy extends PermissionCollection {
+        private static final long serialVersionUID = 1L;
+        private Permission[] permissions;
+        private Class clazz;
+        private Comparator<Permission> comp;
+        private transient DynamicPermissionCollection resolved;
+        SerializationProxy(Class cl, Comparator<Permission> c, DynamicPermissionCollection pc){
+            permissions = null;
+            clazz = cl;
+            comp = c;
+            resolved = pc;
+        } 
+        
+        private Object readResolve() {
+            PermissionCollection pc = 
+                    new DynamicPermissionCollection(clazz, comp);
+            int length = permissions.length;
+            for ( int i = 0 ; i < length ; i++){
+                pc.add(permissions[i]);
+            }
+            if (isReadOnly()) pc.setReadOnly();
+            return pc;
+        }
+        
+        private void writeObject(ObjectOutputStream s) throws IOException{
+            permissions = resolved.getPermissions().toArray(new Permission[0]);
+            s.defaultWriteObject();
+        }
+        
+        private void readObject(ObjectInputStream stream) throws 
+                InvalidObjectException, IOException, ClassNotFoundException {
+            stream.defaultReadObject();
+        }
+
+        @Override
+        public void add(Permission permission) {
+            if ( resolved != null ){
+                resolved.add(permission);
+                return;
+            }
+            throw new IllegalStateException("unresolved after serialization");
+        }
+
+        @Override
+        public boolean implies(Permission permission) {
+            if ( resolved != null ){
+                return resolved.implies(permission);
+            }
+            throw new IllegalStateException("unresolved after serialization");
+        }
+
+        @Override
+        public Enumeration<Permission> elements() {
+            if ( resolved != null ){
+                return resolved.elements();
+            }
+            throw new IllegalStateException("unresolved after serialization");
+        }
+        
+        @Override
+        public void setReadOnly(){
+            super.setReadOnly();
+            resolved.setReadOnly();
+        }
+     
+    }
+ 
+}

Propchange: river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/DynamicPermissionCollection.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/GrantPermission.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/GrantPermission.java?rev=1220916&r1=1220915&r2=1220916&view=diff
==============================================================================
--- river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/GrantPermission.java (original)
+++ river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/GrantPermission.java Mon Dec 19 19:42:37 2011
@@ -774,10 +774,10 @@ public final class GrantPermission exten
 		throw new SecurityException(
 		    "can't add to read-only PermissionCollection");
 	    }
-	    if (!perms.contains(p)){
+//	    if (!perms.contains(p)){
 		perms.add(p);
 		implier.add((GrantPermission) p);
-	    }
+//	    }
 	}
 	
 	public synchronized Enumeration elements() {

Added: river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/PermissionComparator.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/PermissionComparator.java?rev=1220916&view=auto
==============================================================================
--- river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/PermissionComparator.java (added)
+++ river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/PermissionComparator.java Mon Dec 19 19:42:37 2011
@@ -0,0 +1,18 @@
+
+package net.jini.security;
+
+import java.security.Permission;
+import java.util.Comparator;
+
+/**
+ *
+ * @author peter
+ */
+public class PermissionComparator implements Comparator<Permission> {
+
+    @Override
+    public int compare(Permission o1, Permission o2) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+    
+}

Propchange: river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/PermissionComparator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/PermissionPendingResolutionCollection.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/PermissionPendingResolutionCollection.java?rev=1220916&r1=1220915&r2=1220916&view=diff
==============================================================================
--- river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/PermissionPendingResolutionCollection.java (original)
+++ river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/PermissionPendingResolutionCollection.java Mon Dec 19 19:42:37 2011
@@ -78,8 +78,8 @@ class PermissionPendingResolutionCollect
         }
     }
     
-    PermissionCollection resolveCollection(Permission target,
-                                           PermissionCollection holder ){
+    PermissionCollection resolveCollection(Permission target, PermissionCollection holder ){
+        if (target == null || holder == null) throw new NullPointerException("target or holder cannot be null");
         if (pending.get() == 0) { return holder; }
         String klass = target.getClass().getName();
         Collection<PermissionPendingResolution> klassMates = klasses.remove(klass);
@@ -88,9 +88,6 @@ class PermissionPendingResolutionCollect
                 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();

Added: river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/PermissionStringEqualityWrapper.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/PermissionStringEqualityWrapper.java?rev=1220916&view=auto
==============================================================================
--- river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/PermissionStringEqualityWrapper.java (added)
+++ river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/PermissionStringEqualityWrapper.java Mon Dec 19 19:42:37 2011
@@ -0,0 +1,59 @@
+/*
+ *  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 net.jini.security;
+
+import java.security.Permission;
+
+/**
+ * The only purpose of this class is to encapsulate an existing Permission that
+ * doesn't implement equals and hashCode efficiently 
+ * @author peter
+ */
+public class PermissionStringEqualityWrapper extends Permission {
+    private static final long serialVersionUID = 1L;
+    
+    private final Permission encapsulated;
+    
+    PermissionStringEqualityWrapper(Permission p){
+        super("PermissionEqualityWrapper: " + p.toString());
+        encapsulated = p;
+    }
+    
+    @Override
+    public boolean implies(Permission permission) {
+        return false;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if ( this == obj ) return true;
+        if ( obj == null ) return false;
+        if (encapsulated.toString().equals(obj.toString())) return true;
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return encapsulated.toString().hashCode();
+    }
+
+    @Override
+    public String getActions() {
+        return encapsulated.getActions();
+    }
+    
+}

Propchange: river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/PermissionStringEqualityWrapper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/policy/ConcurrentPolicyFile.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/policy/ConcurrentPolicyFile.java?rev=1220916&r1=1220915&r2=1220916&view=diff
==============================================================================
--- river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/policy/ConcurrentPolicyFile.java (original)
+++ river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/policy/ConcurrentPolicyFile.java Mon Dec 19 19:42:37 2011
@@ -29,9 +29,11 @@ package net.jini.security.policy;
 import java.io.File;
 import java.lang.ref.Reference;
 import java.net.URL;
+import java.security.AccessControlContext;
 import java.security.AccessController;
 import java.security.AllPermission;
 import java.security.CodeSource;
+import java.security.Guard;
 import java.security.Permission;
 import java.security.PermissionCollection;
 import java.security.Permissions;
@@ -39,6 +41,7 @@ import java.security.Policy;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 import java.security.ProtectionDomain;
+import java.security.SecurityPermission;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Enumeration;
@@ -51,6 +54,8 @@ import java.util.concurrent.ConcurrentMa
 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 net.jini.security.ConcurrentPermissions;
 import org.apache.river.api.security.PermissionGrant;
 import org.apache.river.impl.security.policy.util.DefaultPolicyParser;
@@ -197,6 +202,9 @@ public class ConcurrentPolicyFile extend
     // A specific parser for a particular policy file format.
     private final PolicyParser parser;
     
+    private static final Guard guard = 
+            new SecurityPermission("getPolicy");
+    
     /**
      * Default constructor, equivalent to
      * <code>ConcurrentPolicyFile(new DefaultPolicyParser())</code>.
@@ -210,6 +218,7 @@ public class ConcurrentPolicyFile extend
      * @param dpr 
      */
     protected ConcurrentPolicyFile(PolicyParser dpr) throws PolicyInitializationException {
+        guard.checkGuard(null);
         parser = dpr;
         ReadWriteLock rwl = new ReentrantReadWriteLock();
         rl = rwl.readLock();
@@ -229,8 +238,10 @@ public class ConcurrentPolicyFile extend
             initialize();
             ensureDependenciesResolved();
         } catch (SecurityException e){
+            throw e;
+        } catch (Exception e){
             throw new PolicyInitializationException("PolicyInitialization failed", e);
-    }
+        }
     }
 
     private void ensureDependenciesResolved() {
@@ -247,6 +258,9 @@ public class ConcurrentPolicyFile extend
      * 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>.
+     * 
+     * Each PermissionCollection returned is a unique instance.
+     * 
      * @param pd ProtectionDomain
      * @see ProtectionDomain
      */
@@ -264,10 +278,10 @@ public class ConcurrentPolicyFile extend
          */
         rl.lock();
         try {
-            PermissionCollection perms = 
-                    pd != null ? impliesCache.get(pd): null;
-            if (perms != null) return perms;
-            perms = new ConcurrentPermissions();
+//            PermissionCollection perms = 
+//                    pd != null ? impliesCache.get(pd): null;
+//            if (perms != null) return perms;
+            PermissionCollection perms = new ConcurrentPermissions();
                 Iterator<PermissionGrant> it = grants.iterator();
                 while (it.hasNext()){
                     PermissionGrant ge = it.next();
@@ -290,7 +304,7 @@ public class ConcurrentPolicyFile extend
                     }
                 }
             }
-            if (pd != null) impliesCache.put(pd, perms); //Overwrite older.
+//            if (pd != null) impliesCache.put(pd, perms); //Overwrite older.
             return perms;
         }finally{
             rl.unlock();
@@ -339,7 +353,16 @@ public class ConcurrentPolicyFile extend
     @Override
     public boolean implies(ProtectionDomain domain, Permission permission) {
         if (permission == null) throw new NullPointerException("permission not allowed to be null");
-	PermissionCollection pc = getPermissions(domain);
+        PermissionCollection pc = 
+                    domain != null ? impliesCache.get(domain): null;
+        if (pc == null){
+            pc = getPermissions(domain);
+            if (domain != null){
+                PermissionCollection existed = impliesCache.putIfAbsent(domain, pc);
+                // Don't bother replacing pc with existed, we're not mutating
+                // so it doesn't matter.
+            }
+        }
         return pc.implies(permission);
     }
 
@@ -355,12 +378,14 @@ public class ConcurrentPolicyFile extend
         if ( !wl.tryLock() ) return; // If another thread has the lock, policy is undergoing an update.
         try {
             initialize();
+        } catch (Exception ex) {
+            ex.printStackTrace(System.err);
         } finally {
             wl.unlock();
         }
     }
     
-    private void initialize(){
+    private void initialize() throws Exception{
         try {
             Set<PermissionGrant> fresh = AccessController.doPrivileged( 
                 new PrivilegedExceptionAction<Set<PermissionGrant>>(){
@@ -384,8 +409,10 @@ public class ConcurrentPolicyFile extend
                                 // It's best to let a SecurityException bubble up
                                 // in case there is a problem with our policy configuration
                                 // or implementation.
-                                if ( e instanceof SecurityException ) throw (SecurityException) e;
-                                e.printStackTrace(System.out);
+                                if ( e instanceof SecurityException ) {
+                                    e.printStackTrace(System.out);
+                                    throw (SecurityException) e;
+                                }
                                 // ignore.
                             }
                         } 
@@ -401,7 +428,9 @@ public class ConcurrentPolicyFile extend
             cache.clear(); // Clear the cache.
             impliesCache.clear();
         }catch (PrivilegedActionException e){
-            e.printStackTrace(System.err);
+            Throwable t = e.getCause();
+            if ( t instanceof Exception ) throw (Exception) t;
+            throw e;
         }
     }
     

Modified: river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/policy/DynamicPolicyProvider.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/policy/DynamicPolicyProvider.java?rev=1220916&r1=1220915&r2=1220916&view=diff
==============================================================================
--- river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/policy/DynamicPolicyProvider.java (original)
+++ river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/policy/DynamicPolicyProvider.java Mon Dec 19 19:42:37 2011
@@ -162,7 +162,8 @@ public class DynamicPolicyProvider exten
      private static final String basePolicyClassProperty =
 	"net.jini.security.policy.DynamicPolicyProvider.basePolicyClass";
     private static final String defaultBasePolicyClass =
-	"net.jini.security.policy.PolicyFileProvider";
+            "net.jini.security.policy.ConcurrentPolicyFile";
+//	"net.jini.security.policy.PolicyFileProvider";
     private static final ProtectionDomain sysDomain = 
 	AccessController.doPrivileged(new PrivilegedAction<ProtectionDomain>() {
         
@@ -457,7 +458,7 @@ Put the policy providers and all referen
 	 * container.
          * 
          * I've since found PolicyPermission's to be unnecessary, the 
-         * ProtectionDomain only merges the permissions for toString()
+         * ProtectionDomain only temporarily merges the permissions for toString()
          * not policy decisions.
          * 
          * TODO: Remove PolicyPermission's
@@ -519,45 +520,47 @@ Put the policy providers and all referen
         // First check our cache if the basePolicy is not dynamic.
         PermissionCollection pc = domain != null? cache.get(domain): null;
         if ( pc != null ) {
-            if (pc.implies(permission)) return true;           
-        } else {
-	    /* Do not call implies on the base Policy, if
-	     * there are UnresolvedPermission's that are undergoing resolution
-	     * while another Permission within that collection is already
-	     * resolved, the Enumeration will cause a ConcurrentModificationException.
-	     */ 
-	    PermissionCollection bpc = basePolicy.getPermissions(domain);
-	    /* Be mindful of static Permissions held by the 
-	     * ProtectionDomain, a Permission may be implied by the 
-	     * the combination of Permission's in the ProtectionDomain and 
-	     * the base policy, but not by either individually.
-	     * The ProtectionDomain merge is only perfomed if
-	     * ProtectionDomain.toString() is called, since this is not
-	     * guaranteed and is also expensive, the underlying policy
-	     * performs the merge.
-	     * 
-	     * Furthermore it is commonly understood that when
-	     * ProtectionDomain.implies(Permission) is called, it first checks
-	     * it's own private Permissions, then calls Policy.implies, however
-	     * this is incorrect, the Policy is checked first.
-	     */ 
-	    //PermissionCollection pdpc = domain.getPermissions();
-	    //PermissionCollection[] p = { pdpc, bpc };
-	   /* Don't use the underlying policy permission collection otherwise
-	    * we can leak grants in to the underlying policy from our cache,
-	    * this could then be merged into the PermissionDomain's permission
-	    * cache negating the possiblity of revoking the permission.  This
-	    * PolicyUtils method defensively copies or creates new if null.
-	    */
-            pc = PolicyUtils.asConcurrent(bpc);
-            PermissionCollection existed = 
-                    domain != null ? cache.putIfAbsent(domain, pc): null; 
-            if ( existed != null ){
-                pc = existed;
-            }
-            expandUmbrella(pc); // We need to avoid using PolicyFileProvider as grants from it are not revokable.
-	    if ( pc.implies(permission)) return true;
-	}
+            if (pc.implies(permission)) return true;          
+        } 
+        /* Do not call implies on the base Policy, if
+         * there are UnresolvedPermission's that are undergoing resolution
+         * while another Permission within that collection is already
+         * resolved, the Enumeration will cause a ConcurrentModificationException.
+         */ 
+        PermissionCollection bpc = basePolicy.getPermissions(domain);
+        /* Be mindful of static Permissions held by the 
+         * ProtectionDomain, a Permission may be implied by the 
+         * the combination of Permission's in the ProtectionDomain and 
+         * the base policy, but not by either individually.
+         * The ProtectionDomain merge is only perfomed if
+         * ProtectionDomain.toString() is called, since this is not
+         * guaranteed and is also expensive, the underlying policy
+         * performs the merge.
+         * 
+         * Furthermore it is commonly understood that when
+         * ProtectionDomain.implies(Permission) is called, it first checks
+         * it's own private Permissions, then calls Policy.implies, however
+         * this is incorrect, the Policy is checked first.
+         */ 
+        //PermissionCollection pdpc = domain.getPermissions();
+        //PermissionCollection[] p = { pdpc, bpc };
+       /* Don't use the underlying policy permission collection otherwise
+        * we can leak grants in to the underlying policy from our cache,
+        * this could then be merged into the PermissionDomain's permission
+        * cache negating the possiblity of revoking the permission.  This
+        * PolicyUtils method defensively copies or creates new if null.
+        */
+        pc = PolicyUtils.asConcurrent(bpc);
+        /* Don't place it in the cache half finished or check it yet since
+         * mutations are blocking */
+//            PermissionCollection existed = 
+//                    domain != null ? cache.putIfAbsent(domain, pc): null; 
+//            if ( existed != null ){
+//                pc = existed;
+//            }
+//            expandUmbrella(pc); // We need to avoid using PolicyFileProvider as grants from it are not revokable.
+//	    if ( pc.implies(permission)) return true;
+	
         // Once we get to here pc is definitely not null and we have the
         // copy referenced in the cache.
 //        if (loggable){
@@ -585,10 +588,10 @@ Put the policy providers and all referen
 //        if (loggable) {
 //            logger.log(Level.FINEST, "Grants: " + dynamicallyGrantedPermissions.toString());
 //        }
-        if (dynamicallyGrantedPermissions.isEmpty()) {
-            // We have no dynamic grants
-            return false;
-        }
+//        if (dynamicallyGrantedPermissions.isEmpty()) {
+//            // We have no dynamic grants
+//            return false;
+//        }
         Iterator<Permission> dgpi = dynamicallyGrantedPermissions.iterator();
         while (dgpi.hasNext()){
             pc.add(dgpi.next());
@@ -598,10 +601,15 @@ Put the policy providers and all referen
 //        if (loggable) {
 //            logger.log(Level.FINEST, "PermissionCollection: " + pc.toString());
 //        }
-        // We have added dynamic grants, lets expand them
-	// But UmbrellaGrant's are to enable easy dynamic GrantPermission's?
+        // We have added dynamic grants, lets expand any UmbrellaGrant's
         expandUmbrella(pc);
-        return pc.implies(permission);
+        if ( pc.implies(permission) ){
+            // The cache is replaced rather than updated, to avoid umbrella grants
+            // causing GrantPermission recursion.
+            if (domain != null ) cache.replace(domain, pc);
+            return true;
+        }
+        return false;
     }
     
     /**

Modified: river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/policy/PolicyFileProvider.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/policy/PolicyFileProvider.java?rev=1220916&r1=1220915&r2=1220916&view=diff
==============================================================================
--- river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/policy/PolicyFileProvider.java (original)
+++ river/jtsk/skunk/peterConcurrentPolicy/src/net/jini/security/policy/PolicyFileProvider.java Mon Dec 19 19:42:37 2011
@@ -26,6 +26,8 @@ import java.security.Policy;
 import java.security.PrivilegedAction;
 import java.security.ProtectionDomain;
 import java.security.Security;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashSet;
@@ -276,7 +278,8 @@ public class PolicyFileProvider extends 
 
     static void expandUmbrella(PermissionCollection pc) {
 	if (pc.implies(umbrella)) {
-            Set<Permission> perms = new HashSet<Permission>(120);
+            // Don't use Set, avoid calling equals and hashCode on SocketPermission.
+            Collection<Permission> perms = new ArrayList<Permission>(120);
             Enumeration<Permission> e = pc.elements();
             while (e.hasMoreElements()){
                 Permission p = e.nextElement();

Modified: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/delegates/DelegatePermission.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/delegates/DelegatePermission.java?rev=1220916&r1=1220915&r2=1220916&view=diff
==============================================================================
--- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/delegates/DelegatePermission.java (original)
+++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/delegates/DelegatePermission.java Mon Dec 19 19:42:37 2011
@@ -96,7 +96,10 @@ public final class DelegatePermission ex
                 Ref.WEAK, Ref.SOFT
             );
     /**
-     * Factory method to obtain a DelegatePermission
+     * Factory method to obtain a DelegatePermission, this is essential to 
+     * overcome broken equals contract in some jvm Permission implementations
+     * like SocketPermission and allow caching.
+     * 
      * @param p Permission to be represented.
      * @return DelegatePermission
      */
@@ -113,14 +116,14 @@ public final class DelegatePermission ex
     }
     
     private final Permission permission;
-    private final transient int hashCode;
+//    private final transient int hashCode;
     
     private DelegatePermission(Permission p){
 	super(p.getClass().toString() + " " + p.getName());
 	permission = p;
-	int hash = 5;
-	hash = 41 * hash + (this.permission != null ? this.permission.hashCode() : 0);
-	hashCode = hash;
+//	int hash = 5;
+//	hash = 41 * hash + (this.permission != null ? this.permission.hashCode() : 0);
+//	hashCode = hash;
     }
     
     public void checkGuard(Object object) throws SecurityException {
@@ -129,6 +132,7 @@ public final class DelegatePermission ex
     }
 
     @Override
+    // This is implemented but never called.
     public boolean implies(Permission permission) {
 	if (permission == null) return false;
 	if (!(permission instanceof DelegatePermission)) return false;
@@ -140,19 +144,24 @@ public final class DelegatePermission ex
 	return permission;
     }
 
+    // Don't override equals so all Delegates can be used in Collections
+    // including those containing SocketPermission.
     @Override
     public boolean equals(Object obj) {
-	if (obj == this) return true;
-	if (obj == null) return false;
-	if ( obj.hashCode() != hashCode ) return false;
-	if (!(obj instanceof DelegatePermission)) return false;
-	if ( obj.getClass() != this.getClass() ) return false;
-	return permission.equals(((DelegatePermission) permission).getPermission());
-        }
+        return obj == this;
+//	if (obj == this) return true;
+//	if (obj == null) return false;
+//	if ( obj.hashCode() != hashCode ) return false;
+//	if (!(obj instanceof DelegatePermission)) return false;
+//	if ( obj.getClass() != this.getClass() ) return false;
+//	return permission.equals(((DelegatePermission) permission).getPermission());
+    }
 
     @Override
     public int hashCode() {
-	return hashCode;
+//	return hashCode;
+        // Not in constructor so we don't let this escape.
+        return System.identityHashCode(this);
     }
 
     @Override

Modified: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/CodeSourceSetGrant.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/CodeSourceSetGrant.java?rev=1220916&r1=1220915&r2=1220916&view=diff
==============================================================================
--- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/CodeSourceSetGrant.java (original)
+++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/CodeSourceSetGrant.java Mon Dec 19 19:42:37 2011
@@ -104,10 +104,13 @@ class CodeSourceSetGrant extends Certifi
         // sun.security.provider.PolicyFile compatibility for null CodeSource.
         // see com.sun.jini.test.spec.policyprovider.dynamicPolicyProvider.GrantPrincipal test.
         if ( codeSource == null ) return false; 
-	if ( cs == null || nullCS.equals(cs)) return true;
+	if ( cs == null || cs.isEmpty()) return true;
+        codeSource = normalizeCodeSource(codeSource);
         Iterator<CodeSource> it = cs.iterator();
         while (it.hasNext()){
-            if  (it.next().implies(normalizeCodeSource(codeSource))) return true;
+            CodeSource c = it.next();
+            if (c == null ) return true;
+            if  (c.implies(codeSource)) return true;
         }
         return false;
     }

Modified: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/DelegateCombinerSecurityManager.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/DelegateCombinerSecurityManager.java?rev=1220916&r1=1220915&r2=1220916&view=diff
==============================================================================
--- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/DelegateCombinerSecurityManager.java (original)
+++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/DelegateCombinerSecurityManager.java Mon Dec 19 19:42:37 2011
@@ -18,8 +18,7 @@
 
 package org.apache.river.api.security;
 
-import java.lang.ref.Reference;
-import java.lang.ref.WeakReference;
+import java.net.SocketPermission;
 import java.security.AccessControlContext;
 import java.security.AccessController;
 import java.security.DomainCombiner;
@@ -31,9 +30,18 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Set;
+import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import org.apache.river.api.delegates.DelegatePermission;
 import org.apache.river.impl.util.CollectionsConcurrent;
 import org.apache.river.impl.util.RC;
@@ -56,6 +64,7 @@ extends SecurityManager implements Deleg
     private final ConcurrentMap<AccessControlContext, Set<Permission>> checked;
     private final Guard g;
     private final Action action;
+    private final ExecutorService executor;
     
     public DelegateCombinerSecurityManager(){
         super();
@@ -71,6 +80,10 @@ extends SecurityManager implements Deleg
         checked = RC.concurrentMap(refmap, Ref.SOFT, Ref.STRONG);
         g = new RevokePermission();
         action = new Action();
+        double blocking_coefficient = 0.8; // 0 CPU intensive to 0.9 IO intensive
+        int numberOfCores = Runtime.getRuntime().availableProcessors();
+        int poolSize = (int) (numberOfCores / ( 1 - blocking_coefficient));
+        executor = Executors.newFixedThreadPool(poolSize);
     }
     
     @Override
@@ -97,7 +110,6 @@ extends SecurityManager implements Deleg
                 // we have sufficient privilege.
                 delegateContext = AccessController.doPrivileged( 
                     new PrivilegedAction<AccessControlContext>(){
-                       
                         public AccessControlContext run() {
                             return new AccessControlContext(finalExecutionContext, dc);
                         }
@@ -119,6 +131,8 @@ extends SecurityManager implements Deleg
         // Normal execution, same as SecurityManager.
         executionContext.checkPermission(perm);
         // If we get to here, no exceptions were thrown, we have permission.
+        // Don't cache SocketPermission.
+        if (perm instanceof SocketPermission) return;
         checkedPerms.add(perm);
     }
 
@@ -164,13 +178,8 @@ extends SecurityManager implements Deleg
     }
     
     private class DelegateDomainCombiner implements DomainCombiner {
-        // Cache the DelegateProtectionDomain's we don't want to 
-        // create any more than abolutely necessary.
-        private final ConcurrentMap<ProtectionDomain,DelegateProtectionDomain> cache;
+        
         private DelegateDomainCombiner (){
-            ConcurrentMap<Referrer<ProtectionDomain>,Referrer<DelegateProtectionDomain>> internal = 
-                    new ConcurrentHashMap<Referrer<ProtectionDomain>,Referrer<DelegateProtectionDomain>>(120);
-            cache = RC.concurrentMap(internal, Ref.WEAK_IDENTITY, Ref.STRONG);
         }
 
         public ProtectionDomain[] combine(ProtectionDomain[] currentDomains, ProtectionDomain[] assignedDomains) {
@@ -178,7 +187,7 @@ extends SecurityManager implements Deleg
              * are from the Context that the SecurityManager has been asked
              * to check.
              * 
-             * This code wraps each ProtectionDomain in a DelegateProtectionDomain
+             * This code wraps assignedDomains in a DelegateProtectionDomain
              * to ensure we check for the DelegatePermission or it's candidate
              * Permission.
              * 
@@ -186,23 +195,13 @@ extends SecurityManager implements Deleg
              * we just created moments earlier, but with the context returned
              * by this DomainCombiner.
              */
-            int l = assignedDomains.length;
-            // I don't believe it's safe to re-use the existing array yet.
+            // I don't believe it's safe to modify the existing array.
             // I think it's the same context array from the original AccessControlContext
             // we've duplicated, so modifing it would risk contaminating the 
             // call stack context.
-            DelegateProtectionDomain[] delegated = new DelegateProtectionDomain[l];
-            for ( int i = 0; i < l ;i++ ){
-                delegated[i] = cache.get(assignedDomains[i]);
-                if (delegated[i] == null){
-                    delegated[i] = new DelegateProtectionDomain(assignedDomains[i]);
-                    DelegateProtectionDomain existed = 
-                            cache.putIfAbsent(assignedDomains[i], delegated[i]);
-                    if (existed != null){
-                        delegated[i] = existed;
-                    }
-                }
-            }
+            // No defensive copying is performed.
+            DelegateProtectionDomain[] delegated = new DelegateProtectionDomain[1];
+            delegated[0] = new DelegateProtectionDomain(assignedDomains);
             return delegated;
         }
     }
@@ -212,50 +211,109 @@ extends SecurityManager implements Deleg
      * a permission check.  The policy will never see it.
      */
     private class DelegateProtectionDomain extends ProtectionDomain {
-        // weakly reference the pd, so it doesn't prevent the cache key
-        // from being garbage collected.
-        private final WeakReference<ProtectionDomain> pd;
+        // Context from AccessControlContext.
+        private final ProtectionDomain[] context;
         
-        DelegateProtectionDomain(ProtectionDomain pd){
+        DelegateProtectionDomain(ProtectionDomain[] context){
             // Use static domain so we don't strong reference to ClassLoader
             // which has a strong reference to ProtectionDomain.
-            super(pd.getCodeSource(),pd.getPermissions());
-            this.pd = new WeakReference<ProtectionDomain>(pd);
+            super(null, null);
+            this.context = context;
         }
         
         @Override
         public boolean implies(Permission perm) {
-            ProtectionDomain pd = this.pd.get();
-            if (pd != null){
-                if (pd.implies(perm)) {
+            Thread currentThread = Thread.currentThread();
+            int l = context.length;
+            CountDownLatch latch = new CountDownLatch(l);
+            List<Future<Boolean>> resultList = null;
+            Collection<Callable<Boolean>> tasks = new ArrayList<Callable<Boolean>>(l);
+            for ( int i = 0; i < l; i++ ){
+                tasks.add(new PermissionCheck(context[i], perm, latch, currentThread));
+            }
+            try {
+                // We can change either call to add a timeout.
+                resultList = executor.invokeAll(tasks);
+                latch.await();
+                Iterator<Future<Boolean>> it = resultList.iterator();
+                try {
+                    while (it.hasNext()){
+                            Boolean result = it.next().get();
+                            if (result.equals(Boolean.FALSE)) {
+                                return false;
+                            }
+                    }
                     return true;
+                } catch (ExecutionException ex) {
+                    // This should never happen, unless a runtime exception occurs.
+                    Logger.getLogger(DelegateCombinerSecurityManager.class.getName()).log(Level.SEVERE, null, ex);
                 }
-                if (perm instanceof DelegatePermission ){
-                    Permission candidate = ((DelegatePermission)perm).getPermission();
-                    if (pd.implies(candidate)){
-                        return true;
-                    }
+            } catch (InterruptedException ex) {
+                // This is normal, it just means one task returned false.
+                // Swallow the interrupt, because it will likely be caused by
+                // a negative result, in which case a SecurityException will
+                // be thrown anyway.
+                Iterator<Future<Boolean>> it = resultList.iterator();
+                while (it.hasNext()){
+                    it.next().cancel(true);
                 }
+                Logger.getLogger(DelegateCombinerSecurityManager.class.getName()).log(Level.FINEST, null, ex);
             }
             return false;
         }
         
         @Override
         public String toString(){
-            // When pd.toString() is called, it will merge the policy permissions
-            // with those in pd if non static, which means the Permissions will no longer
-            // be correct in the superclass.  This won't affect implies, since it
-            // calls the policy anyway, where the permissions have been combined
-            // by the policy.
-            // It will affect getPermissions() however this won't be used.
-//            StringBuilder sb = new StringBuilder(200);
-//            return sb.append("DelegateProtectionDomain\n").append(pd.toString()).toString();
-            // I don't think the output should be any different from standard.
-            ProtectionDomain pd = this.pd.get();
-            if (pd != null){
-                return pd.toString();
+            /* Unfortunately we don't know exactly which domain has failed
+             * in fact, multiple domains may fail the permission check since
+             * they are executed concurrently, for that reason, we'll print
+             * all failed domains on the stack.
+             */
+            StringBuilder sb = new StringBuilder(800);
+            sb.append("DomainCombinerSecurityManager full stack: \n");
+            int l = context.length;
+            for (int i = 0; i < l; i++ ){
+                sb.append(context[i].toString());
+            }
+            return sb.toString();
+        }
+        
+    }
+    
+    /**
+     * Immutable callable task, discarded immediately after use.
+     */
+    private class PermissionCheck implements Callable<Boolean> {
+        private final ProtectionDomain pd;
+        private final Permission p;
+        private final CountDownLatch latch;
+        private final Thread caller;
+        
+        PermissionCheck(ProtectionDomain pd, Permission p, CountDownLatch c, Thread caller){
+            if (pd == null || p == null) throw new NullPointerException();
+            this.pd = pd;
+            this.p = p;
+            latch = c;
+            this.caller = caller;
+        }
+
+        public Boolean call() throws Exception {
+            Boolean result = Boolean.FALSE;
+            if (pd.implies(p)) result = Boolean.TRUE;
+            if (p instanceof DelegatePermission ){
+                Permission candidate = ((DelegatePermission)p).getPermission();
+                if (pd.implies(candidate)){
+                    result = Boolean.TRUE;
+                }
+            }
+            // If we need to check for any Permission that we have substituted
+            // for a standard jvm permission, getPermissions and convert,
+            // then test here for static ProtectionDomain's.
+            if (Boolean.FALSE.equals(result)) {
+                caller.interrupt();
             }
-            return "";
+            latch.countDown();
+            return result;
         }
         
     }

Modified: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/PermissionGrantBuilderImp.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/PermissionGrantBuilderImp.java?rev=1220916&r1=1220915&r2=1220916&view=diff
==============================================================================
--- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/PermissionGrantBuilderImp.java (original)
+++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/PermissionGrantBuilderImp.java Mon Dec 19 19:42:37 2011
@@ -180,7 +180,7 @@ class PermissionGrantBuilderImp extends 
                 return new ClassLoaderGrant(domain, principals, permissions );
             case CODESOURCE:
                 if (hasMultipleCodeSources) {
-                    if (csources == null && multipleCodeSources != null) csources = 
+                    if (multipleCodeSources != null) csources = 
                             multipleCodeSources.toArray(new CodeSource[multipleCodeSources.size()]);
                     return new CodeSourceSetGrant(csources, principals, permissions, inverse);
                 }

Modified: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/ProtectionDomainGrant.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/ProtectionDomainGrant.java?rev=1220916&r1=1220915&r2=1220916&view=diff
==============================================================================
--- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/ProtectionDomainGrant.java (original)
+++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/api/security/ProtectionDomainGrant.java Mon Dec 19 19:42:37 2011
@@ -128,7 +128,11 @@ class ProtectionDomainGrant extends Prin
         if (domain == null ) return true;  // Dynamic grant compatibility
         if (cl == null) return false;       
         if (domain.get() == null ) return false; // is void.
-        return domain.get().getClassLoader().equals(cl); // pd not null
+        ClassLoader thisloader = domain.get().getClassLoader(); // pd not null
+        if (thisloader != null){
+            return thisloader.equals(cl);
+        }
+        return false; // System loader if null.
     }
     // This is here for revoke and for new ProtectionDomain's created by the
     // DomainCombiner such as those in the SubjectDomainCombiner.

Modified: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/DefaultPolicyParser.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/DefaultPolicyParser.java?rev=1220916&r1=1220915&r2=1220916&view=diff
==============================================================================
--- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/DefaultPolicyParser.java (original)
+++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/DefaultPolicyParser.java Mon Dec 19 19:42:37 2011
@@ -23,6 +23,7 @@
 package org.apache.river.impl.security.policy.util;
 
 import java.io.BufferedReader;
+import java.io.File;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.Reader;
@@ -38,13 +39,17 @@ import java.security.Permission;
 import java.security.Principal;
 import java.security.UnresolvedPermission;
 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.Properties;
 import java.util.Set;
+import java.util.SortedSet;
 import java.util.StringTokenizer;
+import java.util.TreeSet;
 
 import org.apache.river.api.security.PermissionGrant;
 import org.apache.river.api.security.PermissionGrantBuilder;
@@ -52,6 +57,7 @@ import org.apache.river.impl.security.po
 import org.apache.river.impl.security.policy.util.DefaultPolicyScanner.KeystoreEntry;
 import org.apache.river.impl.security.policy.util.DefaultPolicyScanner.PermissionEntry;
 import org.apache.river.impl.security.policy.util.DefaultPolicyScanner.PrincipalEntry;
+import org.apache.river.impl.security.policy.util.PolicyUtils.ExpansionFailedException;
 
 
 /**
@@ -132,8 +138,7 @@ public class DefaultPolicyParser impleme
 
         Collection<PermissionGrant> result = new HashSet<PermissionGrant>();
         for (Iterator<GrantEntry> iter = grantEntries.iterator(); iter.hasNext();) {
-            DefaultPolicyScanner.GrantEntry ge = iter
-                    .next();
+            DefaultPolicyScanner.GrantEntry ge = iter.next();
             try {
                 PermissionGrant pe = resolveGrant(ge, ks, system, resolve);
                 if (!pe.isVoid()) {
@@ -145,7 +150,7 @@ public class DefaultPolicyParser impleme
                 e.printStackTrace(System.out);
             }
         }
-
+        
         return result;
     }
 
@@ -192,14 +197,27 @@ public class DefaultPolicyParser impleme
          * CodeSource.
          */
         URL codebase = null;
+        List<URL> codebases = new ArrayList<URL>();
         Certificate[] signers = null;
-        Set<Principal>principals = new HashSet<Principal>();
-        Set<Permission>permissions = new HashSet<Permission>();
-        if (ge.getCodebase(null) != null) {
-            codebase = new URL(resolve ? PolicyUtils.expandURL(ge.getCodebase(system),
-                    system) : ge.getCodebase(null));
+        Set<Principal> principals = new HashSet<Principal>();
+        Set<Permission> permissions = new HashSet<Permission>();
+        String cb = ge.getCodebase(null);
+        if ( cb != null ) {
+            if ( resolve ) {
+                try {
+                    Collection<String> cbstr = expandURLs(cb, system);
+                    Iterator<String> it = cbstr.iterator();
+                    while (it.hasNext()){
+                        codebases.add(new URL(it.next()));
+                    }
+                } catch (ExpansionFailedException e) {
+                    codebase = new URL(cb);
+                }
+            } else {
+                codebase = new URL(cb);
+            }
         }
-        if (ge.getSigners() != null) {
+        if ( ge.getSigners() != null) {
             if (resolve) {
                 ge.setSigners(PolicyUtils.expand(ge.getSigners(), system));
             }
@@ -234,12 +252,48 @@ public class DefaultPolicyParser impleme
             }
         }
         PermissionGrantBuilder pgb = PermissionGrantBuilder.newBuilder();
-        return pgb.codeSource(new CodeSource(codebase, signers))
-                .principals(principals.toArray(new Principal[principals.size()]))
-                .permissions(permissions.toArray(new Permission[permissions.size()]))
-                .context(PermissionGrantBuilder.CODESOURCE)
-                .build();
+        if ( codebase != null ) {
+            pgb.codeSource(new CodeSource(codebase, signers));
+        } else if (codebases.size() == 1) {
+            pgb.codeSource(new CodeSource(codebases.get(0), signers));
+        } else if (codebases.size() > 1 ){
+            pgb.multipleCodeSources();
+            Iterator<URL> iter = codebases.iterator();
+            while (iter.hasNext()){
+                pgb.codeSource(new CodeSource(iter.next(), signers));
+            }
+        }
+        return pgb
+            .principals(principals.toArray(new Principal[principals.size()]))
+            .permissions(permissions.toArray(new Permission[permissions.size()]))
+            .context(PermissionGrantBuilder.CODESOURCE)
+            .build();
+    }
+    
+    Segment segment(String s, Properties p) throws ExpansionFailedException{
+        final String ARRAY_START_MARK = "${{";
+        final String ARRAY_END_MARK = "}}";
+        final String ARRAY_SEPARATOR = ":";
+        final String START_MARK = "${"; //$NON-NLS-1$
+        final String END_MARK = "}"; //$NON-NLS-1$
+        Segment primary = new Segment(s, null);
+        primary.divideAndReplace(ARRAY_START_MARK, ARRAY_END_MARK,
+                ARRAY_SEPARATOR, p);
+        primary.divideAndReplace(START_MARK, END_MARK, null, p);
+        // Repeat twice for nested properties
+        primary.divideAndReplace(START_MARK, END_MARK, null, p);
+        primary.divideAndReplace(START_MARK, END_MARK, null, p);
+        return primary;
     }
+    
+    Collection<String> expandURLs(String s, Properties p) throws ExpansionFailedException{
+        Segment seg = segment(s,p);
+        Collection<String> urls = new ArrayList<String>();
+        while ( seg.hasNext() ){
+            urls.add(seg.next().replace(File.separatorChar, '/'));
+        }
+        return urls;
+    }   
 
     /**
      * Translates PermissionEntry token to Permission object.

Modified: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/DefaultPolicyScanner.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/DefaultPolicyScanner.java?rev=1220916&r1=1220915&r2=1220916&view=diff
==============================================================================
--- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/DefaultPolicyScanner.java (original)
+++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/DefaultPolicyScanner.java Mon Dec 19 19:42:37 2011
@@ -27,16 +27,9 @@ import java.io.Reader;
 import java.io.StreamTokenizer;
 import java.util.ArrayList;
 import java.util.Collection;
-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.Properties;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import org.apache.river.impl.security.policy.util.PolicyUtils.ExpansionFailedException;
@@ -79,7 +72,7 @@ import org.apache.river.impl.security.po
  * @see org.apache.harmony.security.fortress.DefaultPolicyParser
  */
 public class DefaultPolicyScanner {
-
+    
     /**
      * Specific exception class to signal policy file syntax error.
      * 
@@ -405,228 +398,12 @@ public class DefaultPolicyScanner {
                 composeStatus(st)));
     }
 
-    private SortedSet<Segment> segment(String s, Properties p) throws ExpansionFailedException{
-        final String ARRAY_START_MARK = "${{";
-        final String ARRAY_END_MARK = "}}";
-        final String ARRAY_SEPARATOR = ":";
-        final String START_MARK = "${"; //$NON-NLS-1$
-        final String END_MARK = "}"; //$NON-NLS-1$
-        SortedSet<Segment> stringSegments = new TreeSet<Segment>();
-        Segment primary = new Segment(s, null);
-        Collection<Segment> segments 
-                = primary.divideAndReplace(ARRAY_START_MARK, ARRAY_END_MARK,
-                ARRAY_SEPARATOR, p);
-        Iterator<Segment> i = segments.iterator();
-        while (i.hasNext()){
-            stringSegments.addAll(i.next().divideAndReplace(
-                    START_MARK, END_MARK, null, p));
-        }
-        return stringSegments;
-    }
-    
-    protected final Collection<String> expandPolicyProperties(String s, Properties p){
-        Collection<StringBuilder> cache = new ArrayList<StringBuilder>();
-        final String ARRAY_START_MARK = "${{";
-        final String ARRAY_END_MARK = "}}";
-        final String ARRAY_SEPARATOR = ":";
-        final String START_MARK = "${"; //$NON-NLS-1$
-        final String END_MARK = "}"; //$NON-NLS-1$
-        // Check for array's first, for every array, we must clone and create
-        // a new string, with the array substituted.  If there are multiple
-        // arrays, then we must clone for each.
-        // It would be more efficient to use a pattern match to avoid
-        // mutiple processing.
-        Collection<Key> keys = getKeys(p, s, ARRAY_START_MARK, ARRAY_END_MARK);
-        Iterator<Key> i = keys.iterator();
-        int uniqueStrings = 1;
-        while (i.hasNext()){
-            Key k = i.next();
-            while (k != null){
-                short valueCount = k.valueCount(ARRAY_SEPARATOR);
-                uniqueStrings = valueCount * uniqueStrings;
-            }
-        }
-        if ( uniqueStrings < 0 ) throw new IllegalStateException("integer overflow");
-        Collection<String> result = new ArrayList<String>(uniqueStrings);
-        // Now we must replace each key with a value such that we have
-        // X unique stings where:
-        // X = key1.valueCount() * key2.valueCount() ... * keyn.valueCount()
-        Key[] keyArray = keys.toArray(new Key[keys.size()]);
-        StringBuilder sb = new StringBuilder(); // Key builder
-        int lastKey = keyArray.length;
-        for ( int u = 0; u < uniqueStrings ; u++ ){
-            if ( lastKey > 1){
-                for ( int k = 0; k < lastKey; k++ ){
-                    if (keyArray[k] == null) continue;
-                    // Key builder (for building keys) we use for matching.
-                    sb.append(ARRAY_START_MARK)
-                        .append(keyArray[k].toString())
-                        .append(ARRAY_END_MARK);
-                    String primaryKey = sb.toString();
-                    sb.delete(0, sb.length()); // Clear the builder for next use.
-                    Collection<String> values = 
-                            keyArray[k].expandValues(ARRAY_SEPARATOR);
-                    String[] value = values.toArray(new String[values.size()]);
-                    int lastValue = value.length;
-                    for ( int v = 0; v < lastValue; v++ ){
-                        if (value[v] == null) continue;
-                        // Now replace all keys in the string with a value.
-                        // for the primary key's value, do this until we have 
-                        // exhausted the other key's values.
-                        // Add each new string to the cache.
-                        StringBuilder line = new StringBuilder(64 + s.length()); //extra space for values.
-                        boolean primaryKeyIsReplaced = false;
-                        line.append(s);
-                        for ( int kN = 0; kN < lastKey; kN++){
-                            if ( kN == k || keyArray[kN] == null ) continue; // ignore self.
-                            sb.append(ARRAY_START_MARK)
-                                .append(keyArray[kN].toString())
-                                .append(ARRAY_END_MARK);
-                            String secondaryKey = sb.toString();
-                            sb.delete(0, sb.length()); // Clear the builder for next use.
-                            // We are now ready to create our unique string.
-                            // each key value must be combined with each
-                            // value from each other key.
-                            Iterator<String> kNvalues = keyArray[kN]
-                                    .expandValues(ARRAY_SEPARATOR).iterator();
-                            while (kNvalues.hasNext()){
-                                // In all honesty, we have a problem now if
-                                // there is more than one identical key, how
-                                // do we ensure we replace only the correct
-                                // position in the string?
-                                // Ans: Replace them in order of occurance in the
-                                // key array.
-                                if (k < kN){ // replace k first.
-                                    // We must create a new line for every
-                                    // value. the above iterator won't work.
-                                } else { // replace kN first.
-                                    
-                                }
-                            }
-                        }
-                    }
-                }
-            }         
-        }
 
-        return result;
-    }
     
  
-    protected static Collection<String> expandStringValues(String value, String separator){
-        Collection<String> result = new ArrayList<String>();
-        StringBuilder b = new StringBuilder(value);
-        int sep = b.indexOf(separator);
-        final int start = 0;
-        while (sep > 0){
-            String sub = b.substring(start, sep + 1);
-            b.delete(start, sep +1);
-            sep = b.indexOf(separator);
-            result.add(sub);
-        }
-        return result;
-    }
-    
-    protected final Collection<Key> getKeys(Properties p, String keys, 
-            String START_MARK, String END_MARK)
-    {
-        Collection<Key> result = new ArrayList<Key>();
-        final int START_OFFSET = START_MARK.length();
-        final int END_OFFSET = END_MARK.length();
-        int start = keys.indexOf(START_MARK);
-        while (start >= 0){
-            int end = keys.indexOf(END_MARK, start);
-            if (end >= 0) {
-                String key = (keys.substring(start + START_OFFSET, end));
-                result.add(new Key(p,key));
-                start = keys.indexOf(START_MARK, end + END_OFFSET);
-            }
-        }
-        return result;
-    }
-    
-    
-//    protected final String getNextKey(String s, String START_MARK,
-//            String END_MARK, int from)
-//    {
-//        final int START_OFFSET = START_MARK.length();
-//        int start = s.indexOf(START_MARK, from);
-//        if (start >= 0){
-//            int end = s.indexOf(END_MARK , start + START_OFFSET);
-//            if (end >= 0) {
-//                String key = s.substring(start + START_OFFSET, end);
-//                return key;
-//            }
-//        }
-//        return "";
-//    }    
     
-    /*
-     * A string is made up of string segments and key's, if we create an array
-     * which has string segments and keys represented by array elements, we
-     * can use a string builder for every possible combination and simply build
-     * each possible combination.  Also by finding the array key's first, 
-     * we can then find simpler key's that don't contain arrays in the segment
-     * and replace those immediately.
-     * 
-     * The array key's 
-     */
-    public final static class Key {
-        
-        public static final Key nullKey = new Key();
-        private final String key;
-        private final String value;
-        private Collection<String> values;
-        private String separator;
-        
-        public Key(Properties p, String key){
-            this.key = key;
-            String v = p.getProperty(key);
-            value = v == null ? "" : v;
-            values = null;
-            separator = null;
-        }
-        
-        private Key(){
-            key = "";
-            value = "";
-        }
-        
-        public final String getValue(){
-            return value;
-        }
-        
-        public short valueCount(String separator){
-            short result;
-            if (values != null 
-                && this.separator != null 
-                && this.separator.equals(separator)
-               ) result = (short) values.size();
-            values = expandStringValues(value, separator);
-            result = (short) values.size();
-            if (result < 0) throw new IllegalStateException("short overflow");
-            return result;
-        }
-        
-        public Collection<String> expandValues(String separator){
-            if (values != null 
-                && this.separator != null 
-                && this.separator.equals(separator)
-               ) return values;            
-            values = expandStringValues(value, separator);
-            return values;
-        }
-        
-        @Override
-        public final String toString(){
-            return key;
-        }
-        
-        public final boolean isNull(){
-            if (key.isEmpty()) return true;
-            return false;
-        }
-    }
+ 
+
 
     /**
      * Compound token representing <i>keystore </i> clause. See policy format
@@ -646,6 +423,17 @@ public class DefaultPolicyScanner {
          * The typename part of keystore clause.
          */
         public String type;
+        
+        public String toString(){
+            String newline = "\n";
+            int l = url == null? 0 : url.length();
+            l = l + type == null? 0 : type.length();
+            l = l + 4;
+            StringBuffer sb = new StringBuffer(l);
+            if ( url != null ) sb.append(url).append(newline);
+            if ( type != null ) sb.append(type).append(newline);
+            return sb.toString();
+        }
     }
 
     /**
@@ -683,6 +471,17 @@ public class DefaultPolicyScanner {
          * Collection of PermissionEntries of grant clause.
          */
         private Collection<PermissionEntry> permissions;
+        
+        public String toString(){
+            String newline = "\n";
+            StringBuffer sb = new StringBuffer(400);
+            if (signers != null ) sb.append(signers).append(newline);
+            if (codebase != null ) sb.append(codebase).append(newline);
+            if (codebases != null ) sb.append(codebases).append(newline);
+            if (principals != null ) sb.append(principals).append(newline);
+            if (permissions != null ) sb.append(permissions).append(newline);
+            return sb.toString();
+        }
 
         /**
          * Adds specified element to the <code>principals</code> collection.
@@ -717,7 +516,8 @@ public class DefaultPolicyScanner {
             try {
                 return PolicyUtils.expand(codebase, system);
             } catch (ExpansionFailedException ex) {
-                Logger.getLogger(DefaultPolicyScanner.class.getName()).log(Level.SEVERE, null, ex);
+//                Logger.getLogger(DefaultPolicyScanner.class.getName()).log(Level.SEVERE, null, ex);
+                ex.printStackTrace(System.err);
                 return codebase;
             }
         }
@@ -731,16 +531,6 @@ public class DefaultPolicyScanner {
         }
 
         /**
-         * Check this first?  Or just get this and iterate?
-         * @return the codebases
-         */
-        public Collection<String> getCodebases(Properties system) {
-            
-            
-            return codebases;
-        }
-
-        /**
          * @return the principals
          */
         public Collection<PrincipalEntry> getPrincipals(Properties system) {
@@ -796,6 +586,17 @@ public class DefaultPolicyScanner {
          * The name part of principal clause.
          */
         public String name;
+        
+        public String toString(){
+            String newline = "\n";
+            int l = klass == null? 0 : klass.length();
+            l = l + name == null? 0 : name.length();
+            l = l + 4;
+            StringBuffer sb = new StringBuffer(l);
+            if ( klass != null ) sb.append(klass).append(newline);
+            if ( name != null ) sb.append(name).append(newline);
+            return sb.toString();
+        }
     }
 
     /**
@@ -828,5 +629,20 @@ public class DefaultPolicyScanner {
          * of certificate aliases.
          */
         public String signers;
+        
+        public String toString(){
+            String endline = "\n";
+            int l = klass == null ? 0 : klass.length();
+            l = l + name == null? 0 : name.length();
+            l = l + actions == null? 0 : actions.length();
+            l = l + signers == null? 0 : signers.length();
+            l = l + 8;
+            StringBuffer sb = new StringBuffer(l);
+            if ( klass != null ) sb.append(klass).append(endline);
+            if ( name != null ) sb.append(name).append(endline);
+            if ( actions != null ) sb.append(actions).append(endline);
+            if ( signers != null ) sb.append(signers).append(endline);
+            return sb.toString();
+        }
     }
 }

Modified: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/NullPolicyParser.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/NullPolicyParser.java?rev=1220916&r1=1220915&r2=1220916&view=diff
==============================================================================
--- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/NullPolicyParser.java (original)
+++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/NullPolicyParser.java Mon Dec 19 19:42:37 2011
@@ -1,6 +1,20 @@
 /*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
+ * 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.impl.security.policy.util;

Modified: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/PolicyParser.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/PolicyParser.java?rev=1220916&r1=1220915&r2=1220916&view=diff
==============================================================================
--- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/PolicyParser.java (original)
+++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/PolicyParser.java Mon Dec 19 19:42:37 2011
@@ -24,7 +24,8 @@ import java.util.Properties;
 import org.apache.river.api.security.PermissionGrant;
 
 /**
- * Based on the Apache Harmony interface of the same name.
+ * Based on the Apache Harmony interface of the same name, although not compatible.
+ * 
  * @author Peter Firmstone
  */
 public interface PolicyParser {

Modified: river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/PolicyUtils.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/PolicyUtils.java?rev=1220916&r1=1220915&r2=1220916&view=diff
==============================================================================
--- river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/PolicyUtils.java (original)
+++ river/jtsk/skunk/peterConcurrentPolicy/src/org/apache/river/impl/security/policy/util/PolicyUtils.java Mon Dec 19 19:42:37 2011
@@ -484,6 +484,7 @@ public class PolicyUtils {
      */
     public static PermissionCollection 
             asConcurrent(PermissionCollection perms) {
+        if (perms instanceof ConcurrentPermissions ) return perms;
         PermissionCollection pc = new ConcurrentPermissions();
 	if ( perms != null){
 	    Enumeration<Permission> iter = perms.elements();