Author: yliu Date: Tue May 20 02:59:18 2014 New Revision: 1596104 URL: http://svn.apache.org/r1596104 Log: HDFS-6259. Support extended attributes via WebHDFS. Contributed by Yi Liu.
Added: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/XAttrEncodingParam.java hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/XAttrNameParam.java hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/XAttrSetFlagParam.java hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/XAttrValueParam.java hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/TestWebHDFSXAttr.java Modified: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/CHANGES-HDFS-2006.txt hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/web/resources/NamenodeWebHdfsMethods.java hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/JsonUtil.java hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/WebHdfsFileSystem.java hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/GetOpParam.java hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/PutOpParam.java hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/FSXAttrBaseTest.java hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/TestJsonUtil.java hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/resources/TestParam.java Modified: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/CHANGES-HDFS-2006.txt URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/CHANGES-HDFS-2006.txt?rev=1596104&r1=1596103&r2=1596104&view=diff ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/CHANGES-HDFS-2006.txt (original) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/CHANGES-HDFS-2006.txt Tue May 20 02:59:18 2014 @@ -38,6 +38,8 @@ HDFS-2006 (Unreleased) HDFS-6412. Interface audience and stability annotations missing from several new classes related to xattrs. (wang) + HDFS-6259. Support extended attributes via WebHDFS. (yliu) + OPTIMIZATIONS HDFS-6346. Optimize OP_SET_XATTRS by persisting single Xattr entry per setXattr/removeXattr api call Modified: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/web/resources/NamenodeWebHdfsMethods.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/web/resources/NamenodeWebHdfsMethods.java?rev=1596104&r1=1596103&r2=1596104&view=diff ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/web/resources/NamenodeWebHdfsMethods.java (original) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/web/resources/NamenodeWebHdfsMethods.java Tue May 20 02:59:18 2014 @@ -28,6 +28,7 @@ import java.net.URISyntaxException; import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.EnumSet; +import java.util.List; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; @@ -53,8 +54,10 @@ import org.apache.hadoop.conf.Configurat import org.apache.hadoop.fs.ContentSummary; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.Options; +import org.apache.hadoop.fs.XAttr; import org.apache.hadoop.fs.permission.AclStatus; import org.apache.hadoop.hdfs.StorageType; +import org.apache.hadoop.hdfs.XAttrHelper; import org.apache.hadoop.hdfs.protocol.DatanodeInfo; import org.apache.hadoop.hdfs.protocol.DirectoryListing; import org.apache.hadoop.hdfs.protocol.HdfsFileStatus; @@ -101,6 +104,10 @@ import org.apache.hadoop.hdfs.web.resour import org.apache.hadoop.hdfs.web.resources.TokenArgumentParam; import org.apache.hadoop.hdfs.web.resources.UriFsPathParam; import org.apache.hadoop.hdfs.web.resources.UserParam; +import org.apache.hadoop.hdfs.web.resources.XAttrEncodingParam; +import org.apache.hadoop.hdfs.web.resources.XAttrNameParam; +import org.apache.hadoop.hdfs.web.resources.XAttrSetFlagParam; +import org.apache.hadoop.hdfs.web.resources.XAttrValueParam; import org.apache.hadoop.io.Text; import org.apache.hadoop.ipc.Server; import org.apache.hadoop.net.NetworkTopology.InvalidTopologyException; @@ -341,12 +348,19 @@ public class NamenodeWebHdfsMethods { @QueryParam(TokenArgumentParam.NAME) @DefaultValue(TokenArgumentParam.DEFAULT) final TokenArgumentParam delegationTokenArgument, @QueryParam(AclPermissionParam.NAME) @DefaultValue(AclPermissionParam.DEFAULT) - final AclPermissionParam aclPermission + final AclPermissionParam aclPermission, + @QueryParam(XAttrNameParam.NAME) @DefaultValue(XAttrNameParam.DEFAULT) + final XAttrNameParam xattrName, + @QueryParam(XAttrValueParam.NAME) @DefaultValue(XAttrValueParam.DEFAULT) + final XAttrValueParam xattrValue, + @QueryParam(XAttrSetFlagParam.NAME) @DefaultValue(XAttrSetFlagParam.DEFAULT) + final XAttrSetFlagParam xattrSetFlag )throws IOException, InterruptedException { return put(ugi, delegation, username, doAsUser, ROOT, op, destination, owner, group, permission, overwrite, bufferSize, replication, blockSize, modificationTime, accessTime, renameOptions, createParent, - delegationTokenArgument,aclPermission); + delegationTokenArgument,aclPermission, xattrName, xattrValue, + xattrSetFlag); } /** Handle HTTP PUT request. */ @@ -392,12 +406,19 @@ public class NamenodeWebHdfsMethods { @QueryParam(TokenArgumentParam.NAME) @DefaultValue(TokenArgumentParam.DEFAULT) final TokenArgumentParam delegationTokenArgument, @QueryParam(AclPermissionParam.NAME) @DefaultValue(AclPermissionParam.DEFAULT) - final AclPermissionParam aclPermission + final AclPermissionParam aclPermission, + @QueryParam(XAttrNameParam.NAME) @DefaultValue(XAttrNameParam.DEFAULT) + final XAttrNameParam xattrName, + @QueryParam(XAttrValueParam.NAME) @DefaultValue(XAttrValueParam.DEFAULT) + final XAttrValueParam xattrValue, + @QueryParam(XAttrSetFlagParam.NAME) @DefaultValue(XAttrSetFlagParam.DEFAULT) + final XAttrSetFlagParam xattrSetFlag ) throws IOException, InterruptedException { init(ugi, delegation, username, doAsUser, path, op, destination, owner, group, permission, overwrite, bufferSize, replication, blockSize, - modificationTime, accessTime, renameOptions, delegationTokenArgument,aclPermission); + modificationTime, accessTime, renameOptions, delegationTokenArgument,aclPermission, + xattrName, xattrValue, xattrSetFlag); return ugi.doAs(new PrivilegedExceptionAction<Response>() { @Override @@ -407,7 +428,8 @@ public class NamenodeWebHdfsMethods { path.getAbsolutePath(), op, destination, owner, group, permission, overwrite, bufferSize, replication, blockSize, modificationTime, accessTime, renameOptions, createParent, - delegationTokenArgument,aclPermission); + delegationTokenArgument,aclPermission, xattrName, + xattrValue, xattrSetFlag); } finally { reset(); } @@ -435,7 +457,10 @@ public class NamenodeWebHdfsMethods { final RenameOptionSetParam renameOptions, final CreateParentParam createParent, final TokenArgumentParam delegationTokenArgument, - final AclPermissionParam aclPermission + final AclPermissionParam aclPermission, + final XAttrNameParam xattrName, + final XAttrValueParam xattrValue, + final XAttrSetFlagParam xattrSetFlag ) throws IOException, URISyntaxException { final Configuration conf = (Configuration)context.getAttribute(JspHelper.CURRENT_CONF); @@ -535,6 +560,15 @@ public class NamenodeWebHdfsMethods { np.setAcl(fullpath, aclPermission.getAclPermission(true)); return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build(); } + case SETXATTR: { + np.setXAttr(fullpath, XAttrHelper.buildXAttr(xattrName.getXAttrName(), + xattrValue.getXAttrValue()), xattrSetFlag.getFlag()); + return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build(); + } + case REMOVEXATTR: { + np.removeXAttr(fullpath, XAttrHelper.buildXAttr(xattrName.getXAttrName())); + return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build(); + } default: throw new UnsupportedOperationException(op + " is not supported"); } @@ -650,10 +684,14 @@ public class NamenodeWebHdfsMethods { @QueryParam(RenewerParam.NAME) @DefaultValue(RenewerParam.DEFAULT) final RenewerParam renewer, @QueryParam(BufferSizeParam.NAME) @DefaultValue(BufferSizeParam.DEFAULT) - final BufferSizeParam bufferSize + final BufferSizeParam bufferSize, + @QueryParam(XAttrNameParam.NAME) @DefaultValue(XAttrNameParam.DEFAULT) + final XAttrNameParam xattrName, + @QueryParam(XAttrEncodingParam.NAME) @DefaultValue(XAttrEncodingParam.DEFAULT) + final XAttrEncodingParam xattrEncoding ) throws IOException, InterruptedException { return get(ugi, delegation, username, doAsUser, ROOT, op, - offset, length, renewer, bufferSize); + offset, length, renewer, bufferSize, xattrName, xattrEncoding); } /** Handle HTTP GET request. */ @@ -678,18 +716,23 @@ public class NamenodeWebHdfsMethods { @QueryParam(RenewerParam.NAME) @DefaultValue(RenewerParam.DEFAULT) final RenewerParam renewer, @QueryParam(BufferSizeParam.NAME) @DefaultValue(BufferSizeParam.DEFAULT) - final BufferSizeParam bufferSize + final BufferSizeParam bufferSize, + @QueryParam(XAttrNameParam.NAME) @DefaultValue(XAttrNameParam.DEFAULT) + final XAttrNameParam xattrName, + @QueryParam(XAttrEncodingParam.NAME) @DefaultValue(XAttrEncodingParam.DEFAULT) + final XAttrEncodingParam xattrEncoding ) throws IOException, InterruptedException { init(ugi, delegation, username, doAsUser, path, op, - offset, length, renewer, bufferSize); + offset, length, renewer, bufferSize, xattrName, xattrEncoding); return ugi.doAs(new PrivilegedExceptionAction<Response>() { @Override public Response run() throws IOException, URISyntaxException { try { return get(ugi, delegation, username, doAsUser, - path.getAbsolutePath(), op, offset, length, renewer, bufferSize); + path.getAbsolutePath(), op, offset, length, renewer, bufferSize, + xattrName, xattrEncoding); } finally { reset(); } @@ -707,7 +750,9 @@ public class NamenodeWebHdfsMethods { final OffsetParam offset, final LengthParam length, final RenewerParam renewer, - final BufferSizeParam bufferSize + final BufferSizeParam bufferSize, + final XAttrNameParam xattrName, + final XAttrEncodingParam xattrEncoding ) throws IOException, URISyntaxException { final NameNode namenode = (NameNode)context.getAttribute("name.node"); final NamenodeProtocols np = getRPCServer(namenode); @@ -782,6 +827,17 @@ public class NamenodeWebHdfsMethods { final String js = JsonUtil.toJsonString(status); return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); } + case GETXATTR: { + XAttr xAttr = XAttrHelper.getFirstXAttr(np.getXAttrs(fullpath, + XAttrHelper.buildXAttrAsList(xattrName.getXAttrName()))); + final String js = JsonUtil.toJsonString(xAttr, xattrEncoding.getEncoding()); + return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); + } + case GETXATTRS: { + List<XAttr> xAttrs = np.getXAttrs(fullpath, null); + final String js = JsonUtil.toJsonString(xAttrs, xattrEncoding.getEncoding()); + return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); + } default: throw new UnsupportedOperationException(op + " is not supported"); } Modified: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/JsonUtil.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/JsonUtil.java?rev=1596104&r1=1596103&r2=1596104&view=diff ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/JsonUtil.java (original) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/JsonUtil.java Tue May 20 02:59:18 2014 @@ -22,6 +22,7 @@ import org.apache.hadoop.fs.permission.A import org.apache.hadoop.fs.permission.AclStatus; import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.hdfs.DFSUtil; +import org.apache.hadoop.hdfs.XAttrHelper; import org.apache.hadoop.hdfs.protocol.*; import org.apache.hadoop.hdfs.protocol.DatanodeInfo.AdminStates; import org.apache.hadoop.hdfs.security.token.block.BlockTokenIdentifier; @@ -34,6 +35,8 @@ import org.apache.hadoop.util.DataChecks import org.apache.hadoop.util.StringUtils; import org.mortbay.util.ajax.JSON; +import com.google.common.collect.Maps; + import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; @@ -661,4 +664,125 @@ public class JsonUtil { aclStatusBuilder.addEntries(aclEntryList); return aclStatusBuilder.build(); } + + public static String toJsonString(final XAttr xAttr, + final XAttrCodec encoding) throws IOException { + if (xAttr == null) { + return "{}"; + } + final Map<String, Object> m = new TreeMap<String, Object>(); + m.put("name", XAttrHelper.getPrefixName(xAttr)); + m.put("value", xAttr.getValue() != null ? + XAttrCodec.encodeValue(xAttr.getValue(), encoding) : null); + final Map<String, Map<String, Object>> finalMap = + new TreeMap<String, Map<String, Object>>(); + finalMap.put(XAttr.class.getSimpleName(), m); + return JSON.toString(finalMap); + } + + private static Map<String, Object> toJsonMap(final XAttr xAttr, + final XAttrCodec encoding) throws IOException { + if (xAttr == null) { + return null; + } + + final Map<String, Object> m = new TreeMap<String, Object>(); + m.put("name", XAttrHelper.getPrefixName(xAttr)); + m.put("value", xAttr.getValue() != null ? + XAttrCodec.encodeValue(xAttr.getValue(), encoding) : null); + return m; + } + + private static Object[] toJsonArray(final List<XAttr> array, + final XAttrCodec encoding) throws IOException { + if (array == null) { + return null; + } else if (array.size() == 0) { + return EMPTY_OBJECT_ARRAY; + } else { + final Object[] a = new Object[array.size()]; + for(int i = 0; i < array.size(); i++) { + a[i] = toJsonMap(array.get(i), encoding); + } + return a; + } + } + + public static String toJsonString(final List<XAttr> xAttrs, + final XAttrCodec encoding) throws IOException { + final Map<String, Object> finalMap = new TreeMap<String, Object>(); + finalMap.put("XAttrs", toJsonArray(xAttrs, encoding)); + return JSON.toString(finalMap); + } + + public static XAttr toXAttr(final Map<?, ?> json) throws IOException { + if (json == null) { + return null; + } + + Map<?, ?> m = (Map<?, ?>) json.get(XAttr.class.getSimpleName()); + if (m == null) { + return null; + } + String name = (String) m.get("name"); + String value = (String) m.get("value"); + return XAttrHelper.buildXAttr(name, decodeXAttrValue(value)); + } + + public static Map<String, byte[]> toXAttrs(final Map<?, ?> json) + throws IOException { + if (json == null) { + return null; + } + + return toXAttrMap((Object[])json.get("XAttrs")); + } + + public static Map<String, byte[]> toXAttrs(final Map<?, ?> json, + List<String> names) throws IOException { + if (json == null || names == null) { + return null; + } + if (names.isEmpty()) { + return Maps.newHashMap(); + } + Map<String, byte[]> xAttrs = toXAttrs(json); + if (xAttrs == null || xAttrs.isEmpty()) { + return xAttrs; + } + + Map<String, byte[]> result = Maps.newHashMap(); + for (String name : names) { + if (xAttrs.containsKey(name)) { + result.put(name, xAttrs.get(name)); + } + } + return result; + } + + private static Map<String, byte[]> toXAttrMap(final Object[] objects) + throws IOException { + if (objects == null) { + return null; + } else if (objects.length == 0) { + return Maps.newHashMap(); + } else { + final Map<String, byte[]> xAttrs = Maps.newHashMap(); + for(int i = 0; i < objects.length; i++) { + Map<?, ?> m = (Map<?, ?>) objects[i]; + String name = (String) m.get("name"); + String value = (String) m.get("value"); + xAttrs.put(name, decodeXAttrValue(value)); + } + return xAttrs; + } + } + + private static byte[] decodeXAttrValue(String value) throws IOException { + if (value != null) { + return XAttrCodec.decodeValue(value); + } else { + return new byte[0]; + } + } } Modified: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/WebHdfsFileSystem.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/WebHdfsFileSystem.java?rev=1596104&r1=1596103&r2=1596104&view=diff ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/WebHdfsFileSystem.java (original) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/WebHdfsFileSystem.java Tue May 20 02:59:18 2014 @@ -30,6 +30,7 @@ import java.net.URI; import java.net.URL; import java.security.PrivilegedExceptionAction; import java.util.ArrayList; +import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.StringTokenizer; @@ -49,6 +50,9 @@ import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.MD5MD5CRC32FileChecksum; import org.apache.hadoop.fs.Options; import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.XAttr; +import org.apache.hadoop.fs.XAttrCodec; +import org.apache.hadoop.fs.XAttrSetFlag; import org.apache.hadoop.fs.permission.AclEntry; import org.apache.hadoop.fs.permission.AclStatus; import org.apache.hadoop.fs.permission.FsPermission; @@ -813,6 +817,66 @@ public class WebHdfsFileSystem extends F new RenameOptionSetParam(options) ).run(); } + + @Override + public void setXAttr(Path p, String name, byte[] value, + EnumSet<XAttrSetFlag> flag) throws IOException { + statistics.incrementWriteOps(1); + final HttpOpParam.Op op = PutOpParam.Op.SETXATTR; + if (value != null) { + new FsPathRunner(op, p, new XAttrNameParam(name), new XAttrValueParam( + XAttrCodec.encodeValue(value, XAttrCodec.HEX)), + new XAttrSetFlagParam(flag)).run(); + } else { + new FsPathRunner(op, p, new XAttrNameParam(name), + new XAttrSetFlagParam(flag)).run(); + } + } + + @Override + public byte[] getXAttr(Path p, String name) throws IOException { + final HttpOpParam.Op op = GetOpParam.Op.GETXATTR; + return new FsPathResponseRunner<byte[]>(op, p, new XAttrNameParam(name), + new XAttrEncodingParam(XAttrCodec.HEX)) { + @Override + byte[] decodeResponse(Map<?, ?> json) throws IOException { + XAttr xAttr = JsonUtil.toXAttr(json); + return xAttr != null ? xAttr.getValue() : null; + } + }.run(); + } + + @Override + public Map<String, byte[]> getXAttrs(Path p) throws IOException { + final HttpOpParam.Op op = GetOpParam.Op.GETXATTRS; + return new FsPathResponseRunner<Map<String, byte[]>>(op, p, + new XAttrEncodingParam(XAttrCodec.HEX)) { + @Override + Map<String, byte[]> decodeResponse(Map<?, ?> json) throws IOException { + return JsonUtil.toXAttrs(json); + } + }.run(); + } + + @Override + public Map<String, byte[]> getXAttrs(Path p, final List<String> names) + throws IOException { + final HttpOpParam.Op op = GetOpParam.Op.GETXATTRS; + return new FsPathResponseRunner<Map<String, byte[]>>(op, p, + new XAttrEncodingParam(XAttrCodec.HEX)) { + @Override + Map<String, byte[]> decodeResponse(Map<?, ?> json) throws IOException { + return JsonUtil.toXAttrs(json, names); + } + }.run(); + } + + @Override + public void removeXAttr(Path p, String name) throws IOException { + statistics.incrementWriteOps(1); + final HttpOpParam.Op op = PutOpParam.Op.REMOVEXATTR; + new FsPathRunner(op, p, new XAttrNameParam(name)).run(); + } @Override public void setOwner(final Path p, final String owner, final String group Modified: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/GetOpParam.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/GetOpParam.java?rev=1596104&r1=1596103&r2=1596104&view=diff ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/GetOpParam.java (original) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/GetOpParam.java Tue May 20 02:59:18 2014 @@ -36,6 +36,8 @@ public class GetOpParam extends HttpOpPa /** GET_BLOCK_LOCATIONS is a private unstable op. */ GET_BLOCK_LOCATIONS(false, HttpURLConnection.HTTP_OK), GETACLSTATUS(false, HttpURLConnection.HTTP_OK), + GETXATTR(false, HttpURLConnection.HTTP_OK), + GETXATTRS(false, HttpURLConnection.HTTP_OK), NULL(false, HttpURLConnection.HTTP_NOT_IMPLEMENTED); Modified: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/PutOpParam.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/PutOpParam.java?rev=1596104&r1=1596103&r2=1596104&view=diff ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/PutOpParam.java (original) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/PutOpParam.java Tue May 20 02:59:18 2014 @@ -42,6 +42,8 @@ public class PutOpParam extends HttpOpPa REMOVEDEFAULTACL(false, HttpURLConnection.HTTP_OK), REMOVEACL(false, HttpURLConnection.HTTP_OK), SETACL(false, HttpURLConnection.HTTP_OK), + SETXATTR(false, HttpURLConnection.HTTP_OK), + REMOVEXATTR(false, HttpURLConnection.HTTP_OK), NULL(false, HttpURLConnection.HTTP_NOT_IMPLEMENTED); Added: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/XAttrEncodingParam.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/XAttrEncodingParam.java?rev=1596104&view=auto ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/XAttrEncodingParam.java (added) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/XAttrEncodingParam.java Tue May 20 02:59:18 2014 @@ -0,0 +1,56 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.hadoop.hdfs.web.resources; + +import org.apache.hadoop.fs.XAttrCodec; + +public class XAttrEncodingParam extends EnumParam<XAttrCodec> { + /** Parameter name. */ + public static final String NAME = "encoding"; + /** Default parameter value. */ + public static final String DEFAULT = ""; + + private static final Domain<XAttrCodec> DOMAIN = + new Domain<XAttrCodec>(NAME, XAttrCodec.class); + + public XAttrEncodingParam(final XAttrCodec encoding) { + super(DOMAIN, encoding); + } + + /** + * Constructor. + * @param str a string representation of the parameter value. + */ + public XAttrEncodingParam(final String str) { + super(DOMAIN, str != null && !str.isEmpty() ? DOMAIN.parse(str) : null); + } + + @Override + public String getName() { + return NAME; + } + + @Override + public String getValueString() { + return value.toString(); + } + + public XAttrCodec getEncoding() { + return getValue(); + } +} Added: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/XAttrNameParam.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/XAttrNameParam.java?rev=1596104&view=auto ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/XAttrNameParam.java (added) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/XAttrNameParam.java Tue May 20 02:59:18 2014 @@ -0,0 +1,44 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.hadoop.hdfs.web.resources; + +import java.util.regex.Pattern; + +public class XAttrNameParam extends StringParam { + /** Parameter name. **/ + public static final String NAME = "xattr.name"; + /** Default parameter value. **/ + public static final String DEFAULT = ""; + + private static Domain DOMAIN = new Domain(NAME, + Pattern.compile("^(user\\.|trusted\\.|system\\.|security\\.).+")); + + public XAttrNameParam(final String str) { + super(DOMAIN, str == null || str.equals(DEFAULT) ? null : str); + } + + @Override + public String getName() { + return NAME; + } + + public String getXAttrName() { + final String v = getValue(); + return v; + } +} Added: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/XAttrSetFlagParam.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/XAttrSetFlagParam.java?rev=1596104&view=auto ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/XAttrSetFlagParam.java (added) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/XAttrSetFlagParam.java Tue May 20 02:59:18 2014 @@ -0,0 +1,53 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.hadoop.hdfs.web.resources; + +import java.util.EnumSet; + +import org.apache.hadoop.fs.XAttrSetFlag; + +public class XAttrSetFlagParam extends EnumSetParam<XAttrSetFlag> { + /** Parameter name. */ + public static final String NAME = "flag"; + /** Default parameter value. */ + public static final String DEFAULT = ""; + + private static final Domain<XAttrSetFlag> DOMAIN = new Domain<XAttrSetFlag>( + NAME, XAttrSetFlag.class); + + public XAttrSetFlagParam(final EnumSet<XAttrSetFlag> flag) { + super(DOMAIN, flag); + } + + /** + * Constructor. + * @param str a string representation of the parameter value. + */ + public XAttrSetFlagParam(final String str) { + super(DOMAIN, DOMAIN.parse(str)); + } + + @Override + public String getName() { + return NAME; + } + + public EnumSet<XAttrSetFlag> getFlag() { + return getValue(); + } +} Added: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/XAttrValueParam.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/XAttrValueParam.java?rev=1596104&view=auto ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/XAttrValueParam.java (added) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/XAttrValueParam.java Tue May 20 02:59:18 2014 @@ -0,0 +1,45 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.hadoop.hdfs.web.resources; + +import java.io.IOException; + +import org.apache.hadoop.fs.XAttrCodec; + +public class XAttrValueParam extends StringParam { + /** Parameter name. **/ + public static final String NAME = "xattr.value"; + /** Default parameter value. **/ + public static final String DEFAULT = ""; + + private static Domain DOMAIN = new Domain(NAME, null); + + public XAttrValueParam(final String str) { + super(DOMAIN, str == null || str.equals(DEFAULT) ? null : str); + } + + @Override + public String getName() { + return NAME; + } + + public byte[] getXAttrValue() throws IOException { + final String v = getValue(); + return XAttrCodec.decodeValue(v); + } +} Modified: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/FSXAttrBaseTest.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/FSXAttrBaseTest.java?rev=1596104&r1=1596103&r2=1596104&view=diff ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/FSXAttrBaseTest.java (original) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/FSXAttrBaseTest.java Tue May 20 02:59:18 2014 @@ -32,6 +32,7 @@ import org.apache.hadoop.hdfs.DFSConfigK import org.apache.hadoop.hdfs.HdfsConfiguration; import org.apache.hadoop.hdfs.MiniDFSCluster; import org.apache.hadoop.io.IOUtils; +import org.apache.hadoop.ipc.RemoteException; import org.apache.hadoop.test.GenericTestUtils; import org.junit.After; import org.junit.AfterClass; @@ -231,6 +232,8 @@ public class FSXAttrBaseTest { Assert.fail("Setting xattr with null name should fail."); } catch (NullPointerException e) { GenericTestUtils.assertExceptionContains("XAttr name cannot be null", e); + } catch (RemoteException e) { + GenericTestUtils.assertExceptionContains("XAttr name cannot be null", e); } // Set xattr with empty name: "user." @@ -240,6 +243,9 @@ public class FSXAttrBaseTest { Assert.fail("Setting xattr with empty name should fail."); } catch (HadoopIllegalArgumentException e) { GenericTestUtils.assertExceptionContains("XAttr name cannot be empty", e); + } catch (IllegalArgumentException e) { + GenericTestUtils.assertExceptionContains("Invalid value: \"user.\" does " + + "not belong to the domain ^(user\\.|trusted\\.|system\\.|security\\.).+", e); } // Set xattr with invalid name: "a1" @@ -250,6 +256,9 @@ public class FSXAttrBaseTest { "name prefix should fail."); } catch (HadoopIllegalArgumentException e) { GenericTestUtils.assertExceptionContains("XAttr name must be prefixed", e); + } catch (IllegalArgumentException e) { + GenericTestUtils.assertExceptionContains("Invalid value: \"a1\" does " + + "not belong to the domain ^(user\\.|trusted\\.|system\\.|security\\.).+", e); } // Set xattr without XAttrSetFlag Modified: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/TestJsonUtil.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/TestJsonUtil.java?rev=1596104&r1=1596103&r2=1596104&view=diff ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/TestJsonUtil.java (original) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/TestJsonUtil.java Tue May 20 02:59:18 2014 @@ -22,16 +22,22 @@ import static org.apache.hadoop.fs.permi import static org.apache.hadoop.fs.permission.FsAction.*; import static org.apache.hadoop.hdfs.server.namenode.AclTestHelpers.*; +import java.io.IOException; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.XAttr; +import org.apache.hadoop.fs.XAttrCodec; import org.apache.hadoop.fs.permission.AclEntry; import org.apache.hadoop.fs.permission.AclStatus; import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.hdfs.DFSUtil; +import org.apache.hadoop.hdfs.XAttrHelper; import org.apache.hadoop.hdfs.protocol.DatanodeInfo; import org.apache.hadoop.hdfs.protocol.HdfsFileStatus; import org.apache.hadoop.hdfs.server.namenode.INodeId; @@ -186,6 +192,48 @@ public class TestJsonUtil { JsonUtil.toJsonString(aclStatusBuilder.build())); } + + @Test + public void testToJsonFromXAttrs() throws IOException { + String jsonString = + "{\"XAttrs\":[{\"name\":\"user.a1\",\"value\":\"0x313233\"}," + + "{\"name\":\"user.a2\",\"value\":\"0x313131\"}]}"; + XAttr xAttr1 = (new XAttr.Builder()).setNameSpace(XAttr.NameSpace.USER). + setName("a1").setValue(XAttrCodec.decodeValue("0x313233")).build(); + XAttr xAttr2 = (new XAttr.Builder()).setNameSpace(XAttr.NameSpace.USER). + setName("a2").setValue(XAttrCodec.decodeValue("0x313131")).build(); + List<XAttr> xAttrs = Lists.newArrayList(); + xAttrs.add(xAttr1); + xAttrs.add(xAttr2); + + Assert.assertEquals(jsonString, JsonUtil.toJsonString(xAttrs, + XAttrCodec.HEX)); + } + + @Test + public void testToXAttrMap() throws IOException { + String jsonString = + "{\"XAttrs\":[{\"name\":\"user.a1\",\"value\":\"0x313233\"}," + + "{\"name\":\"user.a2\",\"value\":\"0x313131\"}]}"; + Map<?, ?> json = (Map<?, ?>)JSON.parse(jsonString); + XAttr xAttr1 = (new XAttr.Builder()).setNameSpace(XAttr.NameSpace.USER). + setName("a1").setValue(XAttrCodec.decodeValue("0x313233")).build(); + XAttr xAttr2 = (new XAttr.Builder()).setNameSpace(XAttr.NameSpace.USER). + setName("a2").setValue(XAttrCodec.decodeValue("0x313131")).build(); + List<XAttr> xAttrs = Lists.newArrayList(); + xAttrs.add(xAttr1); + xAttrs.add(xAttr2); + Map<String, byte[]> xAttrMap = XAttrHelper.buildXAttrMap(xAttrs); + Map<String, byte[]> parsedXAttrMap = JsonUtil.toXAttrs(json); + + Assert.assertEquals(xAttrMap.size(), parsedXAttrMap.size()); + Iterator<Entry<String, byte[]>> iter = xAttrMap.entrySet().iterator(); + while(iter.hasNext()) { + Entry<String, byte[]> entry = iter.next(); + Assert.assertArrayEquals(entry.getValue(), + parsedXAttrMap.get(entry.getKey())); + } + } private void checkDecodeFailure(Map<String, Object> map) { try { Added: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/TestWebHDFSXAttr.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/TestWebHDFSXAttr.java?rev=1596104&view=auto ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/TestWebHDFSXAttr.java (added) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/TestWebHDFSXAttr.java Tue May 20 02:59:18 2014 @@ -0,0 +1,36 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.hadoop.hdfs.web; + +import org.apache.hadoop.hdfs.server.namenode.FSXAttrBaseTest; + +/** + * Tests XAttr APIs via WebHDFS. + */ +public class TestWebHDFSXAttr extends FSXAttrBaseTest { + /** + * Overridden to provide a WebHdfsFileSystem wrapper for the super-user. + * + * @return WebHdfsFileSystem for super-user + * @throws Exception if creation fails + */ + @Override + protected WebHdfsFileSystem createFileSystem() throws Exception { + return WebHdfsTestUtil.getWebHdfsFileSystem(conf, WebHdfsFileSystem.SCHEME); + } +} Modified: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/resources/TestParam.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/resources/TestParam.java?rev=1596104&r1=1596103&r2=1596104&view=diff ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/resources/TestParam.java (original) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/resources/TestParam.java Tue May 20 02:59:18 2014 @@ -20,6 +20,7 @@ package org.apache.hadoop.hdfs.web.resou import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import java.io.IOException; import java.util.Arrays; import java.util.EnumSet; import java.util.List; @@ -30,6 +31,8 @@ import org.apache.hadoop.conf.Configurat import org.apache.hadoop.fs.CommonConfigurationKeysPublic; import org.apache.hadoop.fs.Options; import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.XAttrCodec; +import org.apache.hadoop.fs.XAttrSetFlag; import org.apache.hadoop.fs.permission.AclEntry; import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.hdfs.DFSConfigKeys; @@ -349,6 +352,43 @@ public class TestParam { } @Test + public void testXAttrNameParam() { + final XAttrNameParam p = new XAttrNameParam("user.a1"); + Assert.assertEquals(p.getXAttrName(), "user.a1"); + try { + new XAttrNameParam("a1"); + Assert.fail(); + } catch (IllegalArgumentException e) { + LOG.info("EXPECTED: " + e); + } + } + + @Test + public void testXAttrValueParam() throws IOException { + final XAttrValueParam p = new XAttrValueParam("0x313233"); + Assert.assertArrayEquals(p.getXAttrValue(), + XAttrCodec.decodeValue("0x313233")); + } + + @Test + public void testXAttrEncodingParam() { + final XAttrEncodingParam p = new XAttrEncodingParam(XAttrCodec.BASE64); + Assert.assertEquals(p.getEncoding(), XAttrCodec.BASE64); + final XAttrEncodingParam p1 = new XAttrEncodingParam(p.getValueString()); + Assert.assertEquals(p1.getEncoding(), XAttrCodec.BASE64); + } + + @Test + public void testXAttrSetFlagParam() { + EnumSet<XAttrSetFlag> flag = EnumSet.of( + XAttrSetFlag.CREATE, XAttrSetFlag.REPLACE); + final XAttrSetFlagParam p = new XAttrSetFlagParam(flag); + Assert.assertEquals(p.getFlag(), flag); + final XAttrSetFlagParam p1 = new XAttrSetFlagParam(p.getValueString()); + Assert.assertEquals(p1.getFlag(), flag); + } + + @Test public void testRenameOptionSetParam() { final RenameOptionSetParam p = new RenameOptionSetParam( Options.Rename.OVERWRITE, Options.Rename.NONE);