⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 policycollection.java

📁 sunxacml源码
💻 JAVA
字号:

/*
 * @(#)PolicyCollection.java
 *
 * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   1. Redistribution of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 * 
 *   2. Redistribution in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * Neither the name of Sun Microsystems, Inc. or the names of contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that this software is not designed or intended for use in
 * the design, construction, operation or maintenance of any nuclear facility.
 */

package com.sun.xacml.support.finder;

import com.sun.xacml.AbstractPolicy;
import com.sun.xacml.EvaluationCtx;
import com.sun.xacml.MatchResult;
import com.sun.xacml.Policy;
import com.sun.xacml.PolicyMetaData;
import com.sun.xacml.PolicyReference;
import com.sun.xacml.PolicySet;
import com.sun.xacml.Target;
import com.sun.xacml.TargetMatch;
import com.sun.xacml.TargetSection;
import com.sun.xacml.VersionConstraints;

import com.sun.xacml.combine.PolicyCombiningAlgorithm;

import com.sun.xacml.ctx.Status;

import java.net.URI;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.TreeSet;


/**
 * This class handles collections of <code>AbstractPolicy</code> instances,
 * and provides some commonly useful operations. Specifically, it lets you
 * retrieve matching policies (based on reference or context), it optionally
 * handles wrapping multiple matches under a single PolicySet, and it manages
 * different versions of policies correctly. This class is intended for use
 * as a backing store to <code>PolicyFinderModule</code>s, but in practice
 * may have many uses.
 * <p>
 * Note that this class will accept multiple versions of the same policy. This
 * means that when you retieve a policy by reference, you will get the
 * correct version. It also means that when you retrieve a policy based on
 * context, there may be multiple revisions of the same policy, any number
 * of which may apply. Generally speaking, the correct behavior here is not
 * to return all of these policies, since they are (virtually speaking) the
 * same policy, but may have conflicting rules. So, as a simplification, and
 * to handle the most common cases, only the most recent version of a policy
 * is returned in these cases. If you need a more complex solution, you
 * will need to implement it yourself. Because the support modules use this
 * class as their backing store, this is true also of those modules.
 * <p>
 * Note that this is not a heavily optimized class. It is intended more as
 * an example, support code for the finder modules, and a starting utility
 * for other programmers than as an enterprise-quality implementation. That
 * said, it is fully functional, and should be useful for many applications.
 *
 * @since 2.0
 * @author Seth Proctor
 */
public class PolicyCollection
{

    // the actual collection of policies
    private HashMap policies;

    // the single instance of the comparator we'll use for managing versions
    private VersionComparator versionComparator = new VersionComparator();

    // the optional combining algorithm used when wrapping multiple policies
    private PolicyCombiningAlgorithm combiningAlg;

    // the optional policy id used when wrapping multiple policies
    private URI parentId;

    // default target that matches anything, used in wrapping policies
    private static final Target target;

    /**
     * This static initializer just sets up the default target, which is
     * used by all wrapping policy sets.
     */
    static {
        target =
            new Target(new TargetSection(null, TargetMatch.SUBJECT,
                                         PolicyMetaData.XACML_VERSION_2_0),
                       new TargetSection(null, TargetMatch.RESOURCE,
                                         PolicyMetaData.XACML_VERSION_2_0),
                       new TargetSection(null, TargetMatch.ACTION,
                                         PolicyMetaData.XACML_VERSION_2_0),
                       new TargetSection(null, TargetMatch.ENVIRONMENT,
                                         PolicyMetaData.XACML_VERSION_2_0));
    };

    /**
     * Creates a new <code>PolicyCollection</code> that will return errors
     * when multiple policies match for a given request.
     */
    public PolicyCollection() {
        policies = new HashMap();
        combiningAlg = null;
    }

    /**
     * Creates a new <code>PolicyCollection</code> that will create a new
     * top-level PolicySet when multiple policies match for a given request.
     *
     * @param combiningAlg the algorithm to use in a new PolicySet when more
     *                     than one policy applies
     * @param parentPolicyId the identifier to use for the new PolicySet
     */
    public PolicyCollection(PolicyCombiningAlgorithm combiningAlg,
                            URI parentPolicyId) {
        policies = new HashMap();

        this.combiningAlg = combiningAlg;
        this.parentId = parentPolicyId;
    }

    /**
     * Adds a new policy to the collection, and uses the policy's identifier
     * as the reference identifier. If this identifier already exists in the
     * collection, and this policy does not represent a new version of the
     * policy, then the policy is not added.
     *
     * @param policy the policy to add
     *
     * @return true if the policy was added, false otherwise
     */
    public boolean addPolicy(AbstractPolicy policy) {
        return addPolicy(policy, policy.getId().toString());
    }

    /**
     * Adds a new policy to the collection using the given identifier as
     * the reference identifier. If this identifier already exists in the
     * collection, and this policy does not represent a new version of the
     * policy, then the policy is not added.
     *
     * @param policy the policy to add
     * @param identifier the identifier to use when referencing this policy
     *
     * @return true if the policy was added, false otherwise
     */
    public boolean addPolicy(AbstractPolicy policy, String identifier) {
        if (policies.containsKey(identifier)) {
            // this identifier is already is use, so see if this version is
            // already in the set
            TreeSet set = (TreeSet)(policies.get(identifier));
            return set.add(policy);
        } else {
            // this identifier isn't already being used, so create a new
            // set in the map for it, and add the policy
            TreeSet set = new TreeSet(versionComparator);
            policies.put(identifier, set);
            return set.add(policy);
        }
    }

