// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.enterprise.adaptor;

import com.google.common.collect.Sets;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Immutable access control list. For description of the semantics of the
 * various fields, see {@link #isAuthorizedLocal isAuthorizedLocal} and
 * {@link #isAuthorized isAuthorized}. Users and groups must not be {@code
 * null}, {@code ""}, or have surrounding whitespace. These values are
 * disallowed to prevent confusion since {@code null} doesn't make sense, {@code
 * ""} would be ignored by the GSA, and surrounding whitespace is automatically
 * trimmed by the GSA.
 */
public class Acl {
  /**
   * Empty convenience instance with all defaults used.
   *
   * @see Builder#Acl.Builder()
   */
  public static final Acl EMPTY = new Acl.Builder().build();
  /**
   * An almost-empty ACL that can be used instead of {@link #EMPTY} when sending
   * ACLs to the GSA. This allows the GSA to distinguish between an empty ACL
   * and a non-existant ACL.
   */
  static final Acl FAKE_EMPTY = new Acl.Builder()
      .setDenyUsers(Arrays.asList(
          new UserPrincipal("google:fakeUserToPreventMissingAcl")))
      .build();

  private static final Logger log = Logger.getLogger(Acl.class.getName());

  /** Locale used for case insensitivity related operations. */
  private static final Locale CASE_LOCALE = Locale.ENGLISH;

  private final Set<GroupPrincipal> permitGroups;
  private final Set<GroupPrincipal> denyGroups;
  private final Set<UserPrincipal> permitUsers;
  private final Set<UserPrincipal> denyUsers;
  private final DocId inheritFrom;
  private final String inheritFromFragment;
  private final InheritanceType inheritType;
  private final boolean caseSensitive;

  private Acl(Set<GroupPrincipal> permitGroups, Set<GroupPrincipal> denyGroups,
      Set<UserPrincipal> permitUsers, Set<UserPrincipal> denyUsers,
      DocId inheritFrom, String inheritFromFragment,
      InheritanceType inheritType, boolean caseSensitive) {
    if (!caseSensitive) {
      permitGroups = Collections.unmodifiableSet(cmpWrap(permitGroups));
      denyGroups = Collections.unmodifiableSet(cmpWrap(denyGroups));
      permitUsers = Collections.unmodifiableSet(cmpWrap(permitUsers));
      denyUsers = Collections.unmodifiableSet(cmpWrap(denyUsers));
    }
    this.permitGroups = permitGroups;
    this.denyGroups = denyGroups;
    this.permitUsers = permitUsers;
    this.denyUsers = denyUsers;
    this.inheritFrom = inheritFrom;
    this.inheritFromFragment = inheritFromFragment;
    this.inheritType = inheritType;
    this.caseSensitive = caseSensitive;
  }

  private <P extends Principal> Set<P> cmpWrap(Set<P> unwrapped) {
    Set<P> tmp = new TreeSet<P>(new CaseInsensitiveCmp<P>());
    tmp.addAll(unwrapped);
    return tmp;
  }

  private static class CaseInsensitiveCmp<P extends Principal>
      implements Comparator<P> {
    /** Does not differentiate between UserPrincipal and GroupPrincipal */
    public int compare(P p1, P p2) {
      String ns1 = p1.getNamespace().toLowerCase(CASE_LOCALE);
      String ns2 = p2.getNamespace().toLowerCase(CASE_LOCALE);
      int nscmp = ns1.compareTo(ns2);
      if (0 != nscmp) {
        return nscmp;
      }
      // OK, same namespace
 
      String n1 = p1.getName().toLowerCase(CASE_LOCALE);
      String n2 = p2.getName().toLowerCase(CASE_LOCALE);
      return n1.compareTo(n2);
    }

    public boolean equals(Object o) {
      return o instanceof CaseInsensitiveCmp;
    }
  }

