All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.wildfly.common.context.ContextPermissionCollection Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

The newest version!
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2016 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed 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.wildfly.common.context;

import java.security.Permission;
import java.security.PermissionCollection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

import org.wildfly.common.Assert;
import org.wildfly.common._private.CommonMessages;

/**
 * @author David M. Lloyd
 */
final class ContextPermissionCollection extends PermissionCollection {
    private static final long serialVersionUID = - 3651721703337368351L;

    private volatile State state = emptyState;

    private static final AtomicReferenceFieldUpdater stateUpdater = AtomicReferenceFieldUpdater.newUpdater(ContextPermissionCollection.class, State.class, "state");

    public void add(final Permission permission) throws SecurityException, IllegalArgumentException {
        Assert.checkNotNullParam("permission", permission);
        if (permission instanceof ContextPermission) {
            add((ContextPermission) permission);
        } else {
            throw CommonMessages.msg.invalidPermissionType(ContextPermission.class, permission.getClass());
        }
    }

    public void add(final ContextPermission contextPermission) throws SecurityException {
        Assert.checkNotNullParam("contextPermission", contextPermission);
        if (isReadOnly()) {
            throw CommonMessages.msg.readOnlyPermissionCollection();
        }
        final int actionBits = contextPermission.getActionBits();
        if (actionBits == 0) {
            // no operation
            return;
        }
        final String name = contextPermission.getName();
        State oldState, newState;
        do {
            oldState = this.state;
            final ContextPermission oldGlobalPermission = oldState.globalPermission;
            final int globalActions = oldGlobalPermission == null ? 0 : oldGlobalPermission.getActionBits();
            if (oldGlobalPermission != null && oldGlobalPermission.implies(contextPermission)) {
                // already fully implied by global permission
                return;
            } else {
                final Map oldPermissions = oldState.permissions;
                final Map newPermissions;
                final ContextPermission newGlobalPermission;
                if (name.equals("*")) {
                    // it's global but with some bits we don't have; calculate the new global actions and subtract from the map
                    if (oldGlobalPermission == null) {
                        newGlobalPermission = contextPermission;
                    } else {
                        newGlobalPermission = oldGlobalPermission.withActionBits(contextPermission.getActionBits());
                    }

                    // now subtract
                    newPermissions = cloneWithout(oldPermissions, newGlobalPermission);
                } else {
                    newGlobalPermission = oldGlobalPermission;
                    // it's not global; check & add actions to our map permission
                    final ContextPermission mapPermission = oldPermissions.get(name);
                    if (mapPermission == null) {
                        // no map entry; just create one (but without any global actions we have defined)
                        if (oldPermissions.isEmpty()) {
                            // change empty map to singleton map
                            newPermissions = Collections.singletonMap(name, contextPermission.withoutActionBits(globalActions));
                        } else {
                            // make a copy of the map plus the new entry
                            newPermissions = new HashMap<>(oldPermissions);
                            newPermissions.put(name, contextPermission.withoutActionBits(globalActions));
                        }
                    } else if (((mapPermission.getActionBits() | globalActions) & actionBits) == actionBits) {
                        // already fully implied by a map entry
                        return;
                    } else {
                        // replace the map entry
                        if (oldPermissions.size() == 1) {
                            // it was a singleton map, just replace it
                            newPermissions = Collections.singletonMap(name, mapPermission.withActionBits(actionBits & ~globalActions));
                        } else {
                            // copy the map and replace the entry
                            newPermissions = new HashMap<>(oldPermissions);
                            newPermissions.put(name, mapPermission.withActionBits(actionBits & ~globalActions));
                        }
                    }
                }
                newState = new State(newGlobalPermission, newPermissions);
            }
        } while (! stateUpdater.compareAndSet(this, oldState, newState));
    }

    private static Map cloneWithout(final Map oldPermissions, final ContextPermission newGlobalPermission) {
        final Iterator iterator = oldPermissions.values().iterator();
        ContextPermission first;
        for (;;) {
            if (! iterator.hasNext()) {
                return Collections.emptyMap();
            }
            first = iterator.next();
            if (! newGlobalPermission.implies(first)) {
                // break into next phase
                break;
            }
        }
        final int globalActionBits = newGlobalPermission.getActionBits();
        ContextPermission second;
        for (;;) {
            if (! iterator.hasNext()) {
                return Collections.singletonMap(first.getName(), first.withoutActionBits(globalActionBits));
            }
            second = iterator.next();
            if (! newGlobalPermission.implies(second)) {
                // break into next phase
                break;
            }
        }
        HashMap newMap = new HashMap<>();
        newMap.put(first.getName(), first.withoutActionBits(globalActionBits));
        newMap.put(second.getName(), second.withoutActionBits(globalActionBits));
        ContextPermission subsequent;
        while (iterator.hasNext()) {
            subsequent = iterator.next();
            if (! newGlobalPermission.implies(subsequent)) {
                newMap.put(subsequent.getName(), subsequent.withoutActionBits(globalActionBits));
            }
        }
        return newMap;
    }

    public boolean implies(final Permission permission) {
        return permission instanceof ContextPermission && implies((ContextPermission) permission);
    }

    public boolean implies(final ContextPermission permission) {
        if (permission == null) return false;
        final State state = this.state;
        final ContextPermission globalPermission = state.globalPermission;
        final int globalBits;
        if (globalPermission != null) {
            if (globalPermission.implies(permission)) {
                return true;
            }
            globalBits = globalPermission.getActionBits();
        } else {
            globalBits = 0;
        }
        final int bits = permission.getActionBits();
        final String name = permission.getName();
        if (name.equals("*")) {
            return false;
        }
        final ContextPermission ourPermission = state.permissions.get(name);
        if (ourPermission == null) {
            return false;
        }
        final int ourBits = ourPermission.getActionBits() | globalBits;
        return (bits & ourBits) == bits;
    }

    public Enumeration elements() {
        final State state = this.state;
        final Iterator iterator = state.permissions.values().iterator();
        return new Enumeration() {
            Permission next = state.globalPermission;

            public boolean hasMoreElements() {
                if (next != null) {
                    return true;
                }
                if (iterator.hasNext()) {
                    next = iterator.next();
                    return true;
                }
                return false;
            }

            public Permission nextElement() {
                if (! hasMoreElements()) throw new NoSuchElementException();
                try {
                    return next;
                } finally {
                    next = null;
                }
            }
        };
    }

    static class State {
        private final ContextPermission globalPermission;
        private final Map permissions;

        State(final ContextPermission globalPermission, final Map permissions) {
            this.globalPermission = globalPermission;
            this.permissions = permissions;
        }
    }

    private static final State emptyState = new State(null, Collections.emptyMap());
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy