HDDS-10454. Make OzoneAcl immutable (#6319)

diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OzoneAcl.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OzoneAcl.java
index 2b79d24..edfb194 100644
--- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OzoneAcl.java
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OzoneAcl.java
@@ -19,7 +19,8 @@
 
 package org.apache.hadoop.ozone;
 
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.google.common.annotations.VisibleForTesting;
 import com.google.protobuf.ByteString;
 import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OzoneAclInfo;
 import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OzoneAclInfo.OzoneAclScope;
@@ -31,8 +32,12 @@
 import java.util.BitSet;
 import java.util.List;
 import java.util.Objects;
+import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
+import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.ALL;
+import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.NONE;
+
 /**
  * OzoneACL classes define bucket ACLs used in OZONE.
  *
@@ -43,65 +48,34 @@
  * <li>world::rw
  * </ul>
  */
-@JsonIgnoreProperties(value = {"aclBitSet"})
 public class OzoneAcl {
 
   private static final String ACL_SCOPE_REGEX = ".*\\[(ACCESS|DEFAULT)\\]";
-  private ACLIdentityType type;
-  private String name;
-  private BitSet aclBitSet;
-  private AclScope aclScope;
+  private final ACLIdentityType type;
+  private final String name;
+  @JsonIgnore
+  private final BitSet aclBitSet;
+  private final AclScope aclScope;
   private static final List<ACLType> EMPTY_LIST = new ArrayList<>(0);
-  public static final BitSet ZERO_BITSET = new BitSet(0);
 
-  /**
-   * Default constructor.
-   */
-  public OzoneAcl() {
+  // TODO use varargs constructor
+  public OzoneAcl(ACLIdentityType type, String name, ACLType acl, AclScope scope) {
+    this(type, name, scope, bitSetOf(acl));
   }
 
-  /**
-   * Constructor for OzoneAcl.
-   *
-   * @param type   - Type
-   * @param name   - Name of user
-   * @param acl    - Rights
-   * @param scope  - AclScope
-   */
-  public OzoneAcl(ACLIdentityType type, String name, ACLType acl,
-      AclScope scope) {
-    this.name = name;
-    this.aclBitSet = new BitSet(ACLType.getNoOfAcls());
-    aclBitSet.set(acl.ordinal(), true);
-    this.type = type;
-    if (type == ACLIdentityType.WORLD || type == ACLIdentityType.ANONYMOUS) {
-      if (!name.equals(ACLIdentityType.WORLD.name()) &&
-          !name.equals(ACLIdentityType.ANONYMOUS.name()) &&
-          name.length() != 0) {
-        throw new IllegalArgumentException("Unexpected name:{" + name +
-            "} for type WORLD, ANONYMOUS. It should be WORLD & " +
-            "ANONYMOUS respectively.");
-      }
-      // For type WORLD and ANONYMOUS we allow only one acl to be set.
-      this.name = type.name();
-    }
-    if (((type == ACLIdentityType.USER) || (type == ACLIdentityType.GROUP))
-        && (name.length() == 0)) {
-      throw new IllegalArgumentException("User or group name is required");
-    }
-    aclScope = scope;
-  }
-
-  /**
-   * Constructor for OzoneAcl.
-   *
-   * @param type   - Type
-   * @param name   - Name of user
-   * @param scope  - AclScope
-   * @param acls   - Rights
-   */
   public OzoneAcl(ACLIdentityType type, String name, AclScope scope, ACLType... acls) {
-    this(type, name, bitSetOf(acls), scope);
+    this(type, name, scope, bitSetOf(acls));
+  }
+
+  public OzoneAcl(ACLIdentityType type, String name, BitSet acls, AclScope scope) {
+    this(type, name, scope, validateAndCopy(acls));
+  }
+
+  private OzoneAcl(ACLIdentityType type, String name, AclScope scope, BitSet acls) {
+    this.name = validateNameAndType(type, name);
+    this.type = type;
+    this.aclScope = scope;
+    this.aclBitSet = acls;
   }
 
   private static BitSet bitSetOf(ACLType... acls) {
@@ -114,36 +88,45 @@
     return bits;
   }
 
-  public OzoneAcl(ACLIdentityType type, String name, BitSet acls,
-      AclScope scope) {
-    Objects.requireNonNull(type);
+  private static BitSet validateAndCopy(BitSet acls) {
     Objects.requireNonNull(acls);
 
     if (acls.cardinality() > ACLType.getNoOfAcls()) {
       throw new IllegalArgumentException("Acl bitset passed has unexpected " +
-          "size. bitset size:" + acls.cardinality() + ", bitset:"
-          + acls.toString());
+          "size. bitset size:" + acls.cardinality() + ", bitset:" + acls);
     }
-    this.aclBitSet = (BitSet) acls.clone();
 
-    this.name = name;
-    this.type = type;
+    return copyBitSet(acls);
+  }
+
+  private static BitSet copyBitSet(BitSet acls) {
+    return (BitSet) acls.clone();
+  }
+
+  private static String validateNameAndType(ACLIdentityType type, String name) {
+    Objects.requireNonNull(type);
+
     if (type == ACLIdentityType.WORLD || type == ACLIdentityType.ANONYMOUS) {
       if (!name.equals(ACLIdentityType.WORLD.name()) &&
           !name.equals(ACLIdentityType.ANONYMOUS.name()) &&
           name.length() != 0) {
-        throw new IllegalArgumentException("Unexpected name:{" + name +
-            "} for type WORLD, ANONYMOUS. It should be WORLD & " +
-            "ANONYMOUS respectively.");
+        throw new IllegalArgumentException("Expected name " + type.name() + ", but was: " + name);
       }
       // For type WORLD and ANONYMOUS we allow only one acl to be set.
-      this.name = type.name();
+      return type.name();
     }
+
     if (((type == ACLIdentityType.USER) || (type == ACLIdentityType.GROUP))
         && (name.length() == 0)) {
-      throw new IllegalArgumentException("User or group name is required");
+      throw new IllegalArgumentException(type + " name is required");
     }
-    aclScope = scope;
+
+    return name;
+  }
+
+  public OzoneAcl withScope(final AclScope scope) {
+    return scope == aclScope ? this
+        : new OzoneAcl(type, name, scope, copyBitSet(aclBitSet));
   }
 
   /**
@@ -219,7 +202,7 @@
         .setName(acl.getName())
         .setType(OzoneAclType.valueOf(acl.getType().name()))
         .setAclScope(OzoneAclScope.valueOf(acl.getAclScope().name()))
-        .setRights(ByteString.copyFrom(acl.getAclBitSet().toByteArray()));
+        .setRights(ByteString.copyFrom(acl.getAclByteArray()));
     return builder.build();
   }
 
@@ -230,35 +213,6 @@
         AclScope.valueOf(protoAcl.getAclScope().name()));
   }
 
-  /**
-   * Helper function to convert a proto message of type {@link OzoneAclInfo}
-   * to {@link OzoneAcl} with acl scope of type ACCESS.
-   *
-   * @param protoAcl
-   * @return OzoneAcl
-   * */
-  public static OzoneAcl fromProtobufWithAccessType(OzoneAclInfo protoAcl) {
-    BitSet aclRights = BitSet.valueOf(protoAcl.getRights().toByteArray());
-    return new OzoneAcl(ACLIdentityType.valueOf(protoAcl.getType().name()),
-        protoAcl.getName(), aclRights, AclScope.ACCESS);
-  }
-
-  /**
-   * Helper function to convert an {@link OzoneAcl} to proto message of type
-   * {@link OzoneAclInfo} with acl scope of type ACCESS.
-   *
-   * @param acl
-   * @return OzoneAclInfo
-   * */
-  public static OzoneAclInfo toProtobufWithAccessType(OzoneAcl acl) {
-    OzoneAclInfo.Builder builder = OzoneAclInfo.newBuilder()
-        .setName(acl.getName())
-        .setType(OzoneAclType.valueOf(acl.getType().name()))
-        .setAclScope(OzoneAclScope.ACCESS)
-        .setRights(ByteString.copyFrom(acl.getAclBitSet().toByteArray()));
-    return builder.build();
-  }
-
   public AclScope getAclScope() {
     return aclScope;
   }
@@ -280,7 +234,7 @@
    */
   @Override
   public int hashCode() {
-    return Objects.hash(this.getName(), this.getAclBitSet(),
+    return Objects.hash(this.getName(), aclBitSet,
                         this.getType().toString(), this.getAclScope());
   }
 
@@ -293,17 +247,45 @@
     return name;
   }
 
-  /**
-   * Returns Rights.
-   *
-   * @return - Rights
-   */
-  public BitSet getAclBitSet() {
-    return aclBitSet;
+  @JsonIgnore
+  public boolean isEmpty() {
+    return aclBitSet.isEmpty();
+  }
+
+  @VisibleForTesting
+  public boolean isSet(ACLType acl) {
+    return aclBitSet.get(acl.ordinal());
+  }
+
+  public boolean checkAccess(ACLType acl) {
+    return (isSet(acl) || isSet(ALL)) && !isSet(NONE);
+  }
+
+  public OzoneAcl add(OzoneAcl other) {
+    return apply(bits -> bits.or(other.aclBitSet));
+  }
+
+  public OzoneAcl remove(OzoneAcl other) {
+    return apply(bits -> bits.andNot(other.aclBitSet));
+  }
+
+  /** @return copy of this {@code OzoneAcl} after applying the given {@code op},
+   * or this instance if {@code op} makes no difference */
+  private OzoneAcl apply(Consumer<BitSet> op) {
+    final BitSet cloneBits = copyBitSet(aclBitSet);
+    op.accept(cloneBits);
+    return cloneBits.equals(aclBitSet)
+        ? this
+        : new OzoneAcl(type, name, aclScope, cloneBits);
+  }
+
+  @JsonIgnore
+  public byte[] getAclByteArray() {
+    return aclBitSet.toByteArray();
   }
 
   public List<ACLType> getAclList() {
-    if (aclBitSet !=  null) {
+    if (aclBitSet != null) {
       return aclBitSet.stream().mapToObj(a ->
           ACLType.values()[a]).collect(Collectors.toList());
     }
@@ -329,24 +311,19 @@
    */
   @Override
   public boolean equals(Object obj) {
-    if (obj == null) {
-      return false;
+    if (obj == this) {
+      return true;
     }
-    if (getClass() != obj.getClass()) {
+    if (obj == null || getClass() != obj.getClass()) {
       return false;
     }
     OzoneAcl otherAcl = (OzoneAcl) obj;
     return otherAcl.getName().equals(this.getName()) &&
         otherAcl.getType().equals(this.getType()) &&
-        otherAcl.getAclBitSet().equals(this.getAclBitSet()) &&
+        Objects.equals(aclBitSet, otherAcl.aclBitSet) &&
         otherAcl.getAclScope().equals(this.getAclScope());
   }
 
-  public OzoneAcl setAclScope(AclScope scope) {
-    this.aclScope = scope;
-    return this;
-  }
-
   /**
    * Scope of ozone acl.
    * */
diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmBucketInfo.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmBucketInfo.java
index 05e633f..dd6406a 100644
--- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmBucketInfo.java
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmBucketInfo.java
@@ -19,7 +19,6 @@
 
 
 import java.util.ArrayList;
-import java.util.BitSet;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -27,6 +26,7 @@
 import java.util.Objects;
 import java.util.stream.Collectors;
 
+import com.google.common.collect.ImmutableList;
 import org.apache.hadoop.hdds.client.DefaultReplicationConfig;
 import org.apache.hadoop.hdds.protocol.StorageType;
 import org.apache.hadoop.hdds.utils.db.Codec;
@@ -153,7 +153,7 @@
    * @return {@literal List<OzoneAcl>}
    */
   public List<OzoneAcl> getAcls() {
-    return acls;
+    return ImmutableList.copyOf(acls);
   }
 
   /**
@@ -353,11 +353,6 @@
       builder.setBucketEncryptionKey(bekInfo.copy());
     }
 
-    builder.acls.clear();
-    acls.forEach(acl -> builder.addAcl(new OzoneAcl(acl.getType(),
-        acl.getName(), (BitSet) acl.getAclBitSet().clone(),
-        acl.getAclScope())));
-
     if (defaultReplicationConfig != null) {
       builder.setDefaultReplicationConfig(defaultReplicationConfig.copy());
     }
diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmDirectoryInfo.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmDirectoryInfo.java
index 69ea2fc..b505166 100644
--- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmDirectoryInfo.java
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmDirectoryInfo.java
@@ -25,7 +25,6 @@
 import org.apache.hadoop.ozone.OzoneConsts;
 import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DirectoryInfo;
 
-import java.util.BitSet;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
@@ -262,14 +261,11 @@
             .setName(name)
             .setCreationTime(creationTime)
             .setModificationTime(modificationTime)
+            .setAcls(acls)
             .setParentObjectID(getParentObjectID())
             .setObjectID(getObjectID())
             .setUpdateID(getUpdateID());
 
-    acls.forEach(acl -> builder.addAcl(new OzoneAcl(acl.getType(),
-            acl.getName(), (BitSet) acl.getAclBitSet().clone(),
-            acl.getAclScope())));
-
     if (getMetadata() != null) {
       builder.addAllMetadata(getMetadata());
     }
diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmKeyInfo.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmKeyInfo.java
index d1fe4a3..e1b7ce1 100644
--- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmKeyInfo.java
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmKeyInfo.java
@@ -19,12 +19,12 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.BitSet;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
+import com.google.common.collect.ImmutableList;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.hadoop.fs.FileChecksum;
@@ -368,7 +368,7 @@
   }
 
   public List<OzoneAcl> getAcls() {
-    return acls;
+    return ImmutableList.copyOf(acls);
   }
 
   public boolean addAcl(OzoneAcl acl) {
@@ -786,6 +786,7 @@
         .setDataSize(dataSize)
         .setReplicationConfig(replicationConfig)
         .setFileEncryptionInfo(encInfo)
+        .setAcls(acls)
         .setObjectID(getObjectID())
         .setUpdateID(getUpdateID())
         .setParentObjectID(getParentObjectID())
@@ -798,10 +799,6 @@
                 keyLocationVersion.getLocationList(),
                 keyLocationVersion.isMultipartKey())));
 
-    acls.forEach(acl -> builder.addAcl(new OzoneAcl(acl.getType(),
-            acl.getName(), (BitSet) acl.getAclBitSet().clone(),
-        acl.getAclScope())));
-
     if (getMetadata() != null) {
       getMetadata().forEach((k, v) -> builder.addMetadata(k, v));
     }
diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmVolumeArgs.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmVolumeArgs.java
index 1a12d4d..d818df1 100644
--- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmVolumeArgs.java
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmVolumeArgs.java
@@ -18,13 +18,13 @@
 package org.apache.hadoop.ozone.om.helpers;
 
 import java.util.ArrayList;
-import java.util.BitSet;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
+import com.google.common.collect.ImmutableList;
 import org.apache.hadoop.hdds.utils.db.Codec;
 import org.apache.hadoop.hdds.utils.db.CopyObject;
 import org.apache.hadoop.hdds.utils.db.DelegatedCodec;
@@ -221,7 +221,7 @@
   }
 
   public List<OzoneAcl> getAcls() {
-    return acls;
+    return ImmutableList.copyOf(acls);
   }
 
   public List<OzoneAcl> getDefaultAcls() {
@@ -477,17 +477,11 @@
   public OmVolumeArgs copyObject() {
     Map<String, String> cloneMetadata = new HashMap<>();
     if (getMetadata() != null) {
-      getMetadata().forEach((k, v) -> cloneMetadata.put(k, v));
+      cloneMetadata.putAll(getMetadata());
     }
 
-    List<OzoneAcl> cloneAcls = new ArrayList(acls.size());
-
-    acls.forEach(acl -> cloneAcls.add(new OzoneAcl(acl.getType(),
-        acl.getName(), (BitSet) acl.getAclBitSet().clone(),
-        acl.getAclScope())));
-
     return new OmVolumeArgs(adminName, ownerName, volume, quotaInBytes,
-        quotaInNamespace, usedNamespace, cloneMetadata, cloneAcls,
+        quotaInNamespace, usedNamespace, cloneMetadata, new ArrayList<>(acls),
         creationTime, modificationTime, getObjectID(), getUpdateID(), refCount);
   }
 }
diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OzoneAclUtil.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OzoneAclUtil.java
index 134675c..a2e738f 100644
--- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OzoneAclUtil.java
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OzoneAclUtil.java
@@ -27,17 +27,17 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.BitSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
 import org.apache.hadoop.security.UserGroupInformation;
 
 import static org.apache.hadoop.ozone.OzoneAcl.AclScope.ACCESS;
 import static org.apache.hadoop.ozone.OzoneAcl.AclScope.DEFAULT;
 import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType.GROUP;
 import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType.USER;
-import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.ALL;
-import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.NONE;
 
 /**
  * Helper class for ozone acls operations.
@@ -91,23 +91,22 @@
 
   private static boolean checkAccessInAcl(OzoneAcl a, UserGroupInformation ugi,
       ACLType aclToCheck) {
-    BitSet rights = a.getAclBitSet();
     switch (a.getType()) {
     case USER:
       if (a.getName().equals(ugi.getShortUserName())) {
-        return checkIfAclBitIsSet(aclToCheck, rights);
+        return a.checkAccess(aclToCheck);
       }
       break;
     case GROUP:
       for (String grp : ugi.getGroupNames()) {
         if (a.getName().equals(grp)) {
-          return checkIfAclBitIsSet(aclToCheck, rights);
+          return a.checkAccess(aclToCheck);
         }
       }
       break;
 
     default:
-      return checkIfAclBitIsSet(aclToCheck, rights);
+      return a.checkAccess(aclToCheck);
     }
     return false;
   }
@@ -137,56 +136,30 @@
   }
 
   /**
-   * Helper function to check if bit for given acl is set.
-   * @param acl
-   * @param bitset
-   * @return True of acl bit is set else false.
-   * */
-  public static boolean checkIfAclBitIsSet(IAccessAuthorizer.ACLType acl,
-      BitSet bitset) {
-    if (bitset == null) {
-      return false;
-    }
-
-    return ((bitset.get(acl.ordinal())
-        || bitset.get(ALL.ordinal()))
-        && !bitset.get(NONE.ordinal()));
-  }
-
-  /**
-   * Helper function to inherit default ACL as access ACL for child object.
-   * 1. deep copy of OzoneAcl to avoid unexpected parent default ACL change
-   * 2. merge inherited access ACL with existing access ACL via
-   * OzoneUtils.addAcl().
-   * @param acls
-   * @param parentAcls
-   * @return true if acls inherited DEFAULT acls from parentAcls successfully,
-   * false otherwise.
+   * Helper function to inherit default ACL with given {@code scope} for child object.
+   * @param acls child object ACL list
+   * @param parentAcls parent object ACL list
+   * @param scope scope applied to inherited ACL
+   * @return true if any ACL was inherited from parent, false otherwise
    */
   public static boolean inheritDefaultAcls(List<OzoneAcl> acls,
-      List<OzoneAcl> parentAcls) {
-    List<OzoneAcl> inheritedAcls = null;
+      List<OzoneAcl> parentAcls, OzoneAcl.AclScope scope) {
     if (parentAcls != null && !parentAcls.isEmpty()) {
-      inheritedAcls = parentAcls.stream()
-          .filter(a -> a.getAclScope() == DEFAULT)
-          .map(acl -> new OzoneAcl(acl.getType(), acl.getName(),
-              acl.getAclBitSet(), ACCESS))
-          .collect(Collectors.toList());
-    }
-    if (inheritedAcls != null && !inheritedAcls.isEmpty()) {
-      inheritedAcls.stream().forEach(acl -> addAcl(acls, acl));
-      return true;
-    }
-    return false;
-  }
+      Stream<OzoneAcl> aclStream = parentAcls.stream()
+          .filter(a -> a.getAclScope() == DEFAULT);
 
-  /**
-   * Helper function to convert the scope of ACLs to DEFAULT.
-   * This method is called in ACL inheritance scenarios.
-   * @param acls
-   */
-  public static void toDefaultScope(List<OzoneAcl> acls) {
-    acls.forEach(a -> a.setAclScope(DEFAULT));
+      if (scope != DEFAULT) {
+        aclStream = aclStream.map(acl -> acl.withScope(scope));
+      }
+
+      List<OzoneAcl> inheritedAcls = aclStream.collect(Collectors.toList());
+      if (!inheritedAcls.isEmpty()) {
+        inheritedAcls.forEach(acl -> addAcl(acls, acl));
+        return true;
+      }
+    }
+
+    return false;
   }
 
   /**
@@ -217,8 +190,6 @@
 
   /**
    * Add an OzoneAcl to existing list of OzoneAcls.
-   * @param existingAcls
-   * @param acl
    * @return true if current OzoneAcls are changed, false otherwise.
    */
   public static boolean addAcl(List<OzoneAcl> existingAcls, OzoneAcl acl) {
@@ -226,17 +197,17 @@
       return false;
     }
 
-    for (OzoneAcl a: existingAcls) {
+    for (int i = 0; i < existingAcls.size(); i++) {
+      final OzoneAcl a = existingAcls.get(i);
       if (a.getName().equals(acl.getName()) &&
           a.getType().equals(acl.getType()) &&
           a.getAclScope().equals(acl.getAclScope())) {
-        BitSet current = a.getAclBitSet();
-        BitSet original = (BitSet) current.clone();
-        current.or(acl.getAclBitSet());
-        if (current.equals(original)) {
-          return false;
+        final OzoneAcl updated = a.add(acl);
+        final boolean changed = !Objects.equals(updated, a);
+        if (changed) {
+          existingAcls.set(i, updated);
         }
-        return true;
+        return changed;
       }
     }
 
@@ -246,8 +217,6 @@
 
   /**
    * remove OzoneAcl from existing list of OzoneAcls.
-   * @param existingAcls
-   * @param acl
    * @return true if current OzoneAcls are changed, false otherwise.
    */
   public static boolean removeAcl(List<OzoneAcl> existingAcls, OzoneAcl acl) {
@@ -255,22 +224,19 @@
       return false;
     }
 
-    for (OzoneAcl a: existingAcls) {
+    for (int i = 0; i < existingAcls.size(); i++) {
+      final OzoneAcl a = existingAcls.get(i);
       if (a.getName().equals(acl.getName()) &&
           a.getType().equals(acl.getType()) &&
           a.getAclScope().equals(acl.getAclScope())) {
-        BitSet current = a.getAclBitSet();
-        BitSet original = (BitSet) current.clone();
-        current.andNot(acl.getAclBitSet());
-
-        if (current.equals(original)) {
-          return false;
+        final OzoneAcl updated = a.remove(acl);
+        final boolean changed = !Objects.equals(updated, a);
+        if (updated.isEmpty()) {
+          existingAcls.remove(i);
+        } else if (changed) {
+          existingAcls.set(i, updated);
         }
-
-        if (current.isEmpty()) {
-          existingAcls.remove(a);
-        }
-        return true;
+        return changed;
       }
     }
     return false;
diff --git a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/TestOzoneAcls.java b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/TestOzoneAcls.java
index 08ae1fb..0b93404 100644
--- a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/TestOzoneAcls.java
+++ b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/TestOzoneAcls.java
@@ -130,132 +130,132 @@
   void testAclValues() {
     OzoneAcl acl = OzoneAcl.parseAcl("user:bilbo:rw");
     assertEquals(acl.getName(), "bilbo");
-    assertTrue(acl.getAclBitSet().get(READ.ordinal()));
-    assertTrue(acl.getAclBitSet().get(WRITE.ordinal()));
-    assertFalse(acl.getAclBitSet().get(ALL.ordinal()));
-    assertFalse(acl.getAclBitSet().get(READ_ACL.ordinal()));
+    assertTrue(acl.isSet(READ));
+    assertTrue(acl.isSet(WRITE));
+    assertFalse(acl.isSet(ALL));
+    assertFalse(acl.isSet(READ_ACL));
     assertEquals(ACLIdentityType.USER, acl.getType());
 
     acl = OzoneAcl.parseAcl("user:bilbo:a");
     assertEquals("bilbo", acl.getName());
-    assertTrue(acl.getAclBitSet().get(ALL.ordinal()));
-    assertFalse(acl.getAclBitSet().get(WRITE.ordinal()));
+    assertTrue(acl.isSet(ALL));
+    assertFalse(acl.isSet(WRITE));
     assertEquals(ACLIdentityType.USER, acl.getType());
 
     acl = OzoneAcl.parseAcl("user:bilbo:r");
     assertEquals("bilbo", acl.getName());
-    assertTrue(acl.getAclBitSet().get(READ.ordinal()));
-    assertFalse(acl.getAclBitSet().get(ALL.ordinal()));
+    assertTrue(acl.isSet(READ));
+    assertFalse(acl.isSet(ALL));
     assertEquals(ACLIdentityType.USER, acl.getType());
 
     acl = OzoneAcl.parseAcl("user:bilbo:w");
     assertEquals("bilbo", acl.getName());
-    assertTrue(acl.getAclBitSet().get(WRITE.ordinal()));
-    assertFalse(acl.getAclBitSet().get(ALL.ordinal()));
+    assertTrue(acl.isSet(WRITE));
+    assertFalse(acl.isSet(ALL));
     assertEquals(ACLIdentityType.USER, acl.getType());
 
     acl = OzoneAcl.parseAcl("group:hobbit:a");
     assertEquals(acl.getName(), "hobbit");
-    assertTrue(acl.getAclBitSet().get(ALL.ordinal()));
-    assertFalse(acl.getAclBitSet().get(READ.ordinal()));
+    assertTrue(acl.isSet(ALL));
+    assertFalse(acl.isSet(READ));
     assertEquals(ACLIdentityType.GROUP, acl.getType());
 
     acl = OzoneAcl.parseAcl("world::a");
     assertEquals(acl.getName(), "WORLD");
-    assertTrue(acl.getAclBitSet().get(ALL.ordinal()));
-    assertFalse(acl.getAclBitSet().get(WRITE.ordinal()));
+    assertTrue(acl.isSet(ALL));
+    assertFalse(acl.isSet(WRITE));
     assertEquals(ACLIdentityType.WORLD, acl.getType());
 
     acl = OzoneAcl.parseAcl("user:bilbo:rwdlncxy");
     assertEquals(acl.getName(), "bilbo");
-    assertTrue(acl.getAclBitSet().get(READ.ordinal()));
-    assertTrue(acl.getAclBitSet().get(WRITE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(DELETE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(LIST.ordinal()));
-    assertTrue(acl.getAclBitSet().get(NONE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(CREATE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(READ_ACL.ordinal()));
-    assertTrue(acl.getAclBitSet().get(WRITE_ACL.ordinal()));
-    assertFalse(acl.getAclBitSet().get(ALL.ordinal()));
+    assertTrue(acl.isSet(READ));
+    assertTrue(acl.isSet(WRITE));
+    assertTrue(acl.isSet(DELETE));
+    assertTrue(acl.isSet(LIST));
+    assertTrue(acl.isSet(NONE));
+    assertTrue(acl.isSet(CREATE));
+    assertTrue(acl.isSet(READ_ACL));
+    assertTrue(acl.isSet(WRITE_ACL));
+    assertFalse(acl.isSet(ALL));
 
     acl = OzoneAcl.parseAcl("group:hadoop:rwdlncxy");
     assertEquals(acl.getName(), "hadoop");
-    assertTrue(acl.getAclBitSet().get(READ.ordinal()));
-    assertTrue(acl.getAclBitSet().get(WRITE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(DELETE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(LIST.ordinal()));
-    assertTrue(acl.getAclBitSet().get(NONE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(CREATE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(READ_ACL.ordinal()));
-    assertTrue(acl.getAclBitSet().get(WRITE_ACL.ordinal()));
-    assertFalse(acl.getAclBitSet().get(ALL.ordinal()));
+    assertTrue(acl.isSet(READ));
+    assertTrue(acl.isSet(WRITE));
+    assertTrue(acl.isSet(DELETE));
+    assertTrue(acl.isSet(LIST));
+    assertTrue(acl.isSet(NONE));
+    assertTrue(acl.isSet(CREATE));
+    assertTrue(acl.isSet(READ_ACL));
+    assertTrue(acl.isSet(WRITE_ACL));
+    assertFalse(acl.isSet(ALL));
     assertEquals(ACLIdentityType.GROUP, acl.getType());
 
     acl = OzoneAcl.parseAcl("world::rwdlncxy");
     assertEquals(acl.getName(), "WORLD");
-    assertTrue(acl.getAclBitSet().get(READ.ordinal()));
-    assertTrue(acl.getAclBitSet().get(WRITE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(DELETE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(LIST.ordinal()));
-    assertTrue(acl.getAclBitSet().get(NONE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(CREATE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(READ_ACL.ordinal()));
-    assertTrue(acl.getAclBitSet().get(WRITE_ACL.ordinal()));
-    assertFalse(acl.getAclBitSet().get(ALL.ordinal()));
+    assertTrue(acl.isSet(READ));
+    assertTrue(acl.isSet(WRITE));
+    assertTrue(acl.isSet(DELETE));
+    assertTrue(acl.isSet(LIST));
+    assertTrue(acl.isSet(NONE));
+    assertTrue(acl.isSet(CREATE));
+    assertTrue(acl.isSet(READ_ACL));
+    assertTrue(acl.isSet(WRITE_ACL));
+    assertFalse(acl.isSet(ALL));
     assertEquals(ACLIdentityType.WORLD, acl.getType());
 
     // Acls with scope info.
     acl = OzoneAcl.parseAcl("user:bilbo:rwdlncxy[DEFAULT]");
     assertEquals(acl.getName(), "bilbo");
-    assertTrue(acl.getAclBitSet().get(READ.ordinal()));
-    assertTrue(acl.getAclBitSet().get(WRITE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(DELETE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(LIST.ordinal()));
-    assertTrue(acl.getAclBitSet().get(NONE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(CREATE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(READ_ACL.ordinal()));
-    assertTrue(acl.getAclBitSet().get(WRITE_ACL.ordinal()));
-    assertFalse(acl.getAclBitSet().get(ALL.ordinal()));
+    assertTrue(acl.isSet(READ));
+    assertTrue(acl.isSet(WRITE));
+    assertTrue(acl.isSet(DELETE));
+    assertTrue(acl.isSet(LIST));
+    assertTrue(acl.isSet(NONE));
+    assertTrue(acl.isSet(CREATE));
+    assertTrue(acl.isSet(READ_ACL));
+    assertTrue(acl.isSet(WRITE_ACL));
+    assertFalse(acl.isSet(ALL));
     assertEquals(acl.getAclScope(), OzoneAcl.AclScope.DEFAULT);
 
     acl = OzoneAcl.parseAcl("user:bilbo:rwdlncxy[ACCESS]");
     assertEquals(acl.getName(), "bilbo");
-    assertTrue(acl.getAclBitSet().get(READ.ordinal()));
-    assertTrue(acl.getAclBitSet().get(WRITE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(DELETE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(LIST.ordinal()));
-    assertTrue(acl.getAclBitSet().get(NONE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(CREATE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(READ_ACL.ordinal()));
-    assertTrue(acl.getAclBitSet().get(WRITE_ACL.ordinal()));
-    assertFalse(acl.getAclBitSet().get(ALL.ordinal()));
+    assertTrue(acl.isSet(READ));
+    assertTrue(acl.isSet(WRITE));
+    assertTrue(acl.isSet(DELETE));
+    assertTrue(acl.isSet(LIST));
+    assertTrue(acl.isSet(NONE));
+    assertTrue(acl.isSet(CREATE));
+    assertTrue(acl.isSet(READ_ACL));
+    assertTrue(acl.isSet(WRITE_ACL));
+    assertFalse(acl.isSet(ALL));
     assertEquals(acl.getAclScope(), OzoneAcl.AclScope.ACCESS);
 
     acl = OzoneAcl.parseAcl("group:hadoop:rwdlncxy[ACCESS]");
     assertEquals(acl.getName(), "hadoop");
-    assertTrue(acl.getAclBitSet().get(READ.ordinal()));
-    assertTrue(acl.getAclBitSet().get(WRITE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(DELETE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(LIST.ordinal()));
-    assertTrue(acl.getAclBitSet().get(NONE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(CREATE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(READ_ACL.ordinal()));
-    assertTrue(acl.getAclBitSet().get(WRITE_ACL.ordinal()));
-    assertFalse(acl.getAclBitSet().get(ALL.ordinal()));
+    assertTrue(acl.isSet(READ));
+    assertTrue(acl.isSet(WRITE));
+    assertTrue(acl.isSet(DELETE));
+    assertTrue(acl.isSet(LIST));
+    assertTrue(acl.isSet(NONE));
+    assertTrue(acl.isSet(CREATE));
+    assertTrue(acl.isSet(READ_ACL));
+    assertTrue(acl.isSet(WRITE_ACL));
+    assertFalse(acl.isSet(ALL));
     assertEquals(ACLIdentityType.GROUP, acl.getType());
     assertEquals(acl.getAclScope(), OzoneAcl.AclScope.ACCESS);
 
     acl = OzoneAcl.parseAcl("world::rwdlncxy[DEFAULT]");
     assertEquals(acl.getName(), "WORLD");
-    assertTrue(acl.getAclBitSet().get(READ.ordinal()));
-    assertTrue(acl.getAclBitSet().get(WRITE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(DELETE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(LIST.ordinal()));
-    assertTrue(acl.getAclBitSet().get(NONE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(CREATE.ordinal()));
-    assertTrue(acl.getAclBitSet().get(READ_ACL.ordinal()));
-    assertTrue(acl.getAclBitSet().get(WRITE_ACL.ordinal()));
-    assertFalse(acl.getAclBitSet().get(ALL.ordinal()));
+    assertTrue(acl.isSet(READ));
+    assertTrue(acl.isSet(WRITE));
+    assertTrue(acl.isSet(DELETE));
+    assertTrue(acl.isSet(LIST));
+    assertTrue(acl.isSet(NONE));
+    assertTrue(acl.isSet(CREATE));
+    assertTrue(acl.isSet(READ_ACL));
+    assertTrue(acl.isSet(WRITE_ACL));
+    assertFalse(acl.isSet(ALL));
     assertEquals(ACLIdentityType.WORLD, acl.getType());
     assertEquals(OzoneAcl.AclScope.DEFAULT, acl.getAclScope());
 
diff --git a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOzoneAclUtil.java b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOzoneAclUtil.java
index 7f15786..cebbab7 100644
--- a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOzoneAclUtil.java
+++ b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOzoneAclUtil.java
@@ -27,7 +27,6 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.BitSet;
 import java.util.List;
 
 import static org.apache.hadoop.hdds.conf.OzoneConfiguration.newInstanceOf;
@@ -35,6 +34,7 @@
 import static org.apache.hadoop.ozone.OzoneAcl.AclScope.DEFAULT;
 import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType.GROUP;
 import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType.USER;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotEquals;
@@ -143,9 +143,12 @@
       if (acl.getName().equals(removedAcl.getName()) &&
           acl.getType().equals(removedAcl.getType()) &&
           acl.getAclScope().equals(removedAcl.getAclScope())) {
-        BitSet temp = (BitSet) acl.getAclBitSet().clone();
-        temp.and(removedAcl.getAclBitSet());
-        return !temp.equals(removedAcl.getAclBitSet());
+        for (ACLType t : removedAcl.getAclList()) {
+          if (acl.isSet(t)) {
+            return false;
+          }
+        }
+        return true;
       }
     }
     return true;
@@ -156,9 +159,12 @@
       if (acl.getName().equals(newAcl.getName()) &&
           acl.getType().equals(newAcl.getType()) &&
           acl.getAclScope().equals(newAcl.getAclScope())) {
-        BitSet temp = (BitSet) acl.getAclBitSet().clone();
-        temp.and(newAcl.getAclBitSet());
-        return temp.equals(newAcl.getAclBitSet());
+        for (ACLType t : newAcl.getAclList()) {
+          if (!acl.isSet(t)) {
+            return false;
+          }
+        }
+        return true;
       }
     }
     return false;
@@ -226,7 +232,7 @@
     assertEquals(2, ozoneAcls.size());
     assertNotEquals(ozoneAcls.get(0).getAclScope(),
         ozoneAcls.get(1).getAclScope());
-    assertEquals(ozoneAcls.get(0).getAclBitSet(),
-        ozoneAcls.get(1).getAclBitSet());
+    assertArrayEquals(ozoneAcls.get(0).getAclByteArray(),
+        ozoneAcls.get(1).getAclByteArray());
   }
 }
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOzoneManagerHAWithAllRunning.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOzoneManagerHAWithAllRunning.java
index 8b63136..0a5fab2 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOzoneManagerHAWithAllRunning.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOzoneManagerHAWithAllRunning.java
@@ -59,7 +59,6 @@
 import java.net.InetSocketAddress;
 import java.time.Instant;
 import java.util.ArrayList;
-import java.util.BitSet;
 import java.util.Collections;
 import java.util.List;
 
@@ -609,9 +608,7 @@
     if (givenAcl.getType().equals(existingAcl.getType())
         && givenAcl.getName().equals(existingAcl.getName())
         && givenAcl.getAclScope().equals(existingAcl.getAclScope())) {
-      BitSet bitSet = (BitSet) givenAcl.getAclBitSet().clone();
-      bitSet.and(existingAcl.getAclBitSet());
-      return bitSet.equals(existingAcl.getAclBitSet());
+      return givenAcl.equals(existingAcl);
     }
     return false;
   }
diff --git a/hadoop-ozone/interface-storage/src/main/java/org/apache/hadoop/ozone/om/helpers/OmPrefixInfo.java b/hadoop-ozone/interface-storage/src/main/java/org/apache/hadoop/ozone/om/helpers/OmPrefixInfo.java
index d6fb140..452275a 100644
--- a/hadoop-ozone/interface-storage/src/main/java/org/apache/hadoop/ozone/om/helpers/OmPrefixInfo.java
+++ b/hadoop-ozone/interface-storage/src/main/java/org/apache/hadoop/ozone/om/helpers/OmPrefixInfo.java
@@ -25,13 +25,12 @@
 import org.apache.hadoop.ozone.OzoneAcl;
 import org.apache.hadoop.ozone.storage.proto.OzoneManagerStorageProtos.PersistedPrefixInfo;
 
-import java.util.BitSet;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.stream.Collectors;
 
 /**
  * Wrapper class for Ozone prefix path info, currently mainly target for ACL but
@@ -49,7 +48,7 @@
   }
 
   private String name;
-  private List<OzoneAcl> acls;
+  private final List<OzoneAcl> acls;
 
   public OmPrefixInfo(String name, List<OzoneAcl> acls,
       Map<String, String> metadata, long objectId, long updateId) {
@@ -235,16 +234,11 @@
    * Return a new copy of the object.
    */
   public OmPrefixInfo copyObject() {
-    List<OzoneAcl> aclList = acls.stream().map(acl ->
-        new OzoneAcl(acl.getType(), acl.getName(),
-            (BitSet) acl.getAclBitSet().clone(), acl.getAclScope()))
-        .collect(Collectors.toList());
-
     Map<String, String> metadataList = new HashMap<>();
     if (getMetadata() != null) {
-      getMetadata().forEach((k, v) -> metadataList.put(k, v));
+      metadataList.putAll(getMetadata());
     }
-    return new OmPrefixInfo(name, aclList, metadataList, getObjectID(), getUpdateID());
+    return new OmPrefixInfo(name, new ArrayList<>(acls), metadataList, getObjectID(), getUpdateID());
   }
 }
 
diff --git a/hadoop-ozone/interface-storage/src/main/java/org/apache/hadoop/ozone/om/helpers/OzoneAclStorage.java b/hadoop-ozone/interface-storage/src/main/java/org/apache/hadoop/ozone/om/helpers/OzoneAclStorage.java
index abc6359..22284e1 100644
--- a/hadoop-ozone/interface-storage/src/main/java/org/apache/hadoop/ozone/om/helpers/OzoneAclStorage.java
+++ b/hadoop-ozone/interface-storage/src/main/java/org/apache/hadoop/ozone/om/helpers/OzoneAclStorage.java
@@ -49,7 +49,7 @@
         .setName(acl.getName())
         .setType(OzoneAclType.valueOf(acl.getType().name()))
         .setAclScope(OzoneAclScope.valueOf(acl.getAclScope().name()))
-        .setRights(ByteString.copyFrom(acl.getAclBitSet().toByteArray()));
+        .setRights(ByteString.copyFrom(acl.getAclByteArray()));
     return builder.build();
   }
 
diff --git a/hadoop-ozone/interface-storage/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmPrefixInfo.java b/hadoop-ozone/interface-storage/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmPrefixInfo.java
index 5226f31..a8394b6 100644
--- a/hadoop-ozone/interface-storage/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmPrefixInfo.java
+++ b/hadoop-ozone/interface-storage/src/test/java/org/apache/hadoop/ozone/om/helpers/TestOmPrefixInfo.java
@@ -25,6 +25,7 @@
 import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer;
 import org.junit.jupiter.api.Test;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 
@@ -40,7 +41,7 @@
   private static OzoneManagerStorageProtos.OzoneAclInfo buildTestOzoneAclInfo(
       String aclString) {
     OzoneAcl oacl = OzoneAcl.parseAcl(aclString);
-    ByteString rights = ByteString.copyFrom(oacl.getAclBitSet().toByteArray());
+    ByteString rights = ByteString.copyFrom(oacl.getAclByteArray());
     return OzoneManagerStorageProtos.OzoneAclInfo.newBuilder()
         .setType(OzoneManagerStorageProtos.OzoneAclInfo.OzoneAclType.USER)
         .setName(oacl.getName())
@@ -74,9 +75,9 @@
       IAccessAuthorizer.ACLType aclType,
       OzoneAcl.AclScope scope) {
     return new OmPrefixInfo(path,
-        Collections.singletonList(new OzoneAcl(
+        new ArrayList<>(Collections.singletonList(new OzoneAcl(
             identityType, identityString,
-            aclType, scope)), new HashMap<>(), 10, 100);
+            aclType, scope))), new HashMap<>(), 10, 100);
   }
 
 
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/PrefixManagerImpl.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/PrefixManagerImpl.java
index 47b44f7..e8e9308 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/PrefixManagerImpl.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/PrefixManagerImpl.java
@@ -41,6 +41,7 @@
 import java.util.Objects;
 import java.util.stream.Collectors;
 
+import static org.apache.hadoop.ozone.OzoneAcl.AclScope.ACCESS;
 import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.BUCKET_NOT_FOUND;
 import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.INTERNAL_ERROR;
 import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.PREFIX_NOT_FOUND;
@@ -302,7 +303,7 @@
       OmPrefixInfo parentPrefixInfo = prefixList.get(prefixList.size() - 1);
       if (parentPrefixInfo != null) {
         prefixParentFound = OzoneAclUtil.inheritDefaultAcls(
-            aclsToBeSet, parentPrefixInfo.getAcls());
+            aclsToBeSet, parentPrefixInfo.getAcls(), ACCESS);
       }
     }
 
@@ -313,7 +314,7 @@
       OmBucketInfo bucketInfo = metadataManager.getBucketTable().
           get(bucketKey);
       if (bucketInfo != null) {
-        OzoneAclUtil.inheritDefaultAcls(aclsToBeSet, bucketInfo.getAcls());
+        OzoneAclUtil.inheritDefaultAcls(aclsToBeSet, bucketInfo.getAcls(), ACCESS);
       }
     }
   }
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketCreateRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketCreateRequest.java
index 7cce3ac..f2c343e 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketCreateRequest.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketCreateRequest.java
@@ -67,6 +67,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import static org.apache.hadoop.ozone.OzoneAcl.AclScope.ACCESS;
 import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.BUCKET_ALREADY_EXISTS;
 import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.VOLUME_NOT_FOUND;
 import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.BUCKET_LOCK;
@@ -330,7 +331,7 @@
 
     // Add default acls from volume.
     List<OzoneAcl> defaultVolumeAcls = omVolumeArgs.getDefaultAcls();
-    OzoneAclUtil.inheritDefaultAcls(acls, defaultVolumeAcls);
+    OzoneAclUtil.inheritDefaultAcls(acls, defaultVolumeAcls, ACCESS);
     omBucketInfo.setAcls(acls);
   }
 
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyRequest.java
index 7e4e303..a25c4a5 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyRequest.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyRequest.java
@@ -92,6 +92,8 @@
 
 import static org.apache.hadoop.hdds.protocol.proto.HddsProtos.BlockTokenSecretProto.AccessModeProto.READ;
 import static org.apache.hadoop.hdds.protocol.proto.HddsProtos.BlockTokenSecretProto.AccessModeProto.WRITE;
+import static org.apache.hadoop.ozone.OzoneAcl.AclScope.ACCESS;
+import static org.apache.hadoop.ozone.OzoneAcl.AclScope.DEFAULT;
 import static org.apache.hadoop.ozone.OzoneConsts.OBJECT_ID_RECLAIM_BLOCKS;
 import static org.apache.hadoop.ozone.OzoneConsts.OZONE_URI_DELIMITER;
 import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes
@@ -344,7 +346,7 @@
         // Add all acls from direct parent to key.
         OmPrefixInfo prefixInfo = prefixList.get(prefixList.size() - 1);
         if (prefixInfo  != null) {
-          if (OzoneAclUtil.inheritDefaultAcls(acls, prefixInfo.getAcls())) {
+          if (OzoneAclUtil.inheritDefaultAcls(acls, prefixInfo.getAcls(), ACCESS)) {
             return acls;
           }
         }
@@ -354,7 +356,7 @@
     // Inherit DEFAULT acls from parent-dir only if DEFAULT acls for
     // prefix are not set
     if (omPathInfo != null) {
-      if (OzoneAclUtil.inheritDefaultAcls(acls, omPathInfo.getAcls())) {
+      if (OzoneAclUtil.inheritDefaultAcls(acls, omPathInfo.getAcls(), ACCESS)) {
         return acls;
       }
     }
@@ -362,7 +364,7 @@
     // Inherit DEFAULT acls from bucket only if DEFAULT acls for
     // parent-dir are not set.
     if (bucketInfo != null) {
-      if (OzoneAclUtil.inheritDefaultAcls(acls, bucketInfo.getAcls())) {
+      if (OzoneAclUtil.inheritDefaultAcls(acls, bucketInfo.getAcls(), ACCESS)) {
         return acls;
       }
     }
@@ -384,17 +386,13 @@
 
     // Inherit DEFAULT acls from parent-dir
     if (omPathInfo != null) {
-      if (OzoneAclUtil.inheritDefaultAcls(acls, omPathInfo.getAcls())) {
-        OzoneAclUtil.toDefaultScope(acls);
-      }
+      OzoneAclUtil.inheritDefaultAcls(acls, omPathInfo.getAcls(), DEFAULT);
     }
 
     // Inherit DEFAULT acls from bucket only if DEFAULT acls for
     // parent-dir are not set.
     if (acls.isEmpty() && bucketInfo != null) {
-      if (OzoneAclUtil.inheritDefaultAcls(acls, bucketInfo.getAcls())) {
-        OzoneAclUtil.toDefaultScope(acls);
-      }
+      OzoneAclUtil.inheritDefaultAcls(acls, bucketInfo.getAcls(), DEFAULT);
     }
 
     // add itself acls
diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/file/TestOMFileCreateRequest.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/file/TestOMFileCreateRequest.java
index fbf9c0b..20da9d3 100644
--- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/file/TestOMFileCreateRequest.java
+++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/file/TestOMFileCreateRequest.java
@@ -492,10 +492,10 @@
         if (indx == dirs.size() - 1) {
           // verify file acls
           assertEquals(omDirInfo.getObjectID(), omKeyInfo.getParentObjectID());
-          List<OzoneAcl> fileAcls = omDirInfo.getAcls();
+          List<OzoneAcl> fileAcls = omKeyInfo.getAcls();
           System.out.println("  file acls : " + omKeyInfo + " ==> " + fileAcls);
           assertEquals(expectedInheritAcls.stream()
-                  .map(acl -> acl.setAclScope(OzoneAcl.AclScope.ACCESS))
+                  .map(acl -> acl.withScope(OzoneAcl.AclScope.ACCESS))
                   .collect(Collectors.toList()), fileAcls,
               "Failed to inherit parent DEFAULT acls!");
         }
@@ -514,7 +514,7 @@
       // Should inherit parent DEFAULT acls
       // [user:newUser:rw[ACCESS], group:newGroup:rwl[ACCESS]]
       assertEquals(parentDefaultAcl.stream()
-              .map(acl -> acl.setAclScope(OzoneAcl.AclScope.ACCESS))
+              .map(acl -> acl.withScope(OzoneAcl.AclScope.ACCESS))
               .collect(Collectors.toList()), keyAcls,
           "Failed to inherit bucket DEFAULT acls!");
       // Should not inherit parent ACCESS acls
diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMKeyCreateRequest.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMKeyCreateRequest.java
index 83b4919..0790e2a 100644
--- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMKeyCreateRequest.java
+++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMKeyCreateRequest.java
@@ -920,7 +920,7 @@
 
     // Should inherit parent DEFAULT Acls
     assertEquals(parentDefaultAcl.stream()
-            .map(acl -> acl.setAclScope(OzoneAcl.AclScope.ACCESS))
+            .map(acl -> acl.withScope(OzoneAcl.AclScope.ACCESS))
             .collect(Collectors.toList()), keyAcls,
         "Failed to inherit parent DEFAULT acls!,");
 
diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/multipart/TestS3InitiateMultipartUploadRequest.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/multipart/TestS3InitiateMultipartUploadRequest.java
index 40b0c23..a4c512b 100644
--- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/multipart/TestS3InitiateMultipartUploadRequest.java
+++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/multipart/TestS3InitiateMultipartUploadRequest.java
@@ -224,21 +224,20 @@
 
     List<OzoneAcl> parentDefaultAcl = bucketAcls.stream()
         .filter(acl -> acl.getAclScope() == OzoneAcl.AclScope.DEFAULT)
+        .map(acl -> acl.withScope(OzoneAcl.AclScope.ACCESS))
         .collect(Collectors.toList());
 
-    OzoneAcl parentAccessAcl = bucketAcls.stream()
+    List<OzoneAcl> parentAccessAcl = bucketAcls.stream()
         .filter(acl -> acl.getAclScope() == OzoneAcl.AclScope.ACCESS)
-        .findAny().orElse(null);
+        .collect(Collectors.toList());
 
     // Should inherit parent DEFAULT Acls
     // [user:newUser:rw[DEFAULT], group:newGroup:rwl[DEFAULT]]
-    assertEquals(parentDefaultAcl.stream()
-            .map(acl -> acl.setAclScope(OzoneAcl.AclScope.ACCESS))
-            .collect(Collectors.toList()), keyAcls,
+    assertEquals(parentDefaultAcl, keyAcls,
         "Failed to inherit parent DEFAULT acls!");
 
     // Should not inherit parent ACCESS Acls
-    assertThat(keyAcls).doesNotContain(parentAccessAcl);
+    assertThat(keyAcls).doesNotContainAnyElementsOf(parentAccessAcl);
   }
 
 }
diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/multipart/TestS3InitiateMultipartUploadRequestWithFSO.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/multipart/TestS3InitiateMultipartUploadRequestWithFSO.java
index ab05f92..cbdea75 100644
--- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/multipart/TestS3InitiateMultipartUploadRequestWithFSO.java
+++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/multipart/TestS3InitiateMultipartUploadRequestWithFSO.java
@@ -256,7 +256,7 @@
         List<OzoneAcl> fileAcls = fileInfo.getAcls();
         System.out.println("  file acls : " + fileInfo + " ==> " + fileAcls);
         assertEquals(expectedInheritAcls.stream()
-                .map(acl -> acl.setAclScope(OzoneAcl.AclScope.ACCESS))
+                .map(acl -> acl.withScope(OzoneAcl.AclScope.ACCESS))
                 .collect(Collectors.toList()), fileAcls,
             "Failed to inherit parent DEFAULT acls!");
       }
diff --git a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/common/CommonUtils.java b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/common/CommonUtils.java
index 753804e..f555e55 100644
--- a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/common/CommonUtils.java
+++ b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/common/CommonUtils.java
@@ -38,6 +38,7 @@
 import javax.ws.rs.core.Response;
 
 import java.net.InetSocketAddress;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 
@@ -64,9 +65,9 @@
       IAccessAuthorizer.ACLType aclType,
       OzoneAcl.AclScope scope) {
     return new OmPrefixInfo(path,
-        Collections.singletonList(new OzoneAcl(
+        new ArrayList<>(Collections.singletonList(new OzoneAcl(
             identityType, identityString,
-            aclType, scope)), new HashMap<>(), 10, 100);
+            aclType, scope))), new HashMap<>(), 10, 100);
   }
 
   public void testNSSummaryBasicInfoRoot(