  /**
   * Returns immutable set of permitted groups.
   */
  public Set<GroupPrincipal> getPermitGroups() {
    return permitGroups;
  }

  /**
   * Returns immutable set of denied groups.
   */
  public Set<GroupPrincipal> getDenyGroups() {
    return denyGroups;
  }

  /**
   * Returns immutable set of permitted users.
   */
  public Set<UserPrincipal> getPermitUsers() {
    return permitUsers;
  }

  /**
   * Returns immutable set of denied users.
   */
  public Set<UserPrincipal> getDenyUsers() {
    return denyUsers;
  }

  /**
   * Returns immutable set of permitted users and groups.
   */
  public Set<Principal> getPermits() {
    return Sets.union(permitUsers, permitGroups);
  }

  /**
   * Returns immutable set of denied users and groups;
   */
  public Set<Principal> getDenies() {
    return Sets.union(denyUsers, denyGroups);
  }

  /**
   * Returns {@code DocId} these ACLs are inherited from. This is also known as
   * the "parent's" ACLs. Note that the parent's {@code InheritanceType}
   * determines how to combine results with this ACL.
   *
   * @see #getInheritanceType
   */
  public DocId getInheritFrom() {
    return inheritFrom;
  }

  /**
   * Returns fragment, if there is one, that specifies which of the parent's
   * ACLs is to to be inhertied from.
   *
   * @see #getInheritanceType
   */
  public String getInheritFromFragment() {
    return inheritFromFragment;
  }

  /**
   * Returns the inheritance type used to combine authz decisions of these ACLs
   * with its <em>child</em>. The inheritance type applies to the interaction
   * between this ACL and any <em>children</em> it has.
   *
   * @see #getInheritFrom
   */
  public InheritanceType getInheritanceType() {
    return inheritType;
  }

  /**
   * Says whether letter casing differentiates names during authorization.
   */
  public boolean isEverythingCaseSensitive() {
    return caseSensitive;
  }

  /**
   * Says whether letter casing doesn't matter during authorization.
   */
  public boolean isEverythingCaseInsensitive() {
    return !caseSensitive;
  }

  /**
   * Determine if the provided {@code userIdentifier} belonging to {@code
   * groups} is authorized, ignoring inheritance. Deny trumps permit,
   * independent of how specific the rule is. So if a user is in permitUsers and
   * one of the user's groups is in denyGroups, that user will be denied. If a
   * user and his groups are unspecified in the ACL, then the response is
   * indeterminate.
   */
  public AuthzStatus isAuthorizedLocal(AuthnIdentity userIdentity) {
    UserPrincipal userIdentifier = userIdentity.getUser();
    Set<GroupPrincipal> commonGroups;
    if (caseSensitive) {
      commonGroups = new HashSet<GroupPrincipal>(denyGroups);
    } else {
      commonGroups = cmpWrap(denyGroups);
    }

    Set<GroupPrincipal> userGroups = userIdentity.getGroups();
    if (!caseSensitive) {
      userGroups = Collections.unmodifiableSet(cmpWrap(userGroups));
    }

    commonGroups.retainAll(userGroups);
    if (denyUsers.contains(userIdentifier) || !commonGroups.isEmpty()) {
      return AuthzStatus.DENY;
    }

    commonGroups.clear();
    commonGroups.addAll(permitGroups);
    commonGroups.retainAll(userGroups);
    if (permitUsers.contains(userIdentifier) || !commonGroups.isEmpty()) {
      return AuthzStatus.PERMIT;
    }

    return AuthzStatus.INDETERMINATE;
  }

