private KerberosIdentityDescriptor dereferenceIdentity(KerberosIdentityDescriptor identity) throws AmbariException {
    KerberosIdentityDescriptor dereferencedIdentity = null;

    if (identity != null) {
      KerberosIdentityDescriptor referencedIdentity;
      try {
        if (identity.getReference() != null) {
          referencedIdentity = getReferencedIdentityDescriptor(identity.getReference());
        } else {
          // For backwards compatibility, see if the identity's name indicates a reference...
          referencedIdentity = getReferencedIdentityDescriptor(identity.getName());

          if(referencedIdentity != null) {
            // Log this since it is deprecated...
            LOG.warn("Referenced identities should be declared using the identity's \"reference\" attribute, not the identity's \"name\" attribute." +
                " This is a deprecated feature. Problems may occur in the future unless this is corrected: {}:{}", identity.getPath(), identity.getName());
          }
        }
      } catch (AmbariException e) {
        throw new AmbariException(String.format("Invalid Kerberos identity reference: %s", identity.getReference()), e);
      }

      if (referencedIdentity != null) {
        dereferencedIdentity = dereferenceIdentity(referencedIdentity);  // Dereference the "parent"...

        if (dereferencedIdentity != null) {
          dereferencedIdentity.update(identity);
        } else {
          dereferencedIdentity = new KerberosIdentityDescriptor(referencedIdentity.toMap());
          dereferencedIdentity.update(identity);
        }
      } else {
        dereferencedIdentity = new KerberosIdentityDescriptor(identity.toMap());
      }

      // Force the path for this identity descriptor to be the same as the original identity descriptor's.
      dereferencedIdentity.setPath(identity.getPath());
    }

    return dereferencedIdentity;
  }
Recursively dereference a referenced identity.
<p>
Follows the path of references such that the top-most identity definition (one with no pointer
to a referenced identity) contains the base  information which is copied and updated with the
referencing identity's data. The composite identity is then update with the next referencing
identity's data, and so on until the initial identity is encountered.

@param identity the initial identity to dereference
@return a (disconnected) {@link KerberosIdentityDescriptor} built by traversing the identity
references; or the input identity if it does not reference any other identities.
@throws AmbariException
ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptorContainer.java