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 2013/03/14 13:13:49 UTC

svn commit: r1456399 [1/2] - in /river/jtsk/skunk/qa_refactor/trunk: ./ qa/src/com/sun/jini/qa/harness/ qa/src/com/sun/jini/test/resources/ src-doc/static/ src/com/sun/jini/jeri/internal/mux/ src/com/sun/jini/start/ src/net/jini/discovery/ src/net/jini...

Author: peter_firmstone
Date: Thu Mar 14 12:13:47 2013
New Revision: 1456399

URL: http://svn.apache.org/r1456399
Log:
Clean up new API, removed some methods and classes.   Tidy up documentation in preparation for release.

Added:
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/common/
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/common/Beta.java
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/package.html
      - copied, changed from r1455024, river/jtsk/skunk/qa_refactor/trunk/src/net/jini/io/package.html
Removed:
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/CodeSourceGrant.java
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/CodeSourceSetGrant.java
    river/jtsk/skunk/qa_refactor/trunk/test/src/org/apache/river/api/security/CodeSourceGrantTest.java
    river/jtsk/skunk/qa_refactor/trunk/test/src/org/apache/river/api/security/PermissionGrantTest.java
Modified:
    river/jtsk/skunk/qa_refactor/trunk/build.xml
    river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/qa/harness/MergedPolicyProvider.java
    river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/resources/qa1.logging
    river/jtsk/skunk/qa_refactor/trunk/src-doc/static/manpages-index.html
    river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/jeri/internal/mux/Mux.java
    river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/start/AggregatePolicyProvider.java
    river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/LookupDiscovery.java
    river/jtsk/skunk/qa_refactor/trunk/src/net/jini/jeri/connection/ConnectionManager.java
    river/jtsk/skunk/qa_refactor/trunk/src/net/jini/lookup/ServiceDiscoveryManager.java
    river/jtsk/skunk/qa_refactor/trunk/src/net/jini/security/Security.java
    river/jtsk/skunk/qa_refactor/trunk/src/net/jini/security/policy/DynamicPolicyProvider.java
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/SerialReflectionFactory.java
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/AbstractPolicy.java
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/CertificateGrant.java
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/ConcurrentPolicyFile.java
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/DefaultPolicyParser.java
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PermissionComparator.java
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PermissionGrant.java
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PermissionGrantBuilder.java
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PermissionGrantBuilderImp.java
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PolicyParser.java
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PrincipalGrant.java
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/RemotePolicy.java
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/RemotePolicyProvider.java
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/ScalableNestedPolicy.java
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/SubjectDomain.java
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/URIGrant.java
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/util/Facade.java
    river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/util/ResultStream.java
    river/jtsk/skunk/qa_refactor/trunk/test/src/org/apache/river/api/security/ConcurrentPolicyFileTest.java
    river/jtsk/skunk/qa_refactor/trunk/test/src/org/apache/river/api/security/PolicyEntryTest.java

Modified: river/jtsk/skunk/qa_refactor/trunk/build.xml
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/build.xml?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/build.xml (original)
+++ river/jtsk/skunk/qa_refactor/trunk/build.xml Thu Mar 14 12:13:47 2013
@@ -368,6 +368,7 @@
             <package name="net.jini.url.file"/>
             <package name="net.jini.url.httpmd"/>
             <package name="net.jini.url.https"/>
+            <package name="org.apache.river.api.io"/>
             <package name="org.apache.river.api.lookup"/>
             <package name="org.apache.river.api.security"/>
             <package name="org.apache.river.api.util"/>

Modified: river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/qa/harness/MergedPolicyProvider.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/qa/harness/MergedPolicyProvider.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/qa/harness/MergedPolicyProvider.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/qa/harness/MergedPolicyProvider.java Thu Mar 14 12:13:47 2013
@@ -181,14 +181,15 @@ public class MergedPolicyProvider extend
 	}
     }
 