  /**
   * Determine if the provided {@code userIdentity} belonging to {@code
   * groups} is authorized for the provided {@code aclChain}. The chain should
   * be in order of root to leaf; that means that the particular file or folder
   * you are checking for authz will be at the end of the chain.
   *
   * <p>If you have an ACL and wish to determine if a user is authorized, you
   * should manually generate an aclChain by recursively retrieving the ACLs of
   * the {@code inheritFrom} {@link DocId}. The ACL you started with should be
   * at the end of the chain. Alternatively, you can use {@link
   * #isAuthorizedBatch isAuthorizedBatch()}.
   *
   * <p>If the entire chain has empty permit/deny sets, then the result is
   * {@link AuthzStatus#INDETERMINATE}.
   *
   * <p>The result of the entire chain is the non-local decision of the root.
   * The non-local decision of any entry in the chain is the local decision of
   * that entry (as calculated with {@link #isAuthorizedLocal
   * isAuthorizedLocal()}) combined with the non-local decision of the next
   * entry in the chain via the {@code InheritanceType} of the original entry.
   * To repeat, the non-local decision of an entry is that entry's local
   * decision combined using its {@code InheritanceType} with its child's
   * non-local decision (which is recursive). Thus, if the root's inheritance
   * type is {@link InheritanceType#PARENT_OVERRIDES} and its local decision is
   * {@link AuthzStatus#DENY}, then independent of any decendant's local
   * decision, the decision of the chain will be {@code DENY}.
   *
   * <p>It should also be noted that the leaf's inheritance type does not matter
   * and is ignored.
   *
   * <p>It is very important to note that a completely empty ACL (one that has
   * all defaults) is equivalent to having no ACLs. The GSA considers content
   * from the Adaptor as public unless it provides an ACL. Thus, empty ACLs
   * cause a document to become public and the GSA does not use ACLs when
   * considering public documents (and all results are PERMIT). However, for
   * non-Adaptor situations, you can get a document to be private and have no
   * ACLs. In these situations the ACLs are checked, but the result is
   * INDETERMINATE and different authz checks must be made.
   *
   * @param userIdentity identity containing the user's username and all the
   *     groups the user belongs to
   * @param aclChain ordered list of ACLs from root to leaf
   * @throws IllegalArgumentException if the chain is empty, the first element
   *     of the chain's {@code getInheritFrom() != null}, or if any element but
   *     the first has {@code getInheritFrom() == null}.
   * @see #isAuthorizedLocal
   * @see InheritanceType
   */
  public static AuthzStatus isAuthorized(AuthnIdentity userIdentity,
                                         List<Acl> aclChain) {
    // Check for completely broken chains. Users of the API should be aware
    // enough to easily prevent these from happening. These also don't directly
    // relate to a case on the GSA because the GSA is working more on the
    // isAuthorizedRecurse level.
    if (aclChain.size() < 1) {
      throw new IllegalArgumentException(
          "aclChain must contain at least one ACL");
    }
    if (aclChain.get(0).getInheritFrom() != null) {
      throw new IllegalArgumentException(
          "Chain must start at the root, which must not have an inheritFrom");
    }
    for (int i = 1; i < aclChain.size(); i++) {
      if (aclChain.get(i).getInheritFrom() == null) {
        throw new IllegalArgumentException(
            "Each ACL in the chain except the first should have an "
            + "inheritFrom");
      }
    }

    // Check for broken chain constructions. These don't throw an exception to
    // 1) match the GSA's identical handling of these situations and 2) because
    // we don't want to throw an exception if the caller can't easily prevent
    // it from ever occuring.
    if (aclChain.size() == 1) {
      Acl acl = aclChain.get(0);
      if (acl.equals(EMPTY)) {
        log.log(Level.FINE, "Chain only has one ACL and it is empty. This "
            + "implies 'no ACLs.'");
        return AuthzStatus.INDETERMINATE;
      }
    }
    for (int i = 0; i < aclChain.size() - 1; i++) {
      if (aclChain.get(i).getInheritanceType() == InheritanceType.LEAF_NODE) {
        log.log(Level.WARNING, "Only the last ACL in a chain can have the "
            + "inheritance type LEAF");
        return AuthzStatus.INDETERMINATE;
      }
    }
    AuthzStatus result = isAuthorizedRecurse(userIdentity, aclChain);
    return (result == AuthzStatus.INDETERMINATE) ? AuthzStatus.DENY : result;
  }

