gt:         String thisCanonical = this.getRFC2253CanonicalName();
context: /*
   * Copyright (C) 2014 The Android Open Source Project
   * Copyright (c) 1996, 2006, 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.x509;
  
  import java.lang.reflect.*;
  import java.io.IOException;
  import java.io.StringReader;
  import java.security.PrivilegedExceptionAction;
  import java.security.AccessController;
  import java.security.Principal;
  import java.util.*;
  
  import sun.security.util.*;
  import sun.security.pkcs.PKCS9Attribute;
  import javax.security.auth.x500.X500Principal;
  
  /**
   * Note:  As of 1.4, the public class,
   * javax.security.auth.x500.X500Principal,
   * should be used when parsing, generating, and comparing X.500 DNs.
   * This class contains other useful methods for checking name constraints
   * and retrieving DNs by keyword.
   *
   * <p> X.500 names are used to identify entities, such as those which are
   * identified by X.509 certificates.  They are world-wide, hierarchical,
   * and descriptive.  Entities can be identified by attributes, and in
   * some systems can be searched for according to those attributes.
   * <p>
   * The ASN.1 for this is:
   * <pre>
   * GeneralName ::= CHOICE {
   * ....
   *     directoryName                   [4]     Name,
   * ....
   * Name ::= CHOICE {
   *   RDNSequence }
   *
   * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
   *
   * RelativeDistinguishedName ::=
   *   SET OF AttributeTypeAndValue
   *
   * AttributeTypeAndValue ::= SEQUENCE {
   *   type     AttributeType,
   *   value    AttributeValue }
   *
   * AttributeType ::= OBJECT IDENTIFIER
   *
   * AttributeValue ::= ANY DEFINED BY AttributeType
   * ....
   * DirectoryString ::= CHOICE {
   *       teletexString           TeletexString (SIZE (1..MAX)),
   *       printableString         PrintableString (SIZE (1..MAX)),
   *       universalString         UniversalString (SIZE (1..MAX)),
   *       utf8String              UTF8String (SIZE (1.. MAX)),
   *       bmpString               BMPString (SIZE (1..MAX)) }
   * </pre>
   * <p>
   * This specification requires only a subset of the name comparison
   * functionality specified in the X.500 series of specifications.  The
   * requirements for conforming implementations are as follows:
   * <ol TYPE=a>
   * <li>attribute values encoded in different types (e.g.,
   *    PrintableString and BMPString) may be assumed to represent
   *    different strings;
   * <p>
   * <li>attribute values in types other than PrintableString are case
   *    sensitive (this permits matching of attribute values as binary
   *    objects);
   * <p>
   * <li>attribute values in PrintableString are not case sensitive
   *    (e.g., "Marianne Swanson" is the same as "MARIANNE SWANSON"); and
   * <p>
   * <li>attribute values in PrintableString are compared after
   *    removing leading and trailing white space and converting internal
   *    substrings of one or more consecutive white space characters to a
   *    single space.
   * </ol>
   * <p>
   * These name comparison rules permit a certificate user to validate
   * certificates issued using languages or encodings unfamiliar to the
   * certificate user.
   * <p>
   * In addition, implementations of this specification MAY use these
   * comparison rules to process unfamiliar attribute types for name
   * chaining. This allows implementations to process certificates with
   * unfamiliar attributes in the issuer name.
   * <p>
   * Note that the comparison rules defined in the X.500 series of
   * specifications indicate that the character sets used to encode data
   * in distinguished names are irrelevant.  The characters themselves are
   * compared without regard to encoding. Implementations of the profile
   * are permitted to use the comparison algorithm defined in the X.500
   * series.  Such an implementation will recognize a superset of name
   * matches recognized by the algorithm specified above.
   * <p>
   * Note that instances of this class are immutable.
   *
   * @author David Brownell
   * @author Amit Kapoor
   * @author Hemma Prafullchandra
   * @see GeneralName
   * @see GeneralNames
   * @see GeneralNameInterface
   */
  
  public class X500Name implements GeneralNameInterface, Principal {
  
      private String dn; // roughly RFC 1779 DN, or null
      private String rfc1779Dn; // RFC 1779 compliant DN, or null
      private String rfc2253Dn; // RFC 2253 DN, or null
      private String canonicalDn; // canonical RFC 2253 DN or null
      private RDN[] names;        // RDNs (never null)
      private X500Principal x500Principal;
      private byte[] encoded;
  
      // cached immutable list of the RDNs and all the AVAs
      private volatile List<RDN> rdnList;
      private volatile List<AVA> allAvaList;
  
      /**
       * Constructs a name from a conventionally formatted string, such
       * as "CN=Dave, OU=JavaSoft, O=Sun Microsystems, C=US".
       * (RFC 1779 or RFC 2253 style).
       *
       * @param DN X.500 Distinguished Name
       */
      public X500Name(String dname) throws IOException {
          this(dname, Collections.<String, String>emptyMap());
      }
  
      /**
       * Constructs a name from a conventionally formatted string, such
       * as "CN=Dave, OU=JavaSoft, O=Sun Microsystems, C=US".
       * (RFC 1779 or RFC 2253 style).
       *
       * @param DN X.500 Distinguished Name
       * @param keywordMap an additional keyword/OID map
       */
      public X500Name(String dname, Map<String, String> keywordMap)
          throws IOException {
          parseDN(dname, keywordMap);
      }
  
      /**
       * Constructs a name from a string formatted according to format.
       * Currently, the formats DEFAULT and RFC2253 are supported.
       * DEFAULT is the default format used by the X500Name(String)
       * constructor. RFC2253 is format strictly according to RFC2253
       * without extensions.
       *
       * @param DN X.500 Distinguished Name
       */
      public X500Name(String dname, String format) throws IOException {
          if (dname == null) {
              throw new NullPointerException("Name must not be null");
          }
          if (format.equalsIgnoreCase("RFC2253")) {
              parseRFC2253DN(dname);
          } else if (format.equalsIgnoreCase("DEFAULT")) {
              parseDN(dname, Collections.<String, String>emptyMap());
          } else {
              throw new IOException("Unsupported format " + format);
          }
      }
  
      /**
       * Constructs a name from fields common in enterprise application
       * environments.
       *
       * <P><EM><STRONG>NOTE:</STRONG>  The behaviour when any of
       * these strings contain characters outside the ASCII range
       * is unspecified in currently relevant standards.</EM>
       *
       * @param commonName common name of a person, e.g. "Vivette Davis"
       * @param organizationUnit small organization name, e.g. "Purchasing"
       * @param organizationName large organization name, e.g. "Onizuka, Inc."
       * @param country two letter country code, e.g. "CH"
       */
      public X500Name(String commonName, String organizationUnit,
                       String organizationName, String country)
      throws IOException {
          names = new RDN[4];
          /*
           * NOTE:  it's only on output that little-endian
           * ordering is used.
           */
          names[3] = new RDN(1);
          names[3].assertion[0] = new AVA(commonName_oid,
                  new DerValue(commonName));
          names[2] = new RDN(1);
          names[2].assertion[0] = new AVA(orgUnitName_oid,
                  new DerValue(organizationUnit));
          names[1] = new RDN(1);
          names[1].assertion[0] = new AVA(orgName_oid,
                  new DerValue(organizationName));
          names[0] = new RDN(1);
          names[0].assertion[0] = new AVA(countryName_oid,
                  new DerValue(country));
      }
  
      /**
       * Constructs a name from fields common in Internet application
       * environments.
       *
       * <P><EM><STRONG>NOTE:</STRONG>  The behaviour when any of
       * these strings contain characters outside the ASCII range
       * is unspecified in currently relevant standards.</EM>
       *
       * @param commonName common name of a person, e.g. "Vivette Davis"
       * @param organizationUnit small organization name, e.g. "Purchasing"
       * @param organizationName large organization name, e.g. "Onizuka, Inc."
       * @param localityName locality (city) name, e.g. "Palo Alto"
       * @param stateName state name, e.g. "California"
       * @param country two letter country code, e.g. "CH"
       */
      public X500Name(String commonName, String organizationUnit,
                      String organizationName, String localityName,
                      String stateName, String country)
      throws IOException {
          names = new RDN[6];
          /*
           * NOTE:  it's only on output that little-endian
           * ordering is used.
           */
          names[5] = new RDN(1);
          names[5].assertion[0] = new AVA(commonName_oid,
                  new DerValue(commonName));
          names[4] = new RDN(1);
          names[4].assertion[0] = new AVA(orgUnitName_oid,
                  new DerValue(organizationUnit));
          names[3] = new RDN(1);
          names[3].assertion[0] = new AVA(orgName_oid,
                  new DerValue(organizationName));
          names[2] = new RDN(1);
          names[2].assertion[0] = new AVA(localityName_oid,
                  new DerValue(localityName));
          names[1] = new RDN(1);
          names[1].assertion[0] = new AVA(stateName_oid,
                  new DerValue(stateName));
          names[0] = new RDN(1);
          names[0].assertion[0] = new AVA(countryName_oid,
                  new DerValue(country));
      }
  
      /**
       * Constructs a name from an array of relative distinguished names
       *
       * @param rdnArray array of relative distinguished names
       * @throws IOException on error
       */
      public X500Name(RDN[] rdnArray) throws IOException {
          if (rdnArray == null) {
              names = new RDN[0];
          } else {
              names = rdnArray.clone();
              for (int i = 0; i < names.length; i++) {
                  if (names[i] == null) {
                      throw new IOException("Cannot create an X500Name");
                  }
              }
          }
      }
  
      /**
       * Constructs a name from an ASN.1 encoded value.  The encoding
       * of the name in the stream uses DER (a BER/1 subset).
       *
       * @param value a DER-encoded value holding an X.500 name.
       */
      public X500Name(DerValue value) throws IOException {
          //Note that toDerInputStream uses only the buffer (data) and not
          //the tag, so an empty SEQUENCE (OF) will yield an empty DerInputStream
          this(value.toDerInputStream());
      }
  
      /**
       * Constructs a name from an ASN.1 encoded input stream.  The encoding
       * of the name in the stream uses DER (a BER/1 subset).
       *
       * @param in DER-encoded data holding an X.500 name.
       */
      public X500Name(DerInputStream in) throws IOException {
          parseDER(in);
      }
  
      /**
       *  Constructs a name from an ASN.1 encoded byte array.
       *
       * @param name DER-encoded byte array holding an X.500 name.
       */
      public X500Name(byte[] name) throws IOException {
          DerInputStream in = new DerInputStream(name);
          parseDER(in);
      }
  
      /**
       * Return an immutable List of all RDNs in this X500Name.
       */
      public List<RDN> rdns() {
          List<RDN> list = rdnList;
          if (list == null) {
              list = Collections.unmodifiableList(Arrays.asList(names));
              rdnList = list;
          }
          return list;
      }
  
      /**
       * Return the number of RDNs in this X500Name.
       */
      public int size() {
          return names.length;
      }
  
      /**
       * Return an immutable List of the the AVAs contained in all the
       * RDNs of this X500Name.
       */
      public List<AVA> allAvas() {
          List<AVA> list = allAvaList;
          if (list == null) {
              list = new ArrayList<AVA>();
              for (int i = 0; i < names.length; i++) {
                  list.addAll(names[i].avas());
              }
          }
          return list;
      }
  
      /**
       * Return the total number of AVAs contained in all the RDNs of
       * this X500Name.
       */
      public int avaSize() {
          return allAvas().size();
      }
  
      /**
       * Return whether this X500Name is empty. An X500Name is not empty
       * if it has at least one RDN containing at least one AVA.
       */
      public boolean isEmpty() {
          int n = names.length;
          if (n == 0) {
              return true;
          }
          for (int i = 0; i < n; i++) {
              if (names[i].assertion.length != 0) {
                  return false;
              }
          }
          return true;
      }
  
      /**
       * Calculates a hash code value for the object.  Objects
       * which are equal will also have the same hashcode.
       */
      public int hashCode() {
          return getRFC2253CanonicalName().hashCode();
      }
  
      /**
       * Compares this name with another, for equality.
       *
       * @return true iff the names are identical.
       */
      public boolean equals(Object obj) {
          if (this == obj) {
              return true;
          }
          if (obj instanceof X500Name == false) {
              return false;
          }
          X500Name other = (X500Name)obj;
          // if we already have the canonical forms, compare now
          if ((this.canonicalDn != null) && (other.canonicalDn != null)) {
              return this.canonicalDn.equals(other.canonicalDn);
          }
          // quick check that number of RDNs and AVAs match before canonicalizing
          int n = this.names.length;
          if (n != other.names.length) {
              return false;
          }
          for (int i = 0; i < n; i++) {
              RDN r1 = this.names[i];
              RDN r2 = other.names[i];
              if (r1.assertion.length != r2.assertion.length) {
                  return false;
              }
          }
          // definite check via canonical form
  