-    public Collection<PermissionGrant> getPermissionGrants(ProtectionDomain domain) {
+    public List<PermissionGrant> getPermissionGrants(ProtectionDomain domain) {
         if (policies.isEmpty()) throw new IllegalStateException("No policies in provider");
-        Collection<PermissionGrant> perms = null;
+        List<PermissionGrant> perms = null;
         Iterator<Policy> it = policies.iterator();
         while (it.hasNext()){
             Policy p = it.next();
             if (p instanceof ScalableNestedPolicy){
-                Collection<PermissionGrant> g = ((ScalableNestedPolicy)p).getPermissionGrants(domain);
+                List<PermissionGrant> g = ((ScalableNestedPolicy)p).getPermissionGrants(domain);
+                if ( !g.isEmpty() && g.get(0).isPrivileged()) return g;
                 if (perms == null) {
                     perms = g;
                 } else {
@@ -196,7 +197,13 @@ public class MergedPolicyProvider extend
                 }
             } else {
                 if (perms == null ) perms = new LinkedList<PermissionGrant>();
-                perms.add(extractGrantFromPolicy(p, domain));
+                PermissionGrant pg = extractGrantFromPolicy(p, domain);
+                if (pg.isPrivileged()){
+                    perms.clear();
+                    perms.add(pg);
+                    return perms;
+                }
+                perms.add(pg);
             }
         }
         return perms;

Modified: river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/resources/qa1.logging
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/resources/qa1.logging?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/resources/qa1.logging (original)
+++ river/jtsk/skunk/qa_refactor/trunk/qa/src/com/sun/jini/test/resources/qa1.logging Thu Mar 14 12:13:47 2013
@@ -104,10 +104,10 @@ java.util.logging.FileHandler.level = IN
 #  FINEST (lowest value) 
 
 # For Everything
-sun.rmi.level = FINE
-net.jini.level = FINE
-org.apache.river.level = FINE
-com.sun.jini.level = FINE
+sun.rmi.level = INFO
+net.jini.level = INFO
+org.apache.river.level = INFO
+com.sun.jini.level = INFO
 
 # For the LogManager
 com.sun.jini.logging.LogManager.level = INFO

Modified: river/jtsk/skunk/qa_refactor/trunk/src-doc/static/manpages-index.html
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src-doc/static/manpages-index.html?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src-doc/static/manpages-index.html (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src-doc/static/manpages-index.html Thu Mar 14 12:13:47 2013
@@ -50,14 +50,12 @@ specifics for services, utilities, and t
 
 	<li><a href="api/com/sun/jini/outrigger/package-summary.html">
         Outrigger</a> - a JavaSpaces service implementation.
-        
-        <li><a href="http://www.rio-project.org">Rio</a> - 
 
 	<li><a href="api/com/sun/jini/phoenix/package-summary.html">
 	Phoenix</a> - a configurable Java RMI activation system daemon
 
 	<li><a href="api/com/sun/jini/reggie/package-summary.html">
-	Reggie</a> - a River lookup service
+	Reggie</a> - a Jini lookup service
 
 
 <p>
@@ -95,7 +93,17 @@ specifics for services, utilities, and t
 </ul><a name="infrastructure"></a>
 <H2>Infrastructure</H2>
 <ul>
-    
+<li><a href="api/org/apache/river/api/security/package-summary.html">Apache River's
+        Security Extensions</a>
+<li><a href="api/org/apache/river/api/io/package-summary.html">Distributed objects</a>
+    - an extension of the Serialization protocol, Distributed objects are themselves
+    not Serialized, instead only instructions for recreating an object remotely 
+    using reflection are marshalled.  This allows Distributed objects to utilised
+    public api methods for construction, avoid publishing their internal state 
+    and to be immutable and safely constructed with invariants checked or 
+    defensively copied using final fields.
+<li><a href="api/org/apache/river/api/lookup/package-summary.html">A next 
+        generation lookup service API.</a>
 <p>
 </ul><a name="tools"></a>
 <H2>Tools</H2>

Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/jeri/internal/mux/Mux.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/jeri/internal/mux/Mux.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/jeri/internal/mux/Mux.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/jeri/internal/mux/Mux.java Thu Mar 14 12:13:47 2013
@@ -139,7 +139,7 @@ abstract class Mux {
     private int expectedPingCookie = -1;
     
     /** unguarded instance state */
-    private volatile long startTimeout = 30000; // milliseconds
+    private volatile long startTimeout = 15000; // milliseconds
 
     /**
      * Constructs a new Mux instance for a connection accessible through

Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/start/AggregatePolicyProvider.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/start/AggregatePolicyProvider.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/start/AggregatePolicyProvider.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/start/AggregatePolicyProvider.java Thu Mar 14 12:13:47 2013
@@ -38,6 +38,7 @@ import java.security.Security;
 import java.security.SecurityPermission;
 import java.util.Collection;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 import java.util.WeakHashMap;
 import java.util.concurrent.ConcurrentHashMap;
@@ -237,12 +238,12 @@ public class AggregatePolicyProvider 
 	getCurrentSubPolicy().refresh();
     }
 
-    public Collection<PermissionGrant> getPermissionGrants(ProtectionDomain domain) {
+    public List<PermissionGrant> getPermissionGrants(ProtectionDomain domain) {
         Policy p = getCurrentSubPolicy();
         if (p instanceof ScalableNestedPolicy){
             return ((ScalableNestedPolicy)p).getPermissionGrants(domain);
         } 
-        Collection<PermissionGrant> c = new LinkedList<PermissionGrant>();
+        List<PermissionGrant> c = new LinkedList<PermissionGrant>();
         c.add(extractGrantFromPolicy(p,domain));
         return c;
     }

Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/LookupDiscovery.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/LookupDiscovery.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/LookupDiscovery.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/LookupDiscovery.java Thu Mar 14 12:13:47 2013
@@ -1989,17 +1989,7 @@ public class LookupDiscovery implements 
 	rawUnicastDiscoveryConstraints = 
 	    constraints.getConstraints(
 		DiscoveryConstraints.unicastDiscoveryMethod);
-
-//        /* Task manager */
-//        TaskManager taskManager;
-//        try {
-//            taskManager = (TaskManager)config.getEntry(COMPONENT_NAME,
-//						       "taskManager",
-//						       TaskManager.class);
-//        } catch(NoSuchEntryException e) { /* use default */
-//            taskManager = new TaskManager(MAX_N_TASKS,(15*1000),1.0f);
-//        }
-        
+  
         /* ExecutorService */
         ExecutorService executorServ;
         try {
@@ -2135,7 +2125,7 @@ public class LookupDiscovery implements 
             return;
         } 
         
-        /* Start threads */
+        /* threads */
         
 	try {
             announcementTimerThread  = Security.doPrivileged(new PrivilegedExceptionAction<AnnouncementTimerThread>() {
@@ -2160,11 +2150,27 @@ public class LookupDiscovery implements 
 	}
 	if (!all_groups || !this.groups.isEmpty()) {
             requestGroups(this.groups);
-        }//endif
-	announceeThread.start();
-	announcementTimerThread.start();
-        notifierThread.start();
+        }//end if
     }//end constructor
+    
+    /* sync on registars */
+    private boolean started = false;
+    
+    /**
+     * In previous releases threads were started in the constructor, however
+     * this violates safe construction according to the JMM.
+     * 
+     * @since 2.2.1
+     */
+    public void start(){
+        synchronized (registrars){
+            if (started) return;
+            announceeThread.start();
+            announcementTimerThread.start();
+            notifierThread.start();
+            started = true;
+        }
+    }
 
     /**
      * Register a listener as interested in receiving DiscoveryEvent
@@ -2191,6 +2197,7 @@ public class LookupDiscovery implements 
             if (terminated) {
                 throw new IllegalStateException("discovery terminated");
             }
+            if (!started) start();
 	    if (listeners.indexOf(l) >= 0) return; //already have this listener
 	    listeners.add(l);
 	    if (registrars.isEmpty()) return;//nothing to send the new listener

Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/jeri/connection/ConnectionManager.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/jeri/connection/ConnectionManager.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/jeri/connection/ConnectionManager.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/jeri/connection/ConnectionManager.java Thu Mar 14 12:13:47 2013
@@ -104,11 +104,11 @@ import net.jini.jeri.OutboundRequestIter
  *
  * <li><code>com.sun.jini.jeri.connectionTimeout</code> - Time in
  * milliseconds to leave idle client-side connections around before
- * closing them. The default value is 30000 milliseconds (30 seconds).
+ * closing them. The default value is 15000 milliseconds (15 seconds).
  *
  * <li><code>com.sun.jini.jeri.handshakeTimeout</code> - Time in
  * milliseconds for client-side connections to wait for the server to
- * acknowledge an opening handshake. The default value is 30000 milliseconds (30 seconds).
+ * acknowledge an opening handshake. The default value is 15000 milliseconds (15 seconds).
  *
  * </ul>
  **/
@@ -119,14 +119,14 @@ public final class ConnectionManager {
     private static final long TIMEOUT =
 	( (Long) AccessController.doPrivileged(new GetLongAction(
 		"com.sun.jini.jeri.connectionTimeout", 
-		30000))).longValue();
+		15000))).longValue();
     /**
      * How long to wait for a server to respond to an initial client message.
      */
     private static final long HANDSHAKE_TIMEOUT =
 	((Long) AccessController.doPrivileged(new GetLongAction(
 		"com.sun.jini.jeri.handshakeTimeout", 
-		30000))).longValue();
+		15000))).longValue();
     /**
      * ConnectionManager logger.
      */

Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/lookup/ServiceDiscoveryManager.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/lookup/ServiceDiscoveryManager.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/lookup/ServiceDiscoveryManager.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/lookup/ServiceDiscoveryManager.java Thu Mar 14 12:13:47 2013
@@ -606,8 +606,8 @@ public class ServiceDiscoveryManager {
 
     /** Class for implementing register/lookup/notify/dropProxy/discard tasks*/
     private static abstract class CacheTask implements TaskManager.Task {
-        protected ProxyReg reg;
-        protected long thisTaskSeqN;
+        protected final ProxyReg reg;
+        protected volatile long thisTaskSeqN;
         public CacheTask(ProxyReg reg, long seqN) {
             this.reg = reg;
             this.thisTaskSeqN = seqN;
@@ -644,7 +644,7 @@ public class ServiceDiscoveryManager {
      *  lookup service.
      */
     private static abstract class ServiceIdTask extends CacheTask {
-        protected ServiceID thisTaskSid;
+        protected final ServiceID thisTaskSid;
         ServiceIdTask(ServiceID srvcId, ProxyReg reg, long seqN) {
             super(reg, seqN);
             this.thisTaskSid = srvcId;
@@ -832,7 +832,7 @@ public class ServiceDiscoveryManager {
 
     /** The Listener class for the LeaseRenewalManager. */
     private final class LeaseListenerImpl implements LeaseListener {
-	private ServiceRegistrar proxy;
+	private final ServiceRegistrar proxy;
 	public LeaseListenerImpl(ServiceRegistrar proxy) {
 	    this.proxy = proxy;
 	}
@@ -948,7 +948,7 @@ public class ServiceDiscoveryManager {
 
 	/** This class requests a "snapshot" of the given registrar's state.*/
         private final class LookupTask extends CacheTask {
-	    private EventReg eReg;
+	    private final EventReg eReg;
             public LookupTask(ProxyReg reg, long seqN, EventReg eReg) {
                 super(reg, seqN);
 		this.eReg = eReg;
@@ -1117,9 +1117,9 @@ public class ServiceDiscoveryManager {
          *  events.
          */
         private final class NotifyEventTask extends ServiceIdTask {
-	    private ServiceID sid;
-	    private ServiceItem item;
-	    private int transition;
+	    private final ServiceID sid;
+	    private final ServiceItem item;
+	    private final int transition;
 	    public NotifyEventTask(ProxyReg reg,
 				   ServiceID sid,
 				   ServiceItem item,
@@ -1382,8 +1382,8 @@ public class ServiceDiscoveryManager {
          *           send NO removed event
          */
         private final class NewOldServiceTask extends ServiceIdTask {
-            private ServiceItem srvcItem;
-            private boolean matchMatchEvent;
+            private final ServiceItem srvcItem;
+            private final boolean matchMatchEvent;
             public NewOldServiceTask(ProxyReg reg,
                                      ServiceItem item,
                                      boolean matchMatchEvent,
@@ -1461,7 +1461,7 @@ public class ServiceDiscoveryManager {
          *  service.
          */
         private final class UnmapProxyTask extends ServiceIdTask {
-            private ServiceItemReg itemReg;
+            private final ServiceItemReg itemReg;
             public UnmapProxyTask(ProxyReg       reg,
                                   ServiceItemReg itemReg,
                                   ServiceID      srvcId,
@@ -1519,7 +1519,7 @@ public class ServiceDiscoveryManager {
 	/* Filter current cache instance should use for secondary matching */
 	private ServiceItemFilter filter = null;
 	/* Desired lease duration to request from lookups' event mechanisms */
-	private long leaseDuration;
+	private final long leaseDuration;
 	/* Log the time when the cache gets created. This value is used to
          * calculate the time when the cache should expire.
 	 */

Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/security/Security.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/security/Security.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/security/Security.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/security/Security.java Thu Mar 14 12:13:47 2013
@@ -1198,7 +1198,8 @@ public final class Security {
     
         private DistributedSubjectCombiner(Subject subject){
             super(subject);
-            if (subject == null) throw new NullPointerException("subject cannot be null");
+            // Don't throw exception in constructor, check subject before calling constructor.
+//            if (subject == null) throw new NullPointerException("subject cannot be null");
             this.subject = subject;
         }
         
@@ -1252,6 +1253,10 @@ public final class Security {
         private final static CodeSource nullCS = new CodeSource(null, (Certificate[]) null);
         private final Subject subject;
         
+        /** 
+         * Visibility of Subject and it's principal set is guaranteed by final 
+         * reference and safe construction of this object. 
+         */
         private SubjectProtectionDomain(Subject subject){
             super(nullCS, new Permissions(), null, (Principal[]) subject.getPrincipals().toArray());
             this.subject = subject;

Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/security/policy/DynamicPolicyProvider.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/security/policy/DynamicPolicyProvider.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/security/policy/DynamicPolicyProvider.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/security/policy/DynamicPolicyProvider.java Thu Mar 14 12:13:47 2013
@@ -40,6 +40,7 @@ import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.NavigableSet;
 import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
@@ -68,7 +69,7 @@ import org.apache.river.api.security.Rev
  * 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, a Policy can only relax security
+ * can only augment policy files; a Policy can only relax security
  * by granting additional permissions, this implementation adds an experimental 
  * feature for revoking permissions, however there are some caveats:</p>
  * 
@@ -120,7 +121,7 @@ import org.apache.river.api.security.Rev
  * all other Permission's using dynamic grants. 
  *
  * </p><p>
- * To make the best utilisation of this Policy provider, set the System property:
+ * The underlying policy provider may be set using the System property:
  * </p>,<p>
  * net.jini.security.policy.PolicyFileProvider.basePolicyClass = 
  * org.apache.river.security.concurrent.ConcurrentPolicyFile
@@ -357,9 +358,12 @@ Put the policy providers and all referen
     @Override
     public boolean implies(ProtectionDomain domain, Permission permission) {
         if (domain == policyDomain) return policyPermissions.implies(permission);
-        if (basePolicyIsDynamic || basePolicyIsRemote){
-            if (basePolicy.implies(domain, permission)) return true;
-        }
+        // There's not much point to this check anymore, besides, it could allow 
+        // a less privileged domain in an underlying policy to be checked
+        // prior to a privileged domain in this policy.
+//        if (basePolicyIsDynamic || basePolicyIsRemote){
+//            if (basePolicy.implies(domain, permission)) return true;
+//        }
 	if (permission == null) throw new NullPointerException("permission not allowed to be null");
         /* If com.sun.security.provider.PolicyFile:
          * Do not call implies on the base Policy, if
@@ -407,15 +411,22 @@ Put the policy providers and all referen
                 }
             }
         }else{
-            Collection<PermissionGrant> grants = ((ScalableNestedPolicy) basePolicy).getPermissionGrants(domain);
-            processGrants(grants, permClass, true, permissions);
-            if (permissions.contains(ALL_PERMISSION)) return true;
+            List<PermissionGrant> grants = ((ScalableNestedPolicy) basePolicy).getPermissionGrants(domain);
+            if ( !grants.isEmpty() && grants.get(0).isPrivileged()) return true;
+            processGrants(grants, permClass, false, permissions);
         }
         Iterator<PermissionGrant> grants = dynamicPolicyGrants.iterator();
+        // Check the privileged case first.
+        while (grants.hasNext()){
+            PermissionGrant g = grants.next();
+            if (g.isPrivileged() && g.implies(domain)) return true;
+        }
+        grants = dynamicPolicyGrants.iterator();
         while (grants.hasNext()){
             PermissionGrant g = grants.next();
-            if (g.implies(domain)){
+            if (!g.isPrivileged() && g.implies(domain)){
                 Collection<Permission> perms = g.getPermissions();
+                // But we only want to add relevant Permissions.
                 Iterator<Permission> it = perms.iterator();
                 while (it.hasNext()){
                     Permission p = it.next();
@@ -532,17 +543,34 @@ Put the policy providers and all referen
         return perms;
     }
 
-    public Collection<PermissionGrant> getPermissionGrants(ProtectionDomain domain) {
-        Collection<PermissionGrant> grants = null;
+    public List<PermissionGrant> getPermissionGrants(ProtectionDomain domain) {
+        List<PermissionGrant> grants = null;
         if (basePolicy instanceof ScalableNestedPolicy){
             grants = ((ScalableNestedPolicy)basePolicy).getPermissionGrants(domain);
+            if ( !grants.isEmpty() && grants.get(0).isPrivileged()) return grants;
         } else {
             grants = new LinkedList<PermissionGrant>();
-            grants.add(extractGrantFromPolicy(basePolicy, domain));
+            PermissionGrant pg = extractGrantFromPolicy(basePolicy, domain);
+            grants.add(pg);
+            if (pg.isPrivileged()) return grants;
         }
         Iterator<PermissionGrant> it = dynamicPolicyGrants.iterator();
         while (it.hasNext()){
-            grants.add(it.next());
+            PermissionGrant pg = it.next();
+            /* Check privileged first */
+            if (pg.isPrivileged() && pg.implies(domain)){
+                grants.clear();
+                grants.add(pg);
+                return grants;
+            }
+        }
+        it = dynamicPolicyGrants.iterator();
+        while (it.hasNext()){
+            PermissionGrant pg = it.next();
+            /* Then check less privileged domains*/
+            if ( !pg.isPrivileged() && pg.implies(domain)){
+                grants.add(pg);
+            }
         }
         return grants;
     }

Added: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/common/Beta.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/common/Beta.java?rev=1456399&view=auto
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/common/Beta.java (added)
+++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/common/Beta.java Thu Mar 14 12:13:47 2013
@@ -0,0 +1,39 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.river.api.common;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to indicate the annotated element is subject to change
+ * in behaviour, definition, removal.
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target({
+    ElementType.ANNOTATION_TYPE,
+    ElementType.CONSTRUCTOR,
+    ElementType.FIELD,
+    ElementType.METHOD,
+    ElementType.TYPE})
+@Documented
+public @interface Beta {
+}
\ No newline at end of file

Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/SerialReflectionFactory.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/SerialReflectionFactory.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/SerialReflectionFactory.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/SerialReflectionFactory.java Thu Mar 14 12:13:47 2013
@@ -20,6 +20,7 @@ import java.io.Externalizable;
 import java.io.IOException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
+import java.io.Serializable;
 import java.io.StreamCorruptedException;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
@@ -34,22 +35,30 @@ import java.security.Guard;
  * 
  * Internal state is guarded, arrays are not defensively coped.
  * 
+ * This is compatible with Version 2 of the Java Serialization Protocol.
+ * 
  * @author Peter Firmstone.
  * @see Distributed
  * @see DistributePermission
+ * @see Serializable
+ * @see Externalizable
  */
 public final class SerialReflectionFactory implements Externalizable {
     private static final long serialVersionUID = 1L;
     /* Guard private state */
     private static final Guard distributable = new DistributePermission();
     
-    /* Minimal protocol to write primitives directly to stream.
+    /* Minimal protocol to write primitives directly to stream, only for parameters.
      * Strings are written as Objects, since they are a special case, identical
-     * strings are sent by reference not duplicates writes to stream.
-     * Class is also a special case, it also is not duplicated in streams.
+     * strings are sent by reference to the first and not duplicated.
+     * Class is also a special case, it too is not duplicated.
+     * 
+     * Primitives are written separately to objects, the first value written 
+     * to ObjectOutput is the length of the parameter array, each parameter is
+     * proceeded by a byte header indicating its type.  For null values, only the
+     * byte header is written to stream.
      * 
-     * Only primitives are written separately, the following indicates the 
-     * next parameter type in the stream.
+     * This protocol is fixed and cannot be changed after release.
      */
     private static final byte BOOLEAN = 0;
     private static final byte BYTE = 1;
@@ -62,7 +71,6 @@ public final class SerialReflectionFacto
     private static final byte OBJECT = 8;
     private static final byte NULL = 9;
     
-    
     private Object classOrObject;
     private String method;
     private Class [] parameterTypes;
@@ -102,6 +110,9 @@ public final class SerialReflectionFacto
      * Object versions of primitive parameters are writen to DataOutput
      * as primitives.
      * <p>
+     * Constructor parameters must either be Serializable, Externalizable or
+     * Distributed objects.
+     * <p>
      * 
      * @param factoryClassOrObject will be used for constructor, factory static method,
      * or builder Object.
@@ -157,6 +168,7 @@ public final class SerialReflectionFacto
         } 
     }
     
+    // Inherit documentation
     public void writeExternal(ObjectOutput out) throws IOException {
         distributable.checkGuard(null);
         out.writeObject(classOrObject);
@@ -197,6 +209,7 @@ public final class SerialReflectionFacto
         if (o instanceof Character){
             out.writeByte(CHAR);
             out.writeChar(((Character)o).charValue());
+            return;
         }
         if (o instanceof Short){
             out.writeByte(SHORT);
@@ -232,34 +245,49 @@ public final class SerialReflectionFacto
     private Object readObject(ObjectInput in) throws IOException, ClassNotFoundException{
         byte b = in.readByte();
         switch(b){
-            case 0: boolean bool = in.readBoolean();
-                    return Boolean.valueOf(bool);
-            case 1: byte bite = in.readByte();
-                    return Byte.valueOf(bite);
-            case 2: char ch = in.readChar();
-                    return Character.valueOf(ch);
-            case 3: short sh = in.readShort();
-                    return Short.valueOf(sh);
-            case 4: int i = in.readInt();
-                    return Integer.valueOf(i);
-            case 5: long l = in.readLong();
-                    return Long.valueOf(l);
-            case 6: float f = in.readFloat();
-                    return Float.valueOf(f);
-            case 7: double d = in.readDouble();
-                    return Double.valueOf(d);
-            case 8: return in.readObject();
-            case 9: return null;
-            default: throw new StreamCorruptedException("out of range byte read from stream");
+            case BOOLEAN:   boolean bool = in.readBoolean();
+                            return Boolean.valueOf(bool);
+                
+            case BYTE:      byte bite = in.readByte();
+                            return Byte.valueOf(bite);
+                
+            case CHAR:      char ch = in.readChar();
+                            return Character.valueOf(ch);
+                
+            case SHORT:     short sh = in.readShort();
+                            return Short.valueOf(sh);
+                
+            case INT:       int i = in.readInt();
+                            return Integer.valueOf(i);
+                
+            case LONG:      long l = in.readLong();
+                            return Long.valueOf(l);
+                
+            case FLOAT:     float f = in.readFloat();
+                            return Float.valueOf(f);
+                
+            case DOUBLE:    double d = in.readDouble();
+                            return Double.valueOf(d);
+                
+            case OBJECT:    return in.readObject();
+                
+            case NULL:      return null;
+                
+            default:        throw new StreamCorruptedException("out of range byte read from stream");
         }
         
     }
     
+    // Inherit documentation.
     public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        /* If created during deserialisation, we needn't be defensive, this
+         * will never be shared with other threads and will be replaced by
+         * a fully constructed thread safe immutable object. */
         if (constructed) throw new IllegalStateException("Object already constructed");
         /* Don't defensively copy arrays, the object is used immediately after
          * deserialization to construct the Distributed Object, the fields are
-         * not accessed again, it is up to creator methods to preserve invariants.
+         * not accessed again, it is up to creator methods themselves to 
+         * preserve invariants.
          */
         classOrObject = in.readObject();
         method = (String) in.readObject();

Copied: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/package.html (from r1455024, river/jtsk/skunk/qa_refactor/trunk/src/net/jini/io/package.html)
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/package.html?p2=river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/package.html&p1=river/jtsk/skunk/qa_refactor/trunk/src/net/jini/io/package.html&r1=1455024&r2=1456399&rev=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/io/package.html (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/io/package.html Thu Mar 14 12:13:47 2013
@@ -25,65 +25,39 @@
 
 Provides I/O interfaces and utility classes.
 
-<h2><code>ObjectStreamContext</code></h2>
+<h2><code>Distributed</code></h2>
 
-<p>The interface {@link net.jini.io.ObjectStreamContext} may be
-implemented by an object serialization stream class (a subclass of
-{@link java.io.ObjectOutputStream} or {@link
-java.io.ObjectInputStream}) to provide each object being serialized or
-deserialized with access to context information relevant to the
-overall serialization or deserialization operation.  The class of an
-object that is being serialized or deserialized can test (in its
-private <code>writeObject(ObjectOutputStream)</code> or
-<code>readObject(ObjectInputStream)</code> method) if the object
-stream being used is an instance of <code>ObjectStreamContext</code>.
-If the stream class does implement that interface, the class can then
-retrieve the context information (as a {@link java.util.Collection
-Collection} of context objects) by invoking the stream's
-<code>getObjectStreamContext</code> method.  The context information
-available from a given element of the collection is determined by that
-element's type.  Examples of types that a context object might
-implement include {@link net.jini.io.context.ClientHost} and {@link
-net.jini.io.context.ClientSubject}.
+<p>The interface {@link org.apache.river.api.io.Distributed} may be
+implemented by an object that is required to be immutable and thread safe
+immediately after un-marshalling, <code>Distributed</code> object's do not
+implement {@link java.io.Serializable}, their fields may be private and they 
+are created by a single reflective invocation of a public constructor, static
+method or <code>Serializable</code> object's builder method.
 
-<h2><code>MarshalOutputStream</code> and <code>MarshalInputStream</code></h2>
+<h2><code>DistributedObjectOutputStream</code> and <code>DistributedObjectInputStream</code></h2>
 
 <p>The classes {@link net.jini.io.MarshalOutputStream} and {@link
-net.jini.io.MarshalInputStream} extend the object serialization stream
-classes {@link java.io.ObjectOutputStream} and {@link
-java.io.ObjectInputStream} to implement the dynamic class loading
-semantics of RMI argument and result marshalling and unmarshalling.
-<code>MarshalOutputStream</code> and <code>MarshalInputStream</code>
-use {@link java.rmi.server.RMIClassLoader} to get class annotations
-for marshalling and to resolve codebase annotations to {@link
-java.lang.Class} objects for unmarshalling.
-<code>MarshalInputStream</code> supports optional verification that
-the codebase annotation URLs used to resolve classes provide content
-integrity (see {@link
-net.jini.security.Security#verifyCodebaseIntegrity
-Security.verifyCodebaseIntegrity}).  <code>MarshalOutputStream</code>
-and <code>MarshalInputStream</code> may be extended (in concert) to
-communicate class annotations in a way other than in the streams' own
-data.  Both <code>MarshalOutputStream</code> and
-<code>MarshalInputStream</code> implement
-<code>ObjectStreamContext</code>.
-
-<h2><code>MarshalledInstance</code></h2>
-
-<p>A {@link net.jini.io.MarshalledInstance} contains an object in
-serialized form.  A <code>MarshalledInstance</code> can be
-unmarshalled on demand, allowing an object to be sent in such a way
-that the receiver can control when and in what context the object is
-unmarshalled.  <code>MarshalledInstance</code> provides functionality
-similar to {@link java.rmi.MarshalledObject}, but it additionally
-supports use of object stream contexts and optional verification that
-the codebase annotation URLs used to resolve classes provide content
-integrity.  A convenience constructor and method are provided for
-converting between <code>MarshalledObject</code> and
-<code>MarshalledInstance</code> instances.
+net.jini.io.MarshalInputStream} extend the Distributed object serialization stream
+classes {@link org.apache.river.api.io.DistributedObjectOutputStream} and {@link
+org.apache.river.api.io.DistributeObjectInputStream} that implement replacement of
+{@link org.apache.river.api.io.Distributed} objects with 
+{@link org.apache.river.api.io.SerialReflectionFactory} during marshalling and
+substitution of <code>SerialReflectionFactory</code> with an object created by
+<code>SerialReflectionFactory</code>upon unmarshalling.
+
+<h2><code>SerialReflectionFactory</code></h2>
+
+<p>A {@link org.apache.river.api.io.SerialReflectionFactory} contains Externalized 
+instructions for creating an Object using reflection upon unmarshalling.
+
+<h2><code>DistributePermission</code></h2>
+
+<p>A {@link org.apache.river.api.io.DistributePermission} guards the 
+    {@link java.io.Externalizable#writeExternal} method of 
+    <code>SerialReflectionFactory</code>, preventing unauthorised marshalling.
 
-@since 2.0
-@version 2.0
+@since 2.2.1
+@version 2.2.1
 
 </body>
 </html>

Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/AbstractPolicy.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/AbstractPolicy.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/AbstractPolicy.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/AbstractPolicy.java Thu Mar 14 12:13:47 2013
@@ -205,6 +205,7 @@ public abstract class AbstractPolicy ext
             while (grants.hasNext()) {
                 PermissionGrant g = grants.next();
                 if (stopIfAll && g.isPrivileged()) {
+                    setToAddPerms.clear();
                     setToAddPerms.add(ALL_PERMISSION);
                     return;
                 }

Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/CertificateGrant.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/CertificateGrant.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/CertificateGrant.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/CertificateGrant.java Thu Mar 14 12:13:47 2013
@@ -93,10 +93,8 @@ class CertificateGrant extends Principal
         if (pd == null) return false; 
 	CodeSource c = null;
 	Principal[] pals = null;
-	if (pd != null){
-	    c = pd.getCodeSource();
-	    pals = getPrincipals(pd);
-	}
+        c = pd.getCodeSource();
+        pals = getPrincipals(pd);
 	return implies(c, pals);
     }
     

Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/ConcurrentPolicyFile.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/ConcurrentPolicyFile.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/ConcurrentPolicyFile.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/ConcurrentPolicyFile.java Thu Mar 14 12:13:47 2013
@@ -59,14 +59,14 @@ import net.jini.security.policy.PolicyIn
 
 /**
  * <p>
- * Concurrent Policy implementation based on policy configuration files,
+ * Concurrent Policy implementation based on policy configuration URL's,
  * it is intended to provide concurrent implies() for greatly improved
  * throughput.  Caching limits scalability and consumes shared memory,
  * so no cache exists.
  * </p><p>
  * By default all River Policy implementations now utilise ConcurrentPolicyFile.
  * </p>
- * This
+ * The default PolicyParser
  * implementation recognises text files, consisting of clauses with the
  * following syntax:
  * 
@@ -165,6 +165,13 @@ import net.jini.security.policy.PolicyIn
  * string, where <i>DN </i> is a certificate's subject distinguished name.
  * </dl>
  * <br>
+ * If there is sufficient interest, we can implement a DENY clause, 
+ * in this case DENY cannot apply to GRANT clauses that contain
+ * {@link java.security.AllPermission}, the domains to which a DENY clause
+ * would apply will be a less privileged domain.  For example a user could be
+ * granted SocketPermission("*", "connect"), while a DENY clause might
+ * list specific SocketPermission domains that are disallowed, where a DENY 
+ * clause has precedence over all GRANT clause Permissions except for AllPermission.
  * <br>
  * This implementation is thread-safe and scalable.
  * @author Peter Firmstone.
@@ -215,7 +222,10 @@ public class ConcurrentPolicyFile extend
     }
 
     /**
-     * Extension constructor for plugging-in a custom parser.
+     * Constructor to allow for custom policy providers, for example a database
+     * policy provider, can make administration simpler than traditional
+     * policy files.
+     * 
      * @param dpr
      * @param comp Comparator to compare permissions. 
      */
@@ -265,23 +275,23 @@ public class ConcurrentPolicyFile extend
         NavigableSet<Permission> perms = new TreeSet<Permission>(comparator);
         PermissionGrant [] grantRefCopy = grantArray;
         int l = grantRefCopy.length;
-        for ( int j =0; j < l; j++ ){
+        /* Check only privileged grants first, this allows privileged domains
+         * to avoid infinite recursion when they implement PermissionGrant
+         * and perform privileged actions during an implies call.
+         * 
+         * It also ensures privileged checks are are fast.
+         */ 
+        for ( int j = 0; j < l; j++){
             PermissionGrant ge = grantRefCopy[j];
-            if (ge.implies(pd)){
-                if (ge.isPrivileged()){// Don't stuff around finish early if you can.
+            if (ge.isPrivileged()){
+                if (ge.implies(pd)){
                     PermissionCollection pc = new Permissions();
-                    pc.add(new AllPermission());
+                    pc.add(ALL_PERMISSION);
                     return pc;
                 }
-                Collection<Permission> c = ge.getPermissions();
-                Iterator<Permission> i = c.iterator();
-                while (i.hasNext()){
-                    Permission p = i.next();
-                    perms.add(p);
-                }
             }
         }
-        // Don't forget to merge the static Permissions.
+        /* Merge  static Permissions and check for AllPermission */
         PermissionCollection staticPC = null;
         if (pd != null) {
             staticPC = pd.getPermissions();
@@ -297,7 +307,22 @@ public class ConcurrentPolicyFile extend
                     perms.add(p);
                 }
             }
+        }       
+        /* Now find less privileged cases */
+        for ( int j =0; j < l; j++ ){
+            PermissionGrant ge = grantRefCopy[j];
+            if (!ge.isPrivileged()){
+                if (ge.implies(pd)){
+                    Collection<Permission> c = ge.getPermissions();
+                    Iterator<Permission> i = c.iterator();
+                    while (i.hasNext()){
+                        Permission p = i.next();
+                        perms.add(p);
+                    }
+                }
+            }
         }
+        
         return convert(perms);
     }
 
@@ -317,8 +342,9 @@ public class ConcurrentPolicyFile extend
     public PermissionCollection getPermissions(CodeSource cs) {
         if (cs == null) throw new NullPointerException("CodeSource cannot be null");
         // for ProtectionDomain AllPermission optimisation.
+        /* Infinite recursion is not an issue for CodeSource */
         PermissionGrant [] grantRefCopy = grantArray;
-        int l = grantRefCopy.length;
+        int l = grantRefCopy.length;        
         for ( int j =0; j < l; j++ ){
             PermissionGrant ge = grantRefCopy[j];
             if (ge.implies(cs, null)){ // No Principal's
@@ -344,22 +370,17 @@ public class ConcurrentPolicyFile extend
         NavigableSet<Permission> perms = new TreeSet<Permission>(comparator);
         PermissionGrant [] grantRefCopy = grantArray;
         int l = grantRefCopy.length;
-        for ( int j =0; j < l; j++ ){
+        /* Check for privileged grants first to avoid recursion when 
+         * privileged domains become involved in policy decisions */
+        for (int j = 0; j < l; j++){
             PermissionGrant ge = grantRefCopy[j];
-            if (ge.implies(domain)){
-                if (ge.isPrivileged()) return true; // Don't stuff around finish early if you can.
-                Collection<Permission> c = ge.getPermissions();
-                Iterator<Permission> i = c.iterator();
-                while (i.hasNext()){
-                    Permission p = i.next();
-                    // Don't make it larger than necessary.
-                    if (klass.isInstance(permission) || permission instanceof UnresolvedPermission){
-                        perms.add(p);
-                    }
+            if (ge.isPrivileged()){
+                if (ge.implies(domain)){
+                    return true;
                 }
             }
         }
-        // Don't forget to merge the static Permissions.
+        /* Merge the static Permissions, check for Privileged */
         PermissionCollection staticPC = null;
         if (domain != null) {
             staticPC =domain.getPermissions();
@@ -369,13 +390,30 @@ public class ConcurrentPolicyFile extend
                     Permission p = e.nextElement();
                     // return early if possible.
                     if (p instanceof AllPermission ) return true;
-                    // Don't make it larger than necessary, but don't worry about duplicates either.
+                    // Only add relevant permissions to minimise size.
                     if (klass.isInstance(permission) || permission instanceof UnresolvedPermission){
                         perms.add(p);
                     }
                 }
             }
         }
+        /* Check less privileged grants */
+        for ( int j =0; j < l; j++ ){
+            PermissionGrant ge = grantRefCopy[j];
+            if (!ge.isPrivileged()){
+                if (ge.implies(domain)){
+                    Collection<Permission> c = ge.getPermissions();
+                    Iterator<Permission> i = c.iterator();
+                    while (i.hasNext()){
+                        Permission p = i.next();
+                        // Only add relevant permissions to minimise size.
+                        if (klass.isInstance(permission) || permission instanceof UnresolvedPermission){
+                            perms.add(p);
+                        }
+                    }
+                }
+            }
+        }      
         return convert(perms).implies(permission);
     }
 
@@ -439,16 +477,21 @@ public class ConcurrentPolicyFile extend
         }
     }
 
-    public Collection<PermissionGrant> getPermissionGrants(ProtectionDomain pd) {
+    public List<PermissionGrant> getPermissionGrants(ProtectionDomain pd) {
         PermissionGrant [] grants = grantArray; // copy volatile reference target.
         int l = grants.length;
         List<PermissionGrant> applicable = new LinkedList<PermissionGrant>();
-        for (int i =0; i < l; i++){
-            if (grants[i].implies(pd)){
-                applicable.add(grants[i]);
+        /* First check for privileged grants */
+        for (int i = 0; i < l; i++){
+            if (grants[i].isPrivileged()){
+                if (grants[i].implies(pd)){
+                    applicable.add(grants[i]);
+                    return applicable;
+                }
+                
             }
         }
-        // Merge any static permissions.
+        /* Merge static permissions and check for privileged */
         PermissionCollection pc = pd != null ? pd.getPermissions() : null;
         if (pc != null){
             PermissionGrantBuilder pgb = PermissionGrantBuilder.newBuilder();
@@ -457,17 +500,24 @@ public class ConcurrentPolicyFile extend
             Collection<Permission> perms = new LinkedList<Permission>();
             Enumeration<Permission> en = pc.elements();
             while (en.hasMoreElements()){
-                perms.add(en.nextElement());
+                Permission p = en.nextElement();
+                perms.add(p);
             }
             pgb.permissions(perms.toArray(new Permission[perms.size()]));
-            applicable.add(pgb.build());
-                        }
+            PermissionGrant pg = pgb.build();
+            applicable.add(pg);
+            // Return now if privileged, to avoid infinite recursion.
+            if (pg.isPrivileged()) return applicable;
+        }
+        /* Gather less privileged grants */
+        for (int i =0; i < l; i++){
+            if (!grants[i].isPrivileged()){
+                if (grants[i].implies(pd)){
+                    applicable.add(grants[i]);
+                }
+            }
+        }
+        
         return applicable;
     }
-    
-//    public Collection<PermissionGrant> getPermissionGrants(boolean recursive) {
-//        PermissionGrant [] grants = grantArray; // copy volatile reference target.
-//        return new LinkedList<PermissionGrant>(Arrays.asList(grants));
-//    }
-
 }

Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/DefaultPolicyParser.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/DefaultPolicyParser.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/DefaultPolicyParser.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/DefaultPolicyParser.java Thu Mar 14 12:13:47 2013
@@ -189,13 +189,6 @@ class DefaultPolicyParser implements Pol
     PermissionGrant resolveGrant(DefaultPolicyScanner.GrantEntry ge,
             KeyStore ks, Properties system, boolean resolve) throws Exception {
         if ( ge == null ) return null;
-        /*
-         * Do we return multiple grants or do we allow a codebase array 
-         * in a permission grant?
-         * 
-         * ANSWER: No we just make a CodeSourceSetGrant, that contains multiple
-         * CodeSource.
-         */
         List<URI> codebases = new ArrayList<URI>(8);
         Certificate[] signers = null;
         Set<Principal> principals = new HashSet<Principal>();

Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PermissionComparator.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PermissionComparator.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PermissionComparator.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PermissionComparator.java Thu Mar 14 12:13:47 2013
@@ -42,7 +42,7 @@ import java.util.Comparator;
  * so that must be very fast.
  * 
  * Note that for SocketPermissionCollection that the desired order to add to 
- * SocketPermission's is in , with the most likely permissions added last.  
+ * SocketPermission's is with the most likely permissions added last.  
  * 
  * HINT: Use a NavigableMap to return a reverse order iterator for 
  * PermissionCollection's like SocketPermissionCollection and 
@@ -53,7 +53,6 @@ import java.util.Comparator;
  */
 public class PermissionComparator implements Comparator<Permission>, Serializable {
     private static final long serialVersionUID = 1L;
-    private static final char wildcard = "*".charAt(0);
 
     public int compare(Permission o1, Permission o2) {
         if ( o1 == o2 ) return 0;

Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PermissionGrant.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PermissionGrant.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PermissionGrant.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PermissionGrant.java Thu Mar 14 12:13:47 2013
@@ -35,31 +35,39 @@ import net.jini.security.GrantPermission
 import org.apache.river.api.security.PermissionGrantBuilderImp.NullPermissionGrant;
 
 /**
- * PermissionGrant implementations are expected to be immutable, non blocking,
+ * <code>PermissionGrant</code> implementations are expected to be immutable, non blocking,
  * thread safe and have a good hashCode implementation to perform well in
  * Collections.
- * 
+ * <p>
  * Developers may use decorators to alter the behaviour of existing implementations.
  * Decorators should use a single transient volatile field to store the result of
  * an event notification, which must be immutable, state
  * may not be updated in the policy until {@link Policy#refresh()} is called.
- * 
- * PermissionGrant does not implement Serializable for security reasons, 
+ * It is the implementors responsibility to call refresh.
+ * <p>
+ * <code>PermissionGrant</code> does not implement <code>Serializable</code> for security reasons, 
  * however classes extending PermissionGrant may implement Serializable,
- * but are forced to use the Serializable Builder Pattern.  Child classes
- * cannot contain circular references to themselves if they implement
- * Serializable. {@link http://wiki.apache.org/river/Serialization}
- * 
- * You shouldn't pass around PermissionGrant's to just anyone; they can
- * provide an attacker with information about granted Permissions.
- * 
- * Caveat Implementor: PermissionGrant's cannot perform privileged actions, 
- * whilst being used by the policy to make policy decisions, any privileged 
- * actions should performed prior to creating a PermissionGrant.  
- * Only PermissionGrant's belonging to the same ProtectionDomain as the
- * active Policy can perform PrivilegedAction's, since the Policy caches it's 
- * own domain Permissions during initialisation, it doesn't consult
- * PermissionGrant's thereafter.
+ * but are forced to use the Serializable Builder Pattern. 
+ * {@link http://wiki.apache.org/river/Serialization}
+ * <p>
+ * <code>PermissionGrant</code>'s are security sensitive objects and can
+ * provide an attacker with information about granted <code>Permission</code>.  
+ * For this reason, it is wise to guard references to <code>PermissionGrant</code>
+ * or to avoid storing them in object fields altogether.
+ * <p>
+ * Caveat Implementor: <code>PermissionGrant</code>'s can only make calls to other objects
+ * that themselves perform security checks during an implies call if
+ * all ProtectionDomains involved are privileged and the call is performed within 
+ * {@link java.security.PrivilegedAction}.  {@link java.security.PrivilegedAction}'s 
+ * should generally be performed prior to creating a PermissionGrant if possible.
+ * <p>
+ * Only PermissionGrant's who's ProtectionDomain has AllPermission can perform 
+ * {@link java.security.PrivilegedAction}'s during 
+ * {@link java.security.Policy#implies(java.security.ProtectionDomain, java.security.Permission) }
+ * calls, since the {@link java.security.Policy} checks privileged PermissionGrant's 
+ * and returns without checking less privileged PermissionGrant's that would
+ * cause an infinite recursion.  Infinite recursion could be used as a denial
+ * of service by an attacker that can access an acting {@link java.security.Policy}
  * 
  * @author Peter Firmstone
  * @since 2.2.1
@@ -101,7 +109,7 @@ public abstract class PermissionGrant {
         int hashcode = 7;
         hashcode = 97 * hashcode + (this.perms != null ? this.perms.hashCode() : 0);
         hashcode = 97 * hashcode + (this.privileged ? 1 : 0);
-        hashcode = 97 * hashcode + (this.decorated != null ? this.decorated.hashCode() : 0);
+        hashcode = 97 * hashcode; // for null decorated.
         this.hash = hashcode;
     }
     
@@ -126,16 +134,60 @@ public abstract class PermissionGrant {
         int hashcode = 7;
         hashcode = 97 * hashcode + (this.perms != null ? this.perms.hashCode() : 0);
         hashcode = 97 * hashcode + (this.privileged ? 1 : 0);
-        hashcode = 97 * hashcode + (this.decorated != null ? this.decorated.hashCode() : 0);
+        hashcode = 97 * hashcode; // for decorated which is null.
         this.hash = hashcode;
     }
     
+    /**
+     * <code>PermissionGrant</code> allows for extension to enable condition or
+     * event based policy decisions.  Extending classes can add functionality 
+     * using the decorator pattern.
+     * <p>
+     * A privileged ProtectionDomain that contains AllPermission cannot be 
+     * decorated and will throw an IllegalArgumentException.  This is to 
+     * prevent accidental infinite recursion; policy's that utilize PermissionGrant
+     * will check privileged PermissionGrant's first to avoid infinite recursion.
+     * <p>
+     * A decorated PermissionGrant that calls methods that perform security
+     * checks during implies, must do so from within a PrivilegedAction and
+     * all subsequent domains on the stack required to perform the PrivilegedAction
+     * must have AllPermission and to avoid infinite recursion.  If possible
+     * avoid security checks while making implies determinations, by having an
+     * external event thread perform the privileged action and update a volatile 
+     * variable that can be checked during an implies call without invoking another
+     * security check.
+     * <p>
+     * @param decorated PermissionGrant to be decorated.
+     * @throws IllegalArguementException if decorated is privileged
+     * @throws SecurityException if caller doesn't have {@link java.lang.RuntimePermission}
+     * "getProtectionDomain" or "getClassLoader".
+     */
     protected PermissionGrant(PermissionGrant decorated){
+        this(checkInvariants(decorated), decorated);
+    }
+    
+    /**
+     * Avoid finalizer attack.  Object#finalize will not be called if first 
+     * call in our constructor is to Object constructor.
+     * 
+     * @param decorated
+     * @return 
+     */
+    private static boolean checkInvariants(PermissionGrant decorated) {
         PD_GUARD.checkGuard(null);
         CL_GUARD.checkGuard(null);
+        if (decorated.isPrivileged()) throw 
+            new IllegalArgumentException("Privileged PermissionGrant cannot be decorated");
+        return true;
+    }
+    
+    /*
+     * Avoidance of finalizer attack.
+     */
+    private PermissionGrant(boolean check, PermissionGrant decorated ){
         this.decorated = decorated;
         perms = Collections.emptySet();
-        privileged = decorated.isPrivileged();
+        privileged = false;
         hash = decorated.hashCode();
     }
 

Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PermissionGrantBuilder.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PermissionGrantBuilder.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PermissionGrantBuilder.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PermissionGrantBuilder.java Thu Mar 14 12:13:47 2013
@@ -50,20 +50,7 @@ public abstract class PermissionGrantBui
      * the ClassLoader
      */ 
     public static final int CLASSLOADER = 0;
-    /**
-     * The PermissionGrant generated will apply to all classes loaded from
-     * the CodeSource.  This has been provided for strict compatibility
-     * with the standard Java Policy, where a DNS lookup may be performed
-     * to determine if CodeSource.implies(CodeSource).  In addition, to
-     * resolve a File URL, it will require disk access.
-     * 
-     * This is very bad for Policy performance, it's use is discouraged,
-     * so much so, it may removed.
-     * 
-     * @deprecated use URI instead.
-     */
-    @Deprecated
-    public static final int CODESOURCE = 1;
+  
     /**
      * The PermissionGrant generated will apply to all classes belonging to
      * the ProtectionDomain.  This is actually a simplification for the 
@@ -92,14 +79,21 @@ public abstract class PermissionGrantBui
     
     /**
      * The PermissionGrant generated will apply to the ProtectionDomain or
-     * CodeSource who's URL is implied by the given URI.  This behaves 
-     * similarly to CodeSource.implies(CodeSource), except no DNS lookup is
-     * performed, nor file system access to verify the file exists.
+     * CodeSource who's URL is implied by the given URI.  The outcome of
+     * URI comparison is identical to {@link CodeSource.implies(CodeSource)}, 
+     * except for item 3.4; host names are normalized according to RFC3986
+     * and compared.
      * 
      * The DNS lookup is avoided for security and performance reasons,
      * DNS is not authenticated and therefore cannot be trusted.  Doing so,
      * could allow an attacker to use DNS Cache poisoning to escalate
      * Permission, by imitating a URL with greater privileges.
+     * 
+     * CodeSource URL are converted to URI and normalized according
+     * to {@link http://www.ietf.org/rfc/rfc3986.txt} RFC3986 before being 
+     * compared.
+     * 
+     * @see java.security.CodeSource#implies
      */
     public static final int URI = 5;
     
@@ -109,7 +103,8 @@ public abstract class PermissionGrantBui
     
     /**
      * resets the state for reuse, identical to a newly created 
-     * PermissionGrantBuilder.
+     * PermissionGrantBuilder, this step must be performed to avoid unintentional
+     * grants to previously added URI.
      */
     public abstract PermissionGrantBuilder reset();
    
@@ -122,17 +117,14 @@ public abstract class PermissionGrantBui
      * @throws IllegalStateException 
      */
     public abstract PermissionGrantBuilder context(int context) throws IllegalStateException;
+    
     /**
-     * Sets the CodeSource that will receive the PermissionGrant
-     * @param cs
-     * @return PermissionGrantBuilder
-     * @deprecated use uri instead.
+     * The URI will be added to the PermissionGrant, multiple may be specified by
+     * calling multiple times.
+     * 
+     * @param uri
+     * @return 
      */
-    @Deprecated
-    public abstract PermissionGrantBuilder codeSource(CodeSource cs);
-    
-    public abstract PermissionGrantBuilder multipleCodeSources();
-    
     public abstract PermissionGrantBuilder uri(URI uri);
     /**
      * Extracts ProtectionDomain
@@ -160,7 +152,7 @@ public abstract class PermissionGrantBui
      */
     public abstract PermissionGrantBuilder principals(Principal[] pals);
     /**
-     * Sets the Permission's that will be granted.
+     * Specifies Permission's to be granted.
      * @param perm
      * @return 
      */

Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PermissionGrantBuilderImp.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PermissionGrantBuilderImp.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PermissionGrantBuilderImp.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PermissionGrantBuilderImp.java Thu Mar 14 12:13:47 2013
@@ -54,19 +54,21 @@ class PermissionGrantBuilderImp extends 
     private static final long serialVersionUID = 1L;
     private static final PermissionGrant nullGrant = new NullPermissionGrant();
     
-    // Serial Form
+   
+    /*@serial */
     private URI[] uri;
-    private CodeSource cs;
-    private CodeSource[] csources;
+    /*@serial */
     private Certificate[] certs;
+    /*@serial */
     private Principal[] principals;
+    /*@serial */
     private Permission[] permissions;
+    /*@serial */
     private int context;
-    private boolean hasMultipleCodeSources;
+    /*@serial */
     private boolean hasDomain;
     
     // Transient Fields
-    private transient Collection<CodeSource> multipleCodeSources;
     private transient Collection<URI> uris;
     private transient WeakReference<ProtectionDomain> domain;
     
@@ -82,16 +84,12 @@ class PermissionGrantBuilderImp extends 
     public final PermissionGrantBuilder reset() {
         uri = null;
         if (uris != null) uris.clear();
-        cs = null;
         certs = null;
         domain = null;
         hasDomain = false;
         principals = null;
         permissions = null;
         context = -1;
-        multipleCodeSources = null;
-        csources = null;
-        hasMultipleCodeSources = false;
         return this;
     }
     
@@ -112,24 +110,6 @@ class PermissionGrantBuilderImp extends 
         this.uris.add(uri);
         return this;
     }
-
-    public PermissionGrantBuilder codeSource(CodeSource cs) {
-        if (hasMultipleCodeSources){
-            multipleCodeSources.add(cs);
-        } else {
-            this.cs = cs;
-        }
-        return this;
-    }
-    
-        @Override
-    public PermissionGrantBuilder multipleCodeSources() {
-        hasMultipleCodeSources = true;
-        multipleCodeSources = new HashSet<CodeSource>();
-        csources = null;
-        cs = null;
-        return this;
-    }
     
 
     public PermissionGrantBuilder clazz(Class cl) {
@@ -175,13 +155,6 @@ class PermissionGrantBuilderImp extends 
                 if (uris != null && !uris.isEmpty() ) uri = uris.toArray(new URI[uris.size()]);
                 if (uri == null ) uri = new URI[0];
                 return new URIGrant(uri, certs, principals, permissions);              
-            case CODESOURCE:
-                if (hasMultipleCodeSources) {
-                    if (multipleCodeSources != null) csources = 
-                            multipleCodeSources.toArray(new CodeSource[multipleCodeSources.size()]);
-                    return new CodeSourceSetGrant(csources, principals, permissions);
-                }
-                return new CodeSourceGrant(cs, principals, permissions);
             case CODESOURCE_CERTS:
                 return new CertificateGrant(certs, principals, permissions);
             case PROTECTIONDOMAIN: //Dynamic grant
@@ -207,11 +180,6 @@ class PermissionGrantBuilderImp extends 
     }
     
     private void writeObject(ObjectOutputStream out) throws IOException{
-        if (hasMultipleCodeSources) {
-            if (csources == null && multipleCodeSources != null) csources = 
-                    multipleCodeSources.toArray(new CodeSource[multipleCodeSources.size()]);
-            cs = null;
-        }
         if (uris != null && !uris.isEmpty()) uri = uris.toArray(new URI[uris.size()]);
         out.defaultWriteObject();
     }

Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PolicyParser.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PolicyParser.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PolicyParser.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PolicyParser.java Thu Mar 14 12:13:47 2013
@@ -24,21 +24,20 @@ import java.util.Properties;
 import org.apache.river.api.security.PermissionGrant;
 
 /**
- * Based on the Apache Harmony interface of the same name, although not compatible.
+ * Parser of policy syntax.
+ * 
+ * @see PermissionGrant
+ * @see URL
+ * @see Properties
+ * @see ConcurrentPolicyFile
  * 
  * @author Peter Firmstone
  */
 public interface PolicyParser {
 
     /**
-     * This is the main business method. It manages loading process as follows:
-     * the associated scanner is used to parse the stream to a set of
-     * {@link org.apache.river.imp.security.policy.util.DefaultPolicyScanner.GrantEntry composite tokens},
-     * then this set is iterated and each token is translated to a PermissionGrant.
-     * Semantically invalid tokens are ignored, the same as void PolicyEntries.
-     * <br>
-     * A policy file may refer to some KeyStore(s), and in this case the first
-     * valid reference is initialized and used in processing tokens.
+     * Parses a given location, making use of system properties as necessary and
+     * returns a collection of <code>PermissionGrant</code>'s
      *
      * @param location an URL of a policy file to be loaded
      * @param system system properties, used for property expansion

Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PrincipalGrant.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PrincipalGrant.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PrincipalGrant.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/PrincipalGrant.java Thu Mar 14 12:13:47 2013
@@ -78,7 +78,7 @@ class PrincipalGrant extends PermissionG
                 Class c = p.getClass();
                 String name = p.getName();
                 String actions = p.getActions();
-                hash = 97 * hash + (c != null ? c.hashCode() : 0);
+                hash = 97 * hash + c.hashCode();
                 hash = 97 * hash + (name != null ? name.hashCode() : 0);
                 hash = 97 * hash + (actions != null ? actions.hashCode() : 0);
             }
@@ -151,7 +151,7 @@ class PrincipalGrant extends PermissionG
                  * a PrincipalGrant is immutable and therefore shouldn't change.
                  * Group represents a mutable component which can change the
                  * result of implies.  A PrincipalGrant, should
-                 * have the same behaviour on all calls to implies.
+                 * have the same behaviour on all calls to implies, ie: be idempotent.
                  * 
                  * The reason for this choice at this time; there is
                  * no way a Policy can be aware the PrincipalGrant
@@ -226,47 +226,9 @@ class PrincipalGrant extends PermissionG
     Principal[] getPrincipals(final ProtectionDomain pd){
         if (pd instanceof SubjectDomain){
             final Set<Principal> principals = ((SubjectDomain) pd).getSubject().getPrincipals();
-            // Synchronisation would prevent modification during array creation,
-            // but it also prevents multi read,
-            // lets use an iterator, catch ConcurrentModificationException 
-            // (which should seldom happen) sleep momentarily and try again.
-            Principal[] result = null;
-            Iterator<Principal> it = null;
-            // This minimal synchronization ensures that array size will
-            // be correct if ConcurrentModificationException is not thrown.
-            synchronized (principals){
-                result = new Principal[principals.size()];
-                it = principals.iterator();
-            }
-            boolean retry = true;
-            while (retry){
-                try {
-                    int i = 0;
-                    while (it.hasNext()){
-                        result[i] = it.next();
-                        i++;
-                    }
-                    return result;
-                } catch ( ConcurrentModificationException e){
-                    try {
-                        // sleep for modifications to finish = back off.
-                        Thread.currentThread().sleep(20L);
-                        synchronized(principals){  // try again
-                            result = new Principal[principals.size()];
-                            it = principals.iterator();
-                        }
-                    } catch (InterruptedException ex) {
-                        // ProtectionDomain.getPrincipals() instead.
-                        retry = false;
-                        Thread.currentThread().interrupt(); // restore interrupt.
-                    }
-                } catch ( ArrayIndexOutOfBoundsException e) {
-                    retry = false;
-                    // ProtectionDomain.getPrincipals() instead.
-                    System.err.println("ArrayIndexOutOfBoundsException occured during iteration of Subject Principals");
-                    e.printStackTrace(System.err);
-                }
-            }
+            // principals is a synchronized Set, always up to date.
+            // Contention should be minimal even if Subject run on many threads.
+            return (Principal[]) principals.toArray();
         }
         return pd.getPrincipals();
     }

Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/RemotePolicy.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/RemotePolicy.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/RemotePolicy.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/RemotePolicy.java Thu Mar 14 12:13:47 2013
@@ -86,8 +86,6 @@ import net.jini.security.policy.Umbrella
  * @see GrantPermission
  * @see UmbrellaGrantPermission
  * @see PolicyParser
- * @see DefaultPolicyParser
- * @see DefaultPolicyScanner
  * @see PolicyPermission
  */
 public interface RemotePolicy {

Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/RemotePolicyProvider.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/RemotePolicyProvider.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/RemotePolicyProvider.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/RemotePolicyProvider.java Thu Mar 14 12:13:47 2013
@@ -30,10 +30,8 @@ import java.security.Policy;
 import java.security.PrivilegedAction;
 import java.security.ProtectionDomain;
 import java.security.UnresolvedPermission;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Comparator;
 import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -45,11 +43,12 @@ import java.util.TreeSet;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import net.jini.security.GrantPermission;
+import org.apache.river.api.common.Beta;
 
 /**
- *
  * @author Peter Firmstone
  */
+@Beta
 public class RemotePolicyProvider extends AbstractPolicy implements RemotePolicy,
         ScalableNestedPolicy{
     
@@ -84,7 +83,7 @@ public class RemotePolicyProvider extend
     private final boolean loggable;
     
     /**
-     * Creates a new <code>DynamicPolicyProvider</code> instance that wraps
+     * Creates a new <code>RemotePolicyProvider</code> instance that wraps
      * around the given non-<code>null</code> base policy object.
      *
      * @param   basePolicy base policy object containing information about
@@ -298,8 +297,8 @@ public class RemotePolicyProvider extend
     }
 
     @Override
-    public Collection<PermissionGrant> getPermissionGrants(ProtectionDomain domain) {
-        Collection<PermissionGrant> grants = null;
+    public List<PermissionGrant> getPermissionGrants(ProtectionDomain domain) {
+        List<PermissionGrant> grants = null;
         if (basePolicy instanceof ScalableNestedPolicy){
             grants = ((ScalableNestedPolicy) basePolicy).getPermissionGrants(domain);
         } else {

Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/ScalableNestedPolicy.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/ScalableNestedPolicy.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/ScalableNestedPolicy.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/ScalableNestedPolicy.java Thu Mar 14 12:13:47 2013
@@ -19,7 +19,7 @@
 package org.apache.river.api.security;
 
 import java.security.ProtectionDomain;
-import java.util.Collection;
+import java.util.List;
 
 /**
  * Policy providers can implement this interface to provide nested policies
@@ -33,16 +33,25 @@ import java.util.Collection;
 public interface ScalableNestedPolicy {
     
     /**
-     * Returns a new Collection containing immutable PermissionGrant's, the
-     * Collection returned is not synchronised and must not be shared with policy 
+     * Returns a new List containing immutable PermissionGrant's, the
+     * List returned is not synchronised and must not be shared with policy 
      * internal state.
      * 
      * Only those PermissionGrant's that imply the domain will be returned.
      * 
-     * This allows the top level policy to gather all PermissionGrant's,
-     * retrieve all relevant permissions, then sort them using PermissionComparator
-     * or any other Comparator, so Permission objects are added to a PermissionCollection
-     * in the most efficient order.
+     * If any PermissionGrant's are privileged (contain AllPermission), then
+     * only that one PermissionGrant should be added to the collection.  If
+     * a List has a size of 1, and contains only a privileged PermissionGrant,
+     * it enables the calling policy to determine the privileged state quickly.
+     * 
+     * If a policy has a privileged PermissionGrant to add to a Collection,
+     * then the Collection must be cleared before the privileged PermissionGrant
+     * is added, so the Collection only contains the privileged PermissionGrant.
+     * 
+     * The top level policy gathers all PermissionGrant's,
+     * retrieves all relevant permissions, then sorts them using a 
+     * PermissionComparator, so Permission objects are added to a 
+     * PermissionCollection in the most efficient order.
      * 
      * If a nested base policy doesn't support ScalableNestedPolicy, then the
      * implementer should create a PermissionGrant for the domain, containing
@@ -55,6 +64,6 @@ public interface ScalableNestedPolicy {
      * @param domain 
      * @return Collection<PermissionGrant>  
      */
-    public Collection<PermissionGrant> getPermissionGrants(
+    public List<PermissionGrant> getPermissionGrants(
                                                 ProtectionDomain domain);
 }

Modified: river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/SubjectDomain.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/SubjectDomain.java?rev=1456399&r1=1456398&r2=1456399&view=diff
==============================================================================
--- river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/SubjectDomain.java (original)
+++ river/jtsk/skunk/qa_refactor/trunk/src/org/apache/river/api/security/SubjectDomain.java Thu Mar 14 12:13:47 2013
@@ -22,7 +22,50 @@ import java.security.ProtectionDomain;
 import javax.security.auth.Subject;
 
 /**
- *
+ * A Marker interface used by {@link net.jini.security.Security} to mark
+ * a {@link java.security.ProtectionDomain} added to the stack that represents an
+ * authenticated {@link javax.security.auth.Subject} with 
+ * {@link java.security.Principal}'s.
+ * <p>
+ * Typically in non-distributed systems, a <code>Subject</code> is represented
+ * by a <code>Thread</code> and all {@link java.security.Permission} granted 
+ * to that <code>Subject</code> is injected into every <code>ProtectionDomain</code> 
+ * present on the call stack. Code is always trusted, or at least it must be at the time the 
+ * <code>Subject</code> is authenticated.
+ * <p>
+ * However in a distributed system, because code trust and Subject's are 
+ * separate concerns, methods have been provided in 
+ * {@link net.jini.security.Security} to prepend a <code>ProtectionDomain</code>
+ * to the stack instead of injecting Principal's into all ProtectionDomain's on 
+ * the stack, this avoids mistakenly elevating privileges of less trusted
+ * code, if present on a call stack at the time the doAs subject method is called.
+ * <p>
+ * When using these methods, the security Policy needs to be written to grant
+ * Permission to code signer certificates and Principals separately.
+ * <p>
+ * For example, a RemotePolicy service is updated by an Administrator client
+ * using PermissionGrant's, however one of these grants is not signed by a 
+ * trusted Certificate.  Ordinarily this PermissionGrant would run with the
+ * privileges of the administrator, but because code trust and user trust
+ * should be considered separate concerns in a distributed system,
+ * the administrator is unable to make these PermissionGrant's in the 
+ * presence of untrusted code.
+ * <p>
+ * These methods apply the principle of least privilege to Subject's as well
+ * as code.  The privileges allowed will be the intersection of Permission 
+ * granted to each ProtectionDomain on the call stack.
+ * <p>
+ * These methods require a River or Jini Policy provider to be installed.  The
+ * SubjectDomain is a dynamic ProtectionDomain, it contains no Permission,
+ * it always consults the current {@link java.security.Policy}.
+ * 
+ * @see net.jini.security.Security#doAs(javax.security.auth.Subject, java.security.PrivilegedAction) 
+ * @see net.jini.security.Security#doAs(javax.security.auth.Subject, java.security.PrivilegedExceptionAction) 
+ * @see net.jini.security.Security#doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedAction, net.jini.security.SecurityContext) 
+ * @see net.jini.security.Security#doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedExceptionAction, net.jini.security.SecurityContext) 
+ * @see net.jini.security.policy.DynamicPolicyProvider
+ * @see org.apache.river.api.security.ConcurrentPolicyFile
+ * 
  * @author Peter Firmstone
  */
 public interface SubjectDomain {