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