  private static AuthzStatus isAuthorizedRecurse(
      final AuthnIdentity userIdentity, final List<Acl> aclChain) {
    if (aclChain.size() == 1) {
      return aclChain.get(0).isAuthorizedLocal(userIdentity);
    }
    Decision parentDecision = new Decision() {
      @Override
      protected AuthzStatus computeDecision() {
        return aclChain.get(0).isAuthorizedLocal(userIdentity);
      }
    };
    Decision childDecision = new Decision() {
      @Override
      protected AuthzStatus computeDecision() {
        // Recurse.
        return isAuthorizedRecurse(userIdentity,
            aclChain.subList(1, aclChain.size()));
      }
    };
    return aclChain.get(0).getInheritanceType()
        .isAuthorized(childDecision, parentDecision);
  }

  /**
   * Check authz for many DocIds at once. This will only fetch ACL information
   * for a DocId once, even when considering inheritFrom. It will then create
   * the appropriate chains and call {@link #isAuthorized isAuthorized()}.
   *
   * <p>If there is an inheritance cycle, an ACL for a DocId in {@code ids} was
   * not returned by {@code retriever} when requested, or an inherited ACL was
   * not returned by {@code retriever} when requested, its response will be
   * {@link AuthzStatus#INDETERMINATE} for that DocId.
   *
   * @param userIdentity identity containing the user's username and all the
   *     groups the user belongs to
   * @param ids collection of DocIds that need authz performed
   * @param retriever object to use to obtain an ACL for a given DocId
   * @throws IOException if the retriever throws an IOException
   */
  public static Map<DocId, AuthzStatus> isAuthorizedBatch(
      AuthnIdentity userIdentity, Collection<DocId> ids,
      BatchRetriever retriever) throws IOException {
    Map<DocId, Acl> acls = retrieveNecessaryAcls(ids, retriever);
    Map<DocId, AuthzStatus> results
        = new HashMap<DocId, AuthzStatus>(ids.size() * 2);
    for (DocId docId : ids) {
      List<Acl> chain = createChain(docId, acls);
      AuthzStatus result;
      if (chain == null) {
        // There was a cycle or other problem generating the chain.
        result = AuthzStatus.INDETERMINATE;
      } else {
        result = isAuthorized(userIdentity, chain);
      }
      results.put(docId, result);
    }
    return Collections.unmodifiableMap(results);
  }

  private static Map<DocId, Acl> retrieveNecessaryAcls(Collection<DocId> ids,
        BatchRetriever retriever) throws IOException {
    Map<DocId, Acl> acls = new HashMap<DocId, Acl>(ids.size() * 2);
    Set<DocId> missingAcls = new HashSet<DocId>();
    Set<DocId> pendingRetrieval = new HashSet<DocId>(ids);
    Set<Acl> checkedAcl = new HashSet<Acl>(ids.size() * 2);
    Set<Acl> toProcess = new HashSet<Acl>(ids.size() * 2);
    while (!pendingRetrieval.isEmpty()) {
      Map<DocId, Acl> returned = retriever.retrieveAcls(pendingRetrieval);
      toProcess.clear();
      for (Map.Entry<DocId, Acl> me : returned.entrySet()) {
        if (me.getValue() == null) {
          throw new NullPointerException(
              "BatchRetriever returned null for a DocId");
        }
        DocId key = me.getKey();
        if (acls.containsKey(key) || missingAcls.contains(key)) {
          // Don't replace previous results since we have already checked them.
          continue;
        }
        acls.put(key, me.getValue());
        // If we requested this ACL, follow its inheritance.
        if (pendingRetrieval.contains(key)) {
          toProcess.add(me.getValue());
        }
      }
      // Compute ACLs that we requested, but did not receive.
      pendingRetrieval.removeAll(returned.keySet());
      missingAcls.addAll(pendingRetrieval);

      pendingRetrieval.clear();

      for (Acl acl : toProcess) {
        // Follow the inheritance chain until it terminates.
        while (true) {
          if (checkedAcl.contains(acl)) {
            // Already processed.
            break;
          }
          checkedAcl.add(acl);

          DocId parent = acl.getInheritFrom();
          if (parent == null) {
            // Inheritance chain terminated; everything looks good.
            break;
          } else if (missingAcls.contains(parent)) {
            // Failed to retrieve parent, so give up.
            break;
          } else if (acls.containsKey(parent)) {
            // Already have the parent ACLs, so check parent.
            acl = acls.get(parent);
          } else {
            // Request parent ACLs.
            pendingRetrieval.add(parent);
            break;
          }
        }
      }
    }
    return acls;
  }

