/*
 * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.security.provider.certpath;

import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import java.security.cert.*;

Implements the PolicyNode interface.

This class provides an implementation of the PolicyNode interface, and is used internally to build and search Policy Trees. While the implementation is mutable during construction, it is immutable before returning to a client and no mutable public or protected methods are exposed by this implementation, as per the contract of PolicyNode.

Author: Seth Proctor, Sean Mullan
Since: 1.4
/** * Implements the <code>PolicyNode</code> interface. * <p> * This class provides an implementation of the <code>PolicyNode</code> * interface, and is used internally to build and search Policy Trees. * While the implementation is mutable during construction, it is immutable * before returning to a client and no mutable public or protected methods * are exposed by this implementation, as per the contract of PolicyNode. * * @since 1.4 * @author Seth Proctor * @author Sean Mullan */
final class PolicyNodeImpl implements PolicyNode {
Use to specify the special policy "Any Policy"
/** * Use to specify the special policy "Any Policy" */
private static final String ANY_POLICY = "2.5.29.32.0"; // every node has one parent, and zero or more children private PolicyNodeImpl mParent; private HashSet<PolicyNodeImpl> mChildren; // the 4 fields specified by RFC 5280 private String mValidPolicy; private HashSet<PolicyQualifierInfo> mQualifierSet; private boolean mCriticalityIndicator; private HashSet<String> mExpectedPolicySet; private boolean mOriginalExpectedPolicySet; // the tree depth private int mDepth; // immutability flag private boolean isImmutable = false;
Constructor which takes a PolicyNodeImpl representing the parent in the Policy Tree to this node. If null, this is the root of the tree. The constructor also takes the associated data for this node, as found in the certificate. It also takes a boolean argument specifying whether this node is being created as a result of policy mapping.
Params:
  • parent – the PolicyNode above this in the tree, or null if this node is the tree's root node
  • validPolicy – a String representing this node's valid policy OID
  • qualifierSet – the Set of qualifiers for this policy
  • criticalityIndicator – a boolean representing whether or not the extension is critical
  • expectedPolicySet – a Set of expected policies
  • generatedByPolicyMapping – a boolean indicating whether this node was generated by a policy mapping
/** * Constructor which takes a <code>PolicyNodeImpl</code> representing the * parent in the Policy Tree to this node. If null, this is the * root of the tree. The constructor also takes the associated data * for this node, as found in the certificate. It also takes a boolean * argument specifying whether this node is being created as a result * of policy mapping. * * @param parent the PolicyNode above this in the tree, or null if this * node is the tree's root node * @param validPolicy a String representing this node's valid policy OID * @param qualifierSet the Set of qualifiers for this policy * @param criticalityIndicator a boolean representing whether or not the * extension is critical * @param expectedPolicySet a Set of expected policies * @param generatedByPolicyMapping a boolean indicating whether this * node was generated by a policy mapping */
PolicyNodeImpl(PolicyNodeImpl parent, String validPolicy, Set<PolicyQualifierInfo> qualifierSet, boolean criticalityIndicator, Set<String> expectedPolicySet, boolean generatedByPolicyMapping) { mParent = parent; mChildren = new HashSet<PolicyNodeImpl>(); if (validPolicy != null) mValidPolicy = validPolicy; else mValidPolicy = ""; if (qualifierSet != null) mQualifierSet = new HashSet<PolicyQualifierInfo>(qualifierSet); else mQualifierSet = new HashSet<PolicyQualifierInfo>(); mCriticalityIndicator = criticalityIndicator; if (expectedPolicySet != null) mExpectedPolicySet = new HashSet<String>(expectedPolicySet); else mExpectedPolicySet = new HashSet<String>(); mOriginalExpectedPolicySet = !generatedByPolicyMapping; // see if we're the root, and act appropriately if (mParent != null) { mDepth = mParent.getDepth() + 1; mParent.addChild(this); } else { mDepth = 0; } }
Alternate constructor which makes a new node with the policy data in an existing PolicyNodeImpl.
Params:
  • parent – a PolicyNode that's the new parent of the node, or null if this is the root node
  • node – a PolicyNode containing the policy data to copy
/** * Alternate constructor which makes a new node with the policy data * in an existing <code>PolicyNodeImpl</code>. * * @param parent a PolicyNode that's the new parent of the node, or * null if this is the root node * @param node a PolicyNode containing the policy data to copy */
PolicyNodeImpl(PolicyNodeImpl parent, PolicyNodeImpl node) { this(parent, node.mValidPolicy, node.mQualifierSet, node.mCriticalityIndicator, node.mExpectedPolicySet, false); } @Override public PolicyNode getParent() { return mParent; } @Override public Iterator<PolicyNodeImpl> getChildren() { return Collections.unmodifiableSet(mChildren).iterator(); } @Override public int getDepth() { return mDepth; } @Override public String getValidPolicy() { return mValidPolicy; } @Override public Set<PolicyQualifierInfo> getPolicyQualifiers() { return Collections.unmodifiableSet(mQualifierSet); } @Override public Set<String> getExpectedPolicies() { return Collections.unmodifiableSet(mExpectedPolicySet); } @Override public boolean isCritical() { return mCriticalityIndicator; }
Return a printable representation of the PolicyNode. Starting at the node on which this method is called, it recurses through the tree and prints out each node.
Returns:a String describing the contents of the Policy Node
/** * Return a printable representation of the PolicyNode. * Starting at the node on which this method is called, * it recurses through the tree and prints out each node. * * @return a String describing the contents of the Policy Node */
@Override public String toString() { StringBuilder buffer = new StringBuilder(this.asString()); for (PolicyNodeImpl node : mChildren) { buffer.append(node); } return buffer.toString(); } // private methods and package private operations boolean isImmutable() { return isImmutable; }
Sets the immutability flag of this node and all of its children to true.
/** * Sets the immutability flag of this node and all of its children * to true. */
void setImmutable() { if (isImmutable) return; for (PolicyNodeImpl node : mChildren) { node.setImmutable(); } isImmutable = true; }
Private method sets a child node. This is called from the child's constructor.
Params:
  • child – new PolicyNodeImpl child node
/** * Private method sets a child node. This is called from the child's * constructor. * * @param child new <code>PolicyNodeImpl</code> child node */
private void addChild(PolicyNodeImpl child) { if (isImmutable) { throw new IllegalStateException("PolicyNode is immutable"); } mChildren.add(child); }
Adds an expectedPolicy to the expected policy set. If this is the original expected policy set initialized by the constructor, then the expected policy set is cleared before the expected policy is added.
Params:
  • expectedPolicy – a String representing an expected policy.
/** * Adds an expectedPolicy to the expected policy set. * If this is the original expected policy set initialized * by the constructor, then the expected policy set is cleared * before the expected policy is added. * * @param expectedPolicy a String representing an expected policy. */
void addExpectedPolicy(String expectedPolicy) { if (isImmutable) { throw new IllegalStateException("PolicyNode is immutable"); } if (mOriginalExpectedPolicySet) { mExpectedPolicySet.clear(); mOriginalExpectedPolicySet = false; } mExpectedPolicySet.add(expectedPolicy); }
Removes all paths which don't reach the specified depth.
Params:
  • depth – an int representing the desired minimum depth of all paths
/** * Removes all paths which don't reach the specified depth. * * @param depth an int representing the desired minimum depth of all paths */
void prune(int depth) { if (isImmutable) throw new IllegalStateException("PolicyNode is immutable"); // if we have no children, we can't prune below us... if (mChildren.size() == 0) return; Iterator<PolicyNodeImpl> it = mChildren.iterator(); while (it.hasNext()) { PolicyNodeImpl node = it.next(); node.prune(depth); // now that we've called prune on the child, see if we should // remove it from the tree if ((node.mChildren.size() == 0) && (depth > mDepth + 1)) it.remove(); } }
Deletes the specified child node of this node, if it exists.
Params:
  • childNode – the child node to be deleted
/** * Deletes the specified child node of this node, if it exists. * * @param childNode the child node to be deleted */
void deleteChild(PolicyNode childNode) { if (isImmutable) { throw new IllegalStateException("PolicyNode is immutable"); } mChildren.remove(childNode); }
Returns a copy of the tree, without copying the policy-related data, rooted at the node on which this was called.
Returns:a copy of the tree
/** * Returns a copy of the tree, without copying the policy-related data, * rooted at the node on which this was called. * * @return a copy of the tree */
PolicyNodeImpl copyTree() { return copyTree(null); } private PolicyNodeImpl copyTree(PolicyNodeImpl parent) { PolicyNodeImpl newNode = new PolicyNodeImpl(parent, this); for (PolicyNodeImpl node : mChildren) { node.copyTree(newNode); } return newNode; }
Returns all nodes at the specified depth in the tree.
Params:
  • depth – an int representing the depth of the desired nodes
Returns:a Set of all nodes at the specified depth
/** * Returns all nodes at the specified depth in the tree. * * @param depth an int representing the depth of the desired nodes * @return a <code>Set</code> of all nodes at the specified depth */
Set<PolicyNodeImpl> getPolicyNodes(int depth) { Set<PolicyNodeImpl> set = new HashSet<>(); getPolicyNodes(depth, set); return set; }
Add all nodes at depth depth to set and return the Set. Internal recursion helper.
/** * Add all nodes at depth depth to set and return the Set. * Internal recursion helper. */
private void getPolicyNodes(int depth, Set<PolicyNodeImpl> set) { // if we've reached the desired depth, then return ourself if (mDepth == depth) { set.add(this); } else { for (PolicyNodeImpl node : mChildren) { node.getPolicyNodes(depth, set); } } }
Finds all nodes at the specified depth whose expected_policy_set contains the specified expected OID (if matchAny is false) or the special OID "any value" (if matchAny is true).
Params:
  • depth – an int representing the desired depth
  • expectedOID – a String encoding the valid OID to match
  • matchAny – a boolean indicating whether an expected_policy_set containing ANY_POLICY should be considered a match
Returns:a Set of matched PolicyNodes
/** * Finds all nodes at the specified depth whose expected_policy_set * contains the specified expected OID (if matchAny is false) * or the special OID "any value" (if matchAny is true). * * @param depth an int representing the desired depth * @param expectedOID a String encoding the valid OID to match * @param matchAny a boolean indicating whether an expected_policy_set * containing ANY_POLICY should be considered a match * @return a Set of matched <code>PolicyNode</code>s */
Set<PolicyNodeImpl> getPolicyNodesExpected(int depth, String expectedOID, boolean matchAny) { if (expectedOID.equals(ANY_POLICY)) { return getPolicyNodes(depth); } else { return getPolicyNodesExpectedHelper(depth, expectedOID, matchAny); } } private Set<PolicyNodeImpl> getPolicyNodesExpectedHelper(int depth, String expectedOID, boolean matchAny) { HashSet<PolicyNodeImpl> set = new HashSet<>(); if (mDepth < depth) { for (PolicyNodeImpl node : mChildren) { set.addAll(node.getPolicyNodesExpectedHelper(depth, expectedOID, matchAny)); } } else { if (matchAny) { if (mExpectedPolicySet.contains(ANY_POLICY)) set.add(this); } else { if (mExpectedPolicySet.contains(expectedOID)) set.add(this); } } return set; }
Finds all nodes at the specified depth that contains the specified valid OID
Params:
  • depth – an int representing the desired depth
  • validOID – a String encoding the valid OID to match
Returns:a Set of matched PolicyNodes
/** * Finds all nodes at the specified depth that contains the * specified valid OID * * @param depth an int representing the desired depth * @param validOID a String encoding the valid OID to match * @return a Set of matched <code>PolicyNode</code>s */
Set<PolicyNodeImpl> getPolicyNodesValid(int depth, String validOID) { HashSet<PolicyNodeImpl> set = new HashSet<>(); if (mDepth < depth) { for (PolicyNodeImpl node : mChildren) { set.addAll(node.getPolicyNodesValid(depth, validOID)); } } else { if (mValidPolicy.equals(validOID)) set.add(this); } return set; } private static String policyToString(String oid) { if (oid.equals(ANY_POLICY)) { return "anyPolicy"; } else { return oid; } }
Prints out some data on this node.
/** * Prints out some data on this node. */
String asString() { if (mParent == null) { return "anyPolicy ROOT\n"; } else { StringBuilder sb = new StringBuilder(); for (int i = 0, n = getDepth(); i < n; i++) { sb.append(" "); } sb.append(policyToString(getValidPolicy())); sb.append(" CRIT: "); sb.append(isCritical()); sb.append(" EP: "); for (String policy : getExpectedPolicies()) { sb.append(policyToString(policy)); sb.append(" "); } sb.append(" ("); sb.append(getDepth()); sb.append(")\n"); return sb.toString(); } } }