You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@river.apache.org by Peter Firmstone <ji...@zeus.net.au> on 2011/12/19 06:59:21 UTC

A non blocking (almost) DynamicPermissionCollection

Thoughts?


/*
 * 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();
        }
     
    }
 
}


Re: A non blocking (almost) DynamicPermissionCollection

Posted by Peter Firmstone <ji...@zeus.net.au>.
Anyone notice a problem yet?

Even though a Permission probably could and should be immutable, there's 
an issue, some aren't.

Going back to our favourite bad example of a Permission implementation, 
SocketPermission:

SocketPermission mutates on implies calls.

Now, most of the state required to determine if SocketPermission is 
published after construction, however there are some fields relating to 
dns lookups and lookup failures.

Currently if multiple threads (each with their own thread stack context 
- AccessControlContext) running the same code concurrently require 
Permission checks, the threads context will or may contain identical 
ProtectionDomain's,

ProtectionDomain -> Policy-> Permissions -> PermissionCollection -> 
Permission

Our implementation:

ProtectionDomain -> DynamicPolicy -> ConcurrentPermissions -> 
DynamicPermissionCollection -> Permission

The existing policy implementation blocks all implies checks at the 
Permissions level (not Permission), so a SocketPermission check blocking 
on a ProtectionDomain will cause all other threads to block on that 
ProtectionDomain for any Permission check!

Now the problem with AccessControlContext is, that the ProtectionDomains 
it contains are checked sequentially, so if one blocks, they all sit 
there waiting to be checked.

No wonder people complain about SecurityManager performance!

All my improvements to date have only pushed synchronisation to the 
PermissionCollection level.

I've got a SecurityManager that executes checks on all ProtectionDomains 
in an AccessControlContext in parallel, so one blocking PD won't hold up 
the others.

This will reduce the remaining work when the blocking SocketPermission 
finally releases the lock, with my implementation, the blocking will 
only occur on SocketPermissionCollection checks.

A major problem with DynamicPermissionCollection is it assumes the 
Permission is immutable, the current calling thread retrieves a private 
array copy of each Permission (all belonging to the same class), then 
assembles these into an independent unshared instance of 
PermissionCollection, it doesn't block, since other threads can't see 
it, however the underlying Permission's are still shared by other threads.

And damn it, SocketPermission isn't thread safe!

So in this case, updated reference fields, will not be seen by other 
threads, in other words if a SocketPermission fails it's dns lookup, it 
will continue to do so for every thread that tries, since none ever 
write cached updated internal object references back to ram.

But wild card SocketPermissions don't mutate and if 
SocketPermissionCollection contains a wild card, non of the other 
permissions even matter!  Despite SocketPermissionCollection's 
implementation insisting otherwise.

It's getting very tempting to just re implement SocketPermission, 
however doing so opens another can of worms with static 
ProtectionDomains that never consult the policy.

Even in current sun policy implementations because a static 
ProtectionDomain copies it's Permissions (note "s" this is a 
PermissionCollection, not a Permission) objects, it's possible for 
SocketPermission to exist in separate PermissionCollection's, again 
creating possible stale unsynchronized state.

Cheers,

Peter.

Thoughts?

Peter Firmstone wrote:
> Thoughts?
>
>
> /*
> * 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();
>        }
>        }
>
> }
>
>


Re: A non blocking (almost) DynamicPermissionCollection

Posted by Peter Firmstone <ji...@zeus.net.au>.
Dan Creswell wrote:
> What kind of thoughts are you after?
>
> Appropriateness, code review, something else?
>   

Ideas.

It would be nice to lock on each SocketPermission, however that isn't 
possible, it cannot be wrapped inside SocketPermissionCollection and the 
latter cannot be guaranteed to be used uniquely to synchronize the former.

I wanted to avoid creating a specific collection for only handling 
SocketPermission, but since it's SocketPermissionCollection doesn't do 
anything fancy and just iterates over all the SocketPermission's I might 
yet create a SocketPermission wrapper that implements a sensible equals 
and has it's own PermissionCollection, that uses a tryLock and skips 
SocketPermission's it can't obtain the lock and try again later.

Cheers,

Peter.
> On 19 December 2011 05:59, Peter Firmstone <ji...@zeus.net.au> wrote:
>   
>> Thoughts?
>>
>>
>> /*
>> * 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();
>>       }
>>       }
>>
>> }
>>
>>     
>
>   


Re: A non blocking (almost) DynamicPermissionCollection

Posted by Dan Creswell <da...@gmail.com>.
What kind of thoughts are you after?

Appropriateness, code review, something else?

On 19 December 2011 05:59, Peter Firmstone <ji...@zeus.net.au> wrote:
> Thoughts?
>
>
> /*
> * 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();
>       }
>       }
>
> }
>

Re: A non blocking (almost) DynamicPermissionCollection

Posted by Peter <ji...@zeus.net.au>.
Hmm,

You're right, the code is more readable with a cast ;)

A side effect of Generics being bolted on, hope they fix it some day.

Peter.

----- Original message -----
> On 12/19/2011 1:14 PM, Peter Firmstone wrote:
> > Gregg Wonderly wrote:
> > > On 12/18/2011 11:59 PM, Peter Firmstone wrote:
> > > >      @Override
> > > >      public boolean implies(Permission permission) {
> > > >              if ( ! cl.isInstance(permission)) return false;
> > > >              Permission [] p = perms.toArray(new Permission[0]); //perms.size()
> > > > may change
> > >
> > > I not sure why you are using an empty Permission array here, and then
> > > looping  over it.  Is this from some other testing?
> > >
> > > Gregg
> > >
> > The collection is wrapped with a ConcurrentCollection's multi read, single
> > write wrapper, by passing a zero length array to the collection, it obtains a
> > read lock, the collection creates a new array, sized to suit the underlying
> > array, copy's the collection's contents into it and returns, releasing the
> > read lock, the operation is atomic.
> > If I did this, the call would acquire and release two read locks
> > consecutively, it wouldn't be atomic:
> >
> > Permission[] p  = perms.toArray(new Permission[perms.size()]);
> >
> > It's there to avoid a cast:
> >
> > Permission [] p = (Permission[]) perms.toArray();
>
> Okay, that make sense from a logic perspective.  It might be better to use the
> second version just to remove the distraction of trying to understand how a zero
> length array results in a non-zero length result.
>
> Your call, I'm not sure it really matters.
>
> Gregg


Re: A non blocking (almost) DynamicPermissionCollection

Posted by Gregg Wonderly <gr...@gmail.com>.
On 12/19/2011 1:14 PM, Peter Firmstone wrote:
> Gregg Wonderly wrote:
>> On 12/18/2011 11:59 PM, Peter Firmstone wrote:
>>>    @Override
>>>    public boolean implies(Permission permission) {
>>>        if ( ! cl.isInstance(permission)) return false;
>>>        Permission [] p = perms.toArray(new Permission[0]); //perms.size() 
>>> may change
>>
>> I not sure why you are using an empty Permission array here, and then looping 
>> over it.  Is this from some other testing?
>>
>> Gregg
>>
> The collection is wrapped with a ConcurrentCollection's multi read, single 
> write wrapper, by passing a zero length array to the collection, it obtains a 
> read lock, the collection creates a new array, sized to suit the underlying 
> array, copy's the collection's contents into it and returns, releasing the 
> read lock, the operation is atomic.
> If I did this, the call would acquire and release two read locks 
> consecutively, it wouldn't be atomic:
>
> Permission[] p  = perms.toArray(new Permission[perms.size()]);
>
> It's there to avoid a cast:
>
> Permission [] p = (Permission[]) perms.toArray();

Okay, that make sense from a logic perspective.  It might be better to use the 
second version just to remove the distraction of trying to understand how a zero 
length array results in a non-zero length result.

Your call, I'm not sure it really matters.

Gregg

Re: A non blocking (almost) DynamicPermissionCollection

Posted by Peter Firmstone <ji...@zeus.net.au>.
Gregg Wonderly wrote:
> On 12/18/2011 11:59 PM, Peter Firmstone wrote:
>>    @Override
>>    public boolean implies(Permission permission) {
>>        if ( ! cl.isInstance(permission)) return false;
>>        Permission [] p = perms.toArray(new Permission[0]); 
>> //perms.size() may change
>
> I not sure why you are using an empty Permission array here, and then 
> looping over it.  Is this from some other testing?
>
> Gregg
>
The collection is wrapped with a ConcurrentCollection's multi read, 
single write wrapper, by passing a zero length array to the collection, 
it obtains a read lock, the collection creates a new array, sized to 
suit the underlying array, copy's the collection's contents into it and 
returns, releasing the read lock, the operation is atomic.  

If I did this, the call would acquire and release two read locks 
consecutively, it wouldn't be atomic:

Permission[] p  = perms.toArray(new Permission[perms.size()]);

It's there to avoid a cast:

Permission [] p = (Permission[]) perms.toArray();

Although not utilised here the Iterator returned by the 
ConcurrentCollection wrapper has a private copy of the underlying 
Collection, so it will never throw ConcurrentModificationException, so I 
could use that instead, but using the array consumes less memory than 
duplicating the collection.

Maybe I should change the comment to // Zero length array is replaced by 
correct size array atomically.

Cheers,

Peter.

Re: A non blocking (almost) DynamicPermissionCollection

Posted by Gregg Wonderly <gr...@wonderly.org>.
On 12/18/2011 11:59 PM, Peter Firmstone wrote:
>    @Override
>    public boolean implies(Permission permission) {
>        if ( ! cl.isInstance(permission)) return false;
>        Permission [] p = perms.toArray(new Permission[0]); //perms.size() may 
> change

I not sure why you are using an empty Permission array here, and then looping 
over it.  Is this from some other testing?

Gregg