  private static List<Acl> createChain(DocId docId, Map<DocId, Acl> acls) {
    List<Acl> chain = new LinkedList<Acl>();
    Set<Acl> used = new HashSet<Acl>();
    DocId cur = docId;
    while (cur != null) {
      Acl acl = acls.get(cur);
      if (acl == null) {
        if (chain.isEmpty()) {
          // The GSA turns this into a chain containing only an empty ACL (which
          // eventually becomes indeterminate), but we want this to be
          // indeterminate immediately because we do not have public/private
          // flags for documents and we don't want to accidentally cause a
          // document to become public.
          log.log(Level.FINE, "Document does not seem to use ACLs: {0}", cur);
        } else {
          log.log(Level.WARNING, "Missing ACLs for document ''{0}'' inherited "
              + "from another document", cur);
        }
        return null;
      }
      if (used.contains(acl)) {
        log.log(Level.WARNING, "Detected ACL cycle at ''{0}''", cur);
        return null;
      }
      used.add(acl);
      chain.add(0, acl);
      cur = acl.getInheritFrom();
    }
    return Collections.unmodifiableList(chain);
  }

  /**
   * Equality is determined if all the permit/deny sets are equal and the
   * inheritance is equal.
   */
  @Override
  public boolean equals(Object o) {
    if (!(o instanceof Acl)) {
      return false;
    }
    if (this == o) {
      return true;
    }
    Acl a = (Acl) o;
    return inheritType == a.inheritType
        // Handle null case.
        && (inheritFrom == a.inheritFrom
            || (inheritFrom != null && inheritFrom.equals(a.inheritFrom)))
        && (inheritFromFragment == a.inheritFromFragment
            || (inheritFromFragment != null
                && inheritFromFragment.equals(a.inheritFromFragment)))
        && permitGroups.equals(a.permitGroups)
        && denyGroups.equals(a.denyGroups)
        && permitUsers.equals(a.permitUsers) && denyUsers.equals(a.denyUsers)
        && caseSensitive == a.caseSensitive;
  }

  /**
   * Returns a hash code for this object that agrees with {@code equals}.
   */
  @Override
  public int hashCode() {
    return Arrays.hashCode(new Object[] {
      permitGroups, denyGroups, permitUsers, denyUsers,
      inheritFrom, inheritFromFragment, inheritType, caseSensitive
    });
  }

  /**
   * Generates a string useful for debugging that contains users and groups
   * along with inheritance information.
   */
  @Override
  public String toString() {
    return "Acl(caseSensitive=" + caseSensitive
        + ", inheritFrom=" + inheritFrom
        + (inheritFromFragment == null ? "" : "#" + inheritFromFragment)
        + ", inheritType=" + inheritType
        + ", permitGroups=" + permitGroups + ", denyGroups=" + denyGroups
        + ", permitUsers=" + permitUsers + ", denyUsers=" + denyUsers + ")";
  }

  /**
   * Batch retrieval of ACLs for efficent processing of many authz checks at
   * once.
   *
   * @see Acl#isAuthorizedBatch
   */
  public static interface BatchRetriever {
    /**
     * Retrieve the ACLs for the requested DocIds. This method is permitted to
     * return ACLs for DocIds not requested, but it should never provide a
     * {@code null} value for a DocId's ACLs. If a DocId does not exist, then it
     * should be missing in the returned map.
     *
     * <p>This method should provide any ACLs for named resources (if any are in
     * use, which is not the common case) in addition to any normal documents.
     * For more information about named resources, see {@link
     * DocIdPusher#pushNamedResources}.
     *
     * @throws IOException if there was an error contacting the data store
     */
    public Map<DocId, Acl> retrieveAcls(Set<DocId> ids)
        throws IOException;
  }

  /**
   * Mutable ACL for creating instances of {@link Acl}.
   */
  public static class Builder {
    private Set<GroupPrincipal> permitGroups = Collections.emptySet();
    private Set<GroupPrincipal> denyGroups = Collections.emptySet();
    private Set<UserPrincipal> permitUsers = Collections.emptySet();
    private Set<UserPrincipal> denyUsers = Collections.emptySet();
    private DocId inheritFrom;
    private String inheritFromFragment;
    private InheritanceType inheritType = InheritanceType.LEAF_NODE;
    private boolean caseSensitive = true;

    /**
     * Create new empty builder. All sets are empty, inheritFrom is {@code
     * null}, and inheritType is {@link InheritanceType#LEAF_NODE}.
     */
    public Builder() {}

    /**
     * Create and initialize builder with ACL information provided in {@code
     * acl}.
     */
    public Builder(Acl acl) {
      permitGroups = sanitizeSet(acl.getPermitGroups());
      denyGroups = sanitizeSet(acl.getDenyGroups());
      permitUsers = sanitizeSet(acl.getPermitUsers());
      denyUsers = sanitizeSet(acl.getDenyUsers());
      inheritFrom = acl.getInheritFrom();
      inheritFromFragment = acl.getInheritFromFragment();
      inheritType = acl.getInheritanceType();
      caseSensitive = acl.isEverythingCaseSensitive();
    }

    private <P extends Principal> Set<P> sanitizeSet(Collection<P> set) {
      if (set.isEmpty()) {
        return Collections.emptySet();
      }
      // Check all the values to make sure they are valid.
      for (P item : set) {
        if (item == null) {
          throw new NullPointerException("Entries in set may not be null");
        }
      }
      // Use TreeSets so that sets have predictable order when serializing.
      return Collections.unmodifiableSet(new TreeSet<P>(set));
    }

    /**
     * Create immutable {@link Acl} instance of the current state.
     */
    public Acl build() {
      return new Acl(permitGroups, denyGroups, permitUsers, denyUsers,
          inheritFrom, inheritFromFragment, inheritType, caseSensitive);
    }

    /**
     * Replace existing permit groups.
     *
     * @return the same instance of the builder, for chaining calls
     * @throws NullPointerException if the collection is {@code null} or
     *     contains {@code null}
     * @throws IllegalArgumentException if the collection contains {@code ""}
     *     or a value that has leading or trailing whitespace
     */
    public Builder setPermitGroups(Collection<GroupPrincipal> permitGroups) {
      this.permitGroups = sanitizeSet(permitGroups);
      return this;
    }

    /**
     * Replace existing deny groups.
     *
     * @return the same instance of the builder, for chaining calls
     * @throws NullPointerException if the collection is {@code null} or
     *     contains {@code null}
     * @throws IllegalArgumentException if the collection contains {@code ""}
     *     or a value that has leading or trailing whitespace
     */
    public Builder setDenyGroups(Collection<GroupPrincipal> denyGroups) {
      this.denyGroups = sanitizeSet(denyGroups);
      return this;
    }

    /**
     * Replace existing permit users.
     *
     * @return the same instance of the builder, for chaining calls
     * @throws NullPointerException if the collection is {@code null} or
     *     contains {@code null}
     * @throws IllegalArgumentException if the collection contains {@code ""}
     *     or a value that has leading or trailing whitespace
     */
    public Builder setPermitUsers(Collection<UserPrincipal> permitUsers) {
      this.permitUsers = sanitizeSet(permitUsers);
      return this;
    }

    /**
     * Replace existing deny users.
     *
     * @return the same instance of the builder, for chaining calls
     * @throws NullPointerException if the collection is {@code null} or
     *     contains {@code null}
     * @throws IllegalArgumentException if the collection contains {@code ""}
     *     or a value that has leading or trailing whitespace
     */
    public Builder setDenyUsers(Collection<UserPrincipal> denyUsers) {
      this.denyUsers = sanitizeSet(denyUsers);
      return this;
    }

    /**
     * Replace existing permit users and groups.
     *
     * @return the same instance of the builder, for chaining calls
     * @throws NullPointerException if the collection is {@code null} or
     *     contains {@code null}
     * @throws IllegalArgumentException if the collection contains {@code ""}
     *     or a value that has leading or trailing whitespace
     */
    public Builder setPermits(Collection<Principal> permits) {
      Collection<GroupPrincipal> groups = new ArrayList<GroupPrincipal>();
      Collection<UserPrincipal> users = new ArrayList<UserPrincipal>();
      for (Principal principal : permits) {
        if (principal.isGroup()) {
          groups.add((GroupPrincipal) principal);
        } else {
          users.add((UserPrincipal) principal);
        }
      }
      Set<GroupPrincipal> sanitizedGroups = sanitizeSet(groups);
      Set<UserPrincipal> sanitizedUsers = sanitizeSet(users);
      this.permitGroups = sanitizedGroups;
      this.permitUsers = sanitizedUsers;
      return this;
    }

    /**
     * Replace existing deny users and groups.
     *
     * @return the same instance of the builder, for chaining calls
     * @throws NullPointerException if the collection is {@code null} or
     *     contains {@code null}
     * @throws IllegalArgumentException if the collection contains {@code ""}
     *     or a value that has leading or trailing whitespace
     */
    public Builder setDenies(Collection<Principal> denies) {
      Collection<GroupPrincipal> groups = new ArrayList<GroupPrincipal>();
      Collection<UserPrincipal> users = new ArrayList<UserPrincipal>();
      for (Principal principal : denies) {
        if (principal.isGroup()) {
          groups.add((GroupPrincipal) principal);
        } else {
          users.add((UserPrincipal) principal);
        }
      }
      Set<GroupPrincipal> sanitizedGroups = sanitizeSet(groups);
      Set<UserPrincipal> sanitizedUsers = sanitizeSet(users);
      this.denyGroups = sanitizedGroups;
      this.denyUsers = sanitizedUsers;
      return this;
    }

    /**
     * Set {@code DocId} to inherit ACLs from. This is also known as the
     * "parent's" ACLs. Note that the parent's {@code InheritanceType}
     * determines how to combine results with this ACL.
     *
     * @return the same instance of the builder, for chaining calls
     * @see #setInheritanceType
     */
    public Builder setInheritFrom(DocId inheritFrom) {
      this.inheritFrom = inheritFrom;
      this.inheritFromFragment = null;
      return this;
    }

    /**
     * Set the parent to inherit ACLs from. 
     * Note that the parent's {@code InheritanceType}
     * determines how to combine results with this ACL.
     * <p>
     * The fragment facilitates a single parent {@code DocId}
     * having multiple ACLs to inherit from.  For example
     * a single parent DocId could have ACLs that are to be inherited
     * by sub-folder {@code DocId} instances and different
     * ACLs that are to be inherited by children files.
     * The fragment allows specifying which of the parent's ACLs
     * is to be inherited from.
     *
     * @return the same instance of the builder, for chaining calls
     * @see #setInheritanceType
     */
    public Builder setInheritFrom(DocId inheritFrom, String fragment) {
      this.inheritFrom = inheritFrom;
      this.inheritFromFragment = fragment;
      return this;
    }

