HADOOP-13150. Avoid use of toString() in output of HDFS ACL shell commands. Contributed by Chris Nauroth.

(cherry picked from commit 1d330fbaf6)
This commit is contained in:
Chris Nauroth 2016-10-06 12:45:11 -07:00
parent ecccb114ae
commit a28ffd0fde
7 changed files with 70 additions and 12 deletions

View File

@ -36,7 +36,7 @@
* to create a new instance. * to create a new instance.
*/ */
@InterfaceAudience.Public @InterfaceAudience.Public
@InterfaceStability.Evolving @InterfaceStability.Stable
public class AclEntry { public class AclEntry {
private final AclEntryType type; private final AclEntryType type;
private final String name; private final String name;
@ -100,13 +100,29 @@ public int hashCode() {
} }
@Override @Override
@InterfaceStability.Unstable
public String toString() { 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(); StringBuilder sb = new StringBuilder();
if (scope == AclEntryScope.DEFAULT) { if (scope == AclEntryScope.DEFAULT) {
sb.append("default:"); sb.append("default:");
} }
if (type != null) { if (type != null) {
sb.append(StringUtils.toLowerCase(type.toString())); sb.append(StringUtils.toLowerCase(type.toStringStable()));
} }
sb.append(':'); sb.append(':');
if (name != null) { if (name != null) {
@ -203,6 +219,8 @@ private AclEntry(AclEntryType type, String name, FsAction permission, AclEntrySc
/** /**
* Parses a string representation of an ACL spec into a list of AclEntry * Parses a string representation of an ACL spec into a list of AclEntry
* objects. Example: "user::rwx,user:foo:rw-,group::r--,other::---" * 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 * @param aclSpec
* String representation of an ACL spec. * String representation of an ACL spec.
@ -228,6 +246,8 @@ public static List<AclEntry> parseAclSpec(String aclSpec,
/** /**
* Parses a string representation of an ACL into a AclEntry object.<br> * Parses a string representation of an ACL into a AclEntry object.<br>
* The expected format of ACL entries in the string parameter is the same
* format produced by the {@link #toStringStable()} method.
* *
* @param aclStr * @param aclStr
* String representation of an ACL.<br> * String representation of an ACL.<br>

View File

@ -24,7 +24,7 @@
* Specifies the scope or intended usage of an ACL entry. * Specifies the scope or intended usage of an ACL entry.
*/ */
@InterfaceAudience.Public @InterfaceAudience.Public
@InterfaceStability.Evolving @InterfaceStability.Stable
public enum AclEntryScope { public enum AclEntryScope {
/** /**
* An ACL entry that is inspected during permission checks to enforce * An ACL entry that is inspected during permission checks to enforce

View File

@ -24,7 +24,7 @@
* Specifies the type of an ACL entry. * Specifies the type of an ACL entry.
*/ */
@InterfaceAudience.Public @InterfaceAudience.Public
@InterfaceStability.Evolving @InterfaceStability.Stable
public enum AclEntryType { public enum AclEntryType {
/** /**
* An ACL entry applied to a specific user. These ACL entries can be unnamed, * 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. * of the more specific ACL entry types.
*/ */
OTHER; 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();
}
} }

View File

@ -31,7 +31,7 @@
* instances are immutable. Use a {@link Builder} to create a new instance. * instances are immutable. Use a {@link Builder} to create a new instance.
*/ */
@InterfaceAudience.Public @InterfaceAudience.Public
@InterfaceStability.Evolving @InterfaceStability.Stable
public class AclStatus { public class AclStatus {
private final String owner; private final String owner;
private final String group; private final String group;

View File

@ -117,7 +117,7 @@ private void printAclEntriesForSingleScope(AclStatus aclStatus,
} }
if (AclUtil.isMinimalAcl(entries)) { if (AclUtil.isMinimalAcl(entries)) {
for (AclEntry entry: entries) { for (AclEntry entry: entries) {
out.println(entry); out.println(entry.toStringStable());
} }
} else { } else {
for (AclEntry entry: entries) { for (AclEntry entry: entries) {
@ -145,10 +145,10 @@ private void printExtendedAclEntry(AclStatus aclStatus,
out.println(String.format("%s\t#effective:%s", entry, out.println(String.format("%s\t#effective:%s", entry,
effectivePerm.SYMBOL)); effectivePerm.SYMBOL));
} else { } else {
out.println(entry); out.println(entry.toStringStable());
} }
} else { } else {
out.println(entry); out.println(entry.toStringStable());
} }
} }
} }

View File

@ -20,11 +20,11 @@
import static org.apache.hadoop.hdfs.client.HdfsClientConfigKeys import static org.apache.hadoop.hdfs.client.HdfsClientConfigKeys
.DFS_WEBHDFS_ACL_PERMISSION_PATTERN_DEFAULT; .DFS_WEBHDFS_ACL_PERMISSION_PATTERN_DEFAULT;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.hadoop.fs.permission.AclEntry; import org.apache.hadoop.fs.permission.AclEntry;
import org.apache.commons.lang.StringUtils;
/** AclPermission parameter. */ /** AclPermission parameter. */
public class AclPermissionParam extends StringParam { public class AclPermissionParam extends StringParam {
@ -63,7 +63,24 @@ public List<AclEntry> getAclPermission(boolean includePermission) {
/** /**
* @return parse {@code aclEntry} and return aclspec * @return parse {@code aclEntry} and return aclspec
*/ */
private static String parseAclSpec(List<AclEntry> aclEntry) { private static String parseAclSpec(List<AclEntry> aclEntries) {
return StringUtils.join(aclEntry, ","); 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<AclEntry> 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();
} }
} }

View File

@ -360,7 +360,7 @@ public static String toJsonString(final AclStatus status) {
final List<String> stringEntries = new ArrayList<>(); final List<String> stringEntries = new ArrayList<>();
for (AclEntry entry : status.getEntries()) { for (AclEntry entry : status.getEntries()) {
stringEntries.add(entry.toString()); stringEntries.add(entry.toStringStable());
} }
m.put("entries", stringEntries); m.put("entries", stringEntries);