/**
   * Parse (unmarshal) a <code>PrincipalName</code> from a DER input stream. This form parsing might
   * be used when expanding a value which is part of a constructed sequence and uses explicitly
   * tagged type.
   *
   * @exception Asn1Exception on error.
   * @param data the Der input stream value, which contains one or more marshaled value.
   * @param explicitTag tag number.
   * @param optional indicate if this data field is optional
   * @param realm the realm for the name
   * @return an instance of <code>PrincipalName</code>, or null if the field is optional and
   *     missing.
   */
  public static PrincipalName parse(
      DerInputStream data, byte explicitTag, boolean optional, Realm realm)
      throws Asn1Exception, IOException, RealmException {

    if ((optional) && (((byte) data.peekByte() & (byte) 0x1F) != explicitTag)) return null;
    DerValue der = data.getDerValue();
    if (explicitTag != (der.getTag() & (byte) 0x1F)) {
      throw new Asn1Exception(Krb5.ASN1_BAD_ID);
    } else {
      DerValue subDer = der.getData().getDerValue();
      if (realm == null) {
        realm = Realm.getDefault();
      }
      return new PrincipalName(subDer, realm);
    }
  }
  /**
   * Constructs a PrincipalName from a string.
   *
   * @param name the name
   * @param type the type
   * @param realm the realm, null if not known. Note that when realm is not null, it will be always
   *     used even if there is a realm part in name. When realm is null, will read realm part from
   *     name, or try to map a realm (for KRB_NT_SRV_HST), or use the default realm, or fail
   * @throws RealmException
   */
  public PrincipalName(String name, int type, String realm) throws RealmException {
    if (name == null) {
      throw new IllegalArgumentException("Null name not allowed");
    }
    String[] nameParts = parseName(name);
    validateNameStrings(nameParts);
    if (realm == null) {
      realm = Realm.parseRealmAtSeparator(name);
    }
    switch (type) {
      case KRB_NT_SRV_HST:
        if (nameParts.length >= 2) {
          String hostName = nameParts[1];
          try {
            // RFC4120 does not recommend canonicalizing a hostname.
            // However, for compatibility reason, we will try
            // canonicalize it and see if the output looks better.

            String canonicalized = (InetAddress.getByName(hostName)).getCanonicalHostName();

            // Looks if canonicalized is a longer format of hostName,
            // we accept cases like
            //     bunny -> bunny.rabbit.hole
            if (canonicalized
                .toLowerCase(Locale.ENGLISH)
                .startsWith(hostName.toLowerCase(Locale.ENGLISH) + ".")) {
              hostName = canonicalized;
            }
          } catch (UnknownHostException e) {
            // no canonicalization, use old
          }
          nameParts[1] = hostName.toLowerCase(Locale.ENGLISH);
        }
        nameStrings = nameParts;
        nameType = type;

        if (realm != null) {
          nameRealm = new Realm(realm);
        } else {
          // We will try to get realm name from the mapping in
          // the configuration. If it is not specified
          // we will use the default realm. This nametype does
          // not allow a realm to be specified. The name string must of
          // the form service@host and this is internally changed into
          // service/host by Kerberos
          String mapRealm = mapHostToRealm(nameParts[1]);
          if (mapRealm != null) {
            nameRealm = new Realm(mapRealm);
          } else {
            nameRealm = Realm.getDefault();
          }
        }
        break;
      case KRB_NT_UNKNOWN:
      case KRB_NT_PRINCIPAL:
      case KRB_NT_SRV_INST:
      case KRB_NT_SRV_XHST:
      case KRB_NT_UID:
        nameStrings = nameParts;
        nameType = type;
        if (realm != null) {
          nameRealm = new Realm(realm);
        } else {
          nameRealm = Realm.getDefault();
        }
        break;
      default:
        throw new IllegalArgumentException("Illegal name type");
    }
  }
 public PrincipalName(String[] nameParts, int type)
     throws IllegalArgumentException, RealmException {
   this(type, nameParts, Realm.getDefault());
 }