    /**
     * Attempts to retrieve a policy based on the given context. If multiple
     * policies match then this will either throw an exception or wrap the
     * policies under a new PolicySet (depending on how this instance was
     * constructed). If no policies match, then this will return null. See
     * the comment in the class header about how this behaves when multiple
     * versions of the same policy exist.
     *
     * @param context representation of a request
     *
     * @return a matching policy, or null if no policy matches
     *
     * @throws TopLevelPolicyException if multiple policies match but this
     *                                 instance wasn't setup to wrap policies
     */
    public AbstractPolicy getPolicy(EvaluationCtx context)
        throws TopLevelPolicyException
    {
        // setup a list of matching policies
        ArrayList list = new ArrayList();
        // get an iterator over all the identifiers
        Iterator it = policies.values().iterator();

        while (it.hasNext()) {
            // for each identifier, get only the most recent policy
            AbstractPolicy policy =
                (AbstractPolicy)(((TreeSet)(it.next())).first());

            // see if we match
            MatchResult match = policy.match(context);
            int result = match.getResult();
            
            // if there was an error, we stop right away
            if (result == MatchResult.INDETERMINATE)
                throw new TopLevelPolicyException(match.getStatus());

            // if we matched, we keep track of the matching policy...
            if (result == MatchResult.MATCH) {
                // ...first checking if this is the first match and if
                // we automaticlly nest policies
                if ((combiningAlg == null) && (list.size() > 0)) {
                    ArrayList code = new ArrayList();
                    code.add(Status.STATUS_PROCESSING_ERROR);
                    Status status = new Status(code, "too many applicable"
                                               + " top-level policies");
                    throw new TopLevelPolicyException(status);
                }

                list.add(policy);
            }
        }
        
        // no errors happened during the search, so now take the right
        // action based on how many policies we found
        switch (list.size()) {
        case 0:
            return null;
        case 1:
            return ((AbstractPolicy)(list.get(0)));
        default:
            return new PolicySet(parentId, combiningAlg, target, list);
        }
    }

    /**
     * Attempts to retrieve a policy based on the given identifier and other
     * constraints. If there are multiple versions of the identified policy
     * that meet the version constraints, then the most recent version is
     * returned.
     *
     * @param identifier an identifier specifying some policy
     * @param type type of reference (policy or policySet) as identified by
     *             the fields in <code>PolicyReference</code>
     * @param constraints any optional constraints on the version of the
     *                    referenced policy (this will never be null, but
     *                    it may impose no constraints, and in fact will
     *                    never impose constraints when used from a pre-2.0
     *                    XACML policy)
     */
    public AbstractPolicy getPolicy(String identifier, int type,
                                    VersionConstraints constraints) {
        TreeSet set = (TreeSet)(policies.get(identifier));
        
        // if we don't know about this identifier then there's nothing to do
        if (set == null)
            return null;

        // walk through the set starting with the most recent version, looking
        // for a match until we exhaust all known versions
        Iterator it = set.iterator();
        while (it.hasNext()) {
            AbstractPolicy policy = (AbstractPolicy)(it.next());
            if (constraints.meetsConstraint(policy.getVersion())) {
                // we found a valid version, so see if it's the right kind,
                // and if it is then we return it
                if (type == PolicyReference.POLICY_REFERENCE) {
                    if (policy instanceof Policy)
                        return policy;
                } else {
                    if (policy instanceof PolicySet)
                        return policy;
                }
            }
        }

        // we didn't find a match
        return null;
    }

    /**
     * A <code>Comparator</code> that is used within this class to maintain
     * ordering amongst different versions of the same policy. Note that
     * it actually maintains reverse-ordering, since we want to traverse the
     * sets in decreasing, not increasing order.
     * <p>
     * Note that this comparator is only used when there are multiple versions
     * of the same policy, which in practice will probably happen far less
     * (from this class' point of view) than additions or fetches.
     */
    class VersionComparator implements Comparator {
        public int compare(Object o1, Object o2) {
            // we swap the parameters so that sorting goes largest to smallest
            String v1 = ((AbstractPolicy)o2).getVersion();
            String v2 = ((AbstractPolicy)o1).getVersion();

            // do a quick check to see if the strings are equal (note that
            // even if the strings aren't equal, the versions can still
            // be equal)
            if (v1.equals(v2))
                return 0;

            // setup tokenizers, and walk through both strings one set of
            // numeric values at a time
            StringTokenizer tok1 = new StringTokenizer(v1, ".");
            StringTokenizer tok2 = new StringTokenizer(v2, ".");

            while (tok1.hasMoreTokens()) {
                // if there's nothing left in tok2, then v1 is bigger
                if (! tok2.hasMoreTokens())
                    return 1;

                // get the next elements in the version, convert to numbers,
                // and compare them (continuing with the loop only if the
                // two values were equal)
                int num1 = Integer.parseInt(tok1.nextToken());
                int num2 = Integer.parseInt(tok2.nextToken());

                if (num1 > num2)
                    return 1;

                if (num1 < num2)
                    return -1;
            }

            // if there's still something left in tok2, then it's bigger
            if (tok2.hasMoreTokens())
                return -1;

            // if we got here it means both versions had the same number of
            // elements and all the elements were equal, so the versions
            // are in fact equal
            return 0;
        }
    }

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -