diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntry.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntry.java index 45402f8a2f7..b42c36525a8 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntry.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntry.java @@ -36,7 +36,7 @@ import org.apache.hadoop.util.StringUtils; * to create a new instance. */ @InterfaceAudience.Public -@InterfaceStability.Evolving +@InterfaceStability.Stable public class AclEntry { private final AclEntryType type; private final String name; @@ -100,13 +100,29 @@ public class AclEntry { } @Override + @InterfaceStability.Unstable public String toString() { + // This currently just delegates to the stable string representation, but it + // is permissible for the output of this method to change across versions. + return toStringStable(); + } + + /** + * Returns a string representation guaranteed to be stable across versions to + * satisfy backward compatibility requirements, such as for shell command + * output or serialization. The format of this string representation matches + * what is expected by the {@link #parseAclSpec(String, boolean)} and + * {@link #parseAclEntry(String, boolean)} methods. + * + * @return stable, backward compatible string representation + */ + public String toStringStable() { StringBuilder sb = new StringBuilder(); if (scope == AclEntryScope.DEFAULT) { sb.append("default:"); } if (type != null) { - sb.append(StringUtils.toLowerCase(type.toString())); + sb.append(StringUtils.toLowerCase(type.toStringStable())); } sb.append(':'); if (name != null) { @@ -203,6 +219,8 @@ public class AclEntry { /** * Parses a string representation of an ACL spec into a list of AclEntry * objects. Example: "user::rwx,user:foo:rw-,group::r--,other::---" + * The expected format of ACL entries in the string parameter is the same + * format produced by the {@link #toStringStable()} method. * * @param aclSpec * String representation of an ACL spec. @@ -228,6 +246,8 @@ public class AclEntry { /** * Parses a string representation of an ACL into a AclEntry object.
+ * The expected format of ACL entries in the string parameter is the same + * format produced by the {@link #toStringStable()} method. * * @param aclStr * String representation of an ACL.
diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntryScope.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntryScope.java index 6d941e7117d..64c70aa8ca8 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntryScope.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntryScope.java @@ -24,7 +24,7 @@ import org.apache.hadoop.classification.InterfaceStability; * Specifies the scope or intended usage of an ACL entry. */ @InterfaceAudience.Public -@InterfaceStability.Evolving +@InterfaceStability.Stable public enum AclEntryScope { /** * An ACL entry that is inspected during permission checks to enforce diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntryType.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntryType.java index ffd62d7080b..002ead2b6a9 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntryType.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntryType.java @@ -24,7 +24,7 @@ import org.apache.hadoop.classification.InterfaceStability; * Specifies the type of an ACL entry. */ @InterfaceAudience.Public -@InterfaceStability.Evolving +@InterfaceStability.Stable public enum AclEntryType { /** * An ACL entry applied to a specific user. These ACL entries can be unnamed, @@ -55,4 +55,25 @@ public enum AclEntryType { * of the more specific ACL entry types. */ OTHER; + + @Override + @InterfaceStability.Unstable + public String toString() { + // This currently just delegates to the stable string representation, but it + // is permissible for the output of this method to change across versions. + return toStringStable(); + } + + /** + * Returns a string representation guaranteed to be stable across versions to + * satisfy backward compatibility requirements, such as for shell command + * output or serialization. + * + * @return stable, backward compatible string representation + */ + public String toStringStable() { + // The base implementation uses the enum value names, which are public API + // and therefore stable. + return super.toString(); + } } diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclStatus.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclStatus.java index 9d7500a697b..131aa199435 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclStatus.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclStatus.java @@ -31,7 +31,7 @@ import com.google.common.collect.Lists; * instances are immutable. Use a {@link Builder} to create a new instance. */ @InterfaceAudience.Public -@InterfaceStability.Evolving +@InterfaceStability.Stable public class AclStatus { private final String owner; private final String group; diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/AclCommands.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/AclCommands.java index 9a5404032b0..a5e386c785e 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/AclCommands.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/AclCommands.java @@ -117,7 +117,7 @@ class AclCommands extends FsCommand { } if (AclUtil.isMinimalAcl(entries)) { for (AclEntry entry: entries) { - out.println(entry); + out.println(entry.toStringStable()); } } else { for (AclEntry entry: entries) { @@ -145,10 +145,10 @@ class AclCommands extends FsCommand { out.println(String.format("%s\t#effective:%s", entry, effectivePerm.SYMBOL)); } else { - out.println(entry); + out.println(entry.toStringStable()); } } else { - out.println(entry); + out.println(entry.toStringStable()); } } } diff --git a/hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/web/resources/AclPermissionParam.java b/hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/web/resources/AclPermissionParam.java index 48f202c4f57..130c8fd6cf6 100644 --- a/hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/web/resources/AclPermissionParam.java +++ b/hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/web/resources/AclPermissionParam.java @@ -20,11 +20,11 @@ package org.apache.hadoop.hdfs.web.resources; import static org.apache.hadoop.hdfs.client.HdfsClientConfigKeys .DFS_WEBHDFS_ACL_PERMISSION_PATTERN_DEFAULT; +import java.util.Iterator; import java.util.List; import java.util.regex.Pattern; import org.apache.hadoop.fs.permission.AclEntry; -import org.apache.commons.lang.StringUtils; /** AclPermission parameter. */ public class AclPermissionParam extends StringParam { @@ -63,7 +63,24 @@ public class AclPermissionParam extends StringParam { /** * @return parse {@code aclEntry} and return aclspec */ - private static String parseAclSpec(List aclEntry) { - return StringUtils.join(aclEntry, ","); + private static String parseAclSpec(List aclEntries) { + if (aclEntries == null) { + return null; + } + if (aclEntries.isEmpty()) { + return ""; + } + if (aclEntries.size() == 1) { + AclEntry entry = aclEntries.get(0); + return entry == null ? "" : entry.toStringStable(); + } + StringBuilder sb = new StringBuilder(); + Iterator iter = aclEntries.iterator(); + sb.append(iter.next().toStringStable()); + while (iter.hasNext()) { + AclEntry entry = iter.next(); + sb.append(',').append(entry == null ? "" : entry.toStringStable()); + } + return sb.toString(); } } diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/JsonUtil.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/JsonUtil.java index 33477eecdb9..ac9ab77dd6c 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/JsonUtil.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/JsonUtil.java @@ -360,7 +360,7 @@ public class JsonUtil { final List stringEntries = new ArrayList<>(); for (AclEntry entry : status.getEntries()) { - stringEntries.add(entry.toString()); + stringEntries.add(entry.toStringStable()); } m.put("entries", stringEntries);