    /**
     * Set the type of inheritance of ACL information used to combine authz
     * decisions of these ACLs with its <em>child</em>. The inheritance type
     * applies to the interaction between this ACL and any <em>children</em> it
     * has.
     *
     * @return the same instance of the builder, for chaining calls
     * @throws NullPointerException if {@code inheritType} is {@code null}
     * @see #setInheritFrom
     */
    public Builder setInheritanceType(InheritanceType inheritType) {
      if (inheritType == null) {
        throw new NullPointerException();
      }
      this.inheritType = inheritType;
      return this;
    }

    public Builder setEverythingCaseSensitive() {
      caseSensitive = true;
      return this;
    }

    public Builder setEverythingCaseInsensitive() {
      caseSensitive = false;
      return this;
    }
  }

  /**
   * The rule for combining a parent's authz response with its child's. This is
   * stored as part of the parent's ACLs.
   */
  public static enum InheritanceType {
    /**
     * The child's authz result is used, unless it is indeterminate, in which
     * case this ACL's authz result is used.
     */
    CHILD_OVERRIDES("child-overrides") {
      @Override
      AuthzStatus isAuthorized(Decision child, Decision parent) {
        if (child.getStatus() == AuthzStatus.INDETERMINATE) {
          return parent.getStatus();
        }
        return child.getStatus();
      }
    },
    /**
     * This ACL's authz result is used, unless it is indeterminate, in which
     * case the child's authz result is used.
     */
    PARENT_OVERRIDES("parent-overrides") {
      @Override
      AuthzStatus isAuthorized(Decision child, Decision parent) {
        if (parent.getStatus() == AuthzStatus.INDETERMINATE) {
          return child.getStatus();
        }
        return parent.getStatus();
      }
    },
    /**
     * The user is denied, unless both this ACL and the child's authz result is
     * permit.
     */
    AND_BOTH_PERMIT("and-both-permit") {
      @Override
      AuthzStatus isAuthorized(Decision child, Decision parent) {
        if (parent.getStatus() == AuthzStatus.PERMIT
            && child.getStatus() == AuthzStatus.PERMIT) {
          return AuthzStatus.PERMIT;
        }
        return AuthzStatus.DENY;
      }
    },
    /**
     * The ACL should never have a child and thus the inheritance type is
     * unnecessary. If a child inherits from this ACL then the result is deny.
     */
    LEAF_NODE("leaf-node") {
      @Override
      AuthzStatus isAuthorized(Decision child, Decision parent) {
        log.log(Level.WARNING, "Illegal ACL information. A LEAF_NODE is the "
                + "parent of another node.");
        return AuthzStatus.DENY;
      }
    },
    ;

    private final String commonForm;

    private InheritanceType(String commonForm) {
      this.commonForm = commonForm;
    }

    /**
     * The identifier used to represent enum value during communication with the
     * GSA.
     */
    String getCommonForm() {
      return commonForm;
    }

    /**
     * Combine the result of a child and a parent.
     */
    abstract AuthzStatus isAuthorized(Decision child, Decision parent);
  }

  /**
   * Lazy-computing of AuthzStatus.
   */
  abstract static class Decision {
    private AuthzStatus status;

    public AuthzStatus getStatus() {
      if (status == null) {
        status = computeDecision();
        if (status == null) {
          throw new AssertionError();
        }
      }
      return status;
    }

    /**
     * Compute the actual decision. The response will be cached, so this will be
     * called at most once.
     *
     * @return a non-{@code null} authz status
     */
    protected abstract AuthzStatus computeDecision();
  }
}
