001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hdfs.web; 019 020import org.apache.hadoop.fs.*; 021import org.apache.hadoop.fs.permission.AclEntry; 022import org.apache.hadoop.fs.permission.AclStatus; 023import org.apache.hadoop.fs.permission.FsPermission; 024import org.apache.hadoop.hdfs.DFSUtil; 025import org.apache.hadoop.hdfs.XAttrHelper; 026import org.apache.hadoop.hdfs.protocol.*; 027import org.apache.hadoop.hdfs.protocol.DatanodeInfo.AdminStates; 028import org.apache.hadoop.hdfs.security.token.block.BlockTokenIdentifier; 029import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenIdentifier; 030import org.apache.hadoop.hdfs.server.blockmanagement.BlockStoragePolicySuite; 031import org.apache.hadoop.hdfs.server.namenode.INodeId; 032import org.apache.hadoop.ipc.RemoteException; 033import org.apache.hadoop.security.token.Token; 034import org.apache.hadoop.security.token.TokenIdentifier; 035import org.apache.hadoop.util.DataChecksum; 036import org.apache.hadoop.util.StringUtils; 037import org.codehaus.jackson.map.ObjectMapper; 038import org.codehaus.jackson.map.ObjectReader; 039 040import com.google.common.collect.Lists; 041import com.google.common.collect.Maps; 042 043import java.io.ByteArrayInputStream; 044import java.io.DataInputStream; 045import java.io.IOException; 046import java.util.*; 047 048/** JSON Utilities */ 049public class JsonUtil { 050 private static final Object[] EMPTY_OBJECT_ARRAY = {}; 051 private static final DatanodeInfo[] EMPTY_DATANODE_INFO_ARRAY = {}; 052 053 // Reuse ObjectMapper instance for improving performance. 054 // ObjectMapper is thread safe as long as we always configure instance 055 // before use. We don't have a re-entrant call pattern in WebHDFS, 056 // so we just need to worry about thread-safety. 057 private static final ObjectMapper MAPPER = new ObjectMapper(); 058 059 /** Convert a token object to a Json string. */ 060 public static String toJsonString(final Token<? extends TokenIdentifier> token 061 ) throws IOException { 062 return toJsonString(Token.class, toJsonMap(token)); 063 } 064 065 private static Map<String, Object> toJsonMap( 066 final Token<? extends TokenIdentifier> token) throws IOException { 067 if (token == null) { 068 return null; 069 } 070 071 final Map<String, Object> m = new TreeMap<String, Object>(); 072 m.put("urlString", token.encodeToUrlString()); 073 return m; 074 } 075 076 /** Convert a Json map to a Token. */ 077 public static Token<? extends TokenIdentifier> toToken( 078 final Map<?, ?> m) throws IOException { 079 if (m == null) { 080 return null; 081 } 082 083 final Token<DelegationTokenIdentifier> token 084 = new Token<DelegationTokenIdentifier>(); 085 token.decodeFromUrlString((String)m.get("urlString")); 086 return token; 087 } 088 089 /** Convert a Json map to a Token of DelegationTokenIdentifier. */ 090 @SuppressWarnings("unchecked") 091 public static Token<DelegationTokenIdentifier> toDelegationToken( 092 final Map<?, ?> json) throws IOException { 093 final Map<?, ?> m = (Map<?, ?>)json.get(Token.class.getSimpleName()); 094 return (Token<DelegationTokenIdentifier>)toToken(m); 095 } 096 097 /** Convert a Json map to a Token of BlockTokenIdentifier. */ 098 @SuppressWarnings("unchecked") 099 private static Token<BlockTokenIdentifier> toBlockToken( 100 final Map<?, ?> m) throws IOException { 101 return (Token<BlockTokenIdentifier>)toToken(m); 102 } 103 104 /** Convert an exception object to a Json string. */ 105 public static String toJsonString(final Exception e) { 106 final Map<String, Object> m = new TreeMap<String, Object>(); 107 m.put("exception", e.getClass().getSimpleName()); 108 m.put("message", e.getMessage()); 109 m.put("javaClassName", e.getClass().getName()); 110 return toJsonString(RemoteException.class, m); 111 } 112 113 /** Convert a Json map to a RemoteException. */ 114 public static RemoteException toRemoteException(final Map<?, ?> json) { 115 final Map<?, ?> m = (Map<?, ?>)json.get(RemoteException.class.getSimpleName()); 116 final String message = (String)m.get("message"); 117 final String javaClassName = (String)m.get("javaClassName"); 118 return new RemoteException(javaClassName, message); 119 } 120 121 private static String toJsonString(final Class<?> clazz, final Object value) { 122 return toJsonString(clazz.getSimpleName(), value); 123 } 124 125 /** Convert a key-value pair to a Json string. */ 126 public static String toJsonString(final String key, final Object value) { 127 final Map<String, Object> m = new TreeMap<String, Object>(); 128 m.put(key, value); 129 try { 130 return MAPPER.writeValueAsString(m); 131 } catch (IOException ignored) { 132 } 133 return null; 134 } 135 136 /** Convert a FsPermission object to a string. */ 137 private static String toString(final FsPermission permission) { 138 return String.format("%o", permission.toShort()); 139 } 140 141 /** Convert a string to a FsPermission object. */ 142 private static FsPermission toFsPermission(final String s, Boolean aclBit, 143 Boolean encBit) { 144 FsPermission perm = new FsPermission(Short.parseShort(s, 8)); 145 final boolean aBit = (aclBit != null) ? aclBit : false; 146 final boolean eBit = (encBit != null) ? encBit : false; 147 if (aBit || eBit) { 148 return new FsPermissionExtension(perm, aBit, eBit); 149 } else { 150 return perm; 151 } 152 } 153 154 static enum PathType { 155 FILE, DIRECTORY, SYMLINK; 156 157 static PathType valueOf(HdfsFileStatus status) { 158 return status.isDir()? DIRECTORY: status.isSymlink()? SYMLINK: FILE; 159 } 160 } 161 162 /** Convert a HdfsFileStatus object to a Json string. */ 163 public static String toJsonString(final HdfsFileStatus status, 164 boolean includeType) { 165 if (status == null) { 166 return null; 167 } 168 final Map<String, Object> m = new TreeMap<String, Object>(); 169 m.put("pathSuffix", status.getLocalName()); 170 m.put("type", PathType.valueOf(status)); 171 if (status.isSymlink()) { 172 m.put("symlink", status.getSymlink()); 173 } 174 175 m.put("length", status.getLen()); 176 m.put("owner", status.getOwner()); 177 m.put("group", status.getGroup()); 178 FsPermission perm = status.getPermission(); 179 m.put("permission", toString(perm)); 180 if (perm.getAclBit()) { 181 m.put("aclBit", true); 182 } 183 if (perm.getEncryptedBit()) { 184 m.put("encBit", true); 185 } 186 m.put("accessTime", status.getAccessTime()); 187 m.put("modificationTime", status.getModificationTime()); 188 m.put("blockSize", status.getBlockSize()); 189 m.put("replication", status.getReplication()); 190 m.put("fileId", status.getFileId()); 191 m.put("childrenNum", status.getChildrenNum()); 192 m.put("storagePolicy", status.getStoragePolicy()); 193 try { 194 return includeType ? 195 toJsonString(FileStatus.class, m) : MAPPER.writeValueAsString(m); 196 } catch (IOException ignored) { 197 } 198 return null; 199 } 200 201 /** Convert a Json map to a HdfsFileStatus object. */ 202 public static HdfsFileStatus toFileStatus(final Map<?, ?> json, boolean includesType) { 203 if (json == null) { 204 return null; 205 } 206 207 final Map<?, ?> m = includesType ? 208 (Map<?, ?>)json.get(FileStatus.class.getSimpleName()) : json; 209 final String localName = (String) m.get("pathSuffix"); 210 final PathType type = PathType.valueOf((String) m.get("type")); 211 final byte[] symlink = type != PathType.SYMLINK? null 212 : DFSUtil.string2Bytes((String)m.get("symlink")); 213 214 final long len = ((Number) m.get("length")).longValue(); 215 final String owner = (String) m.get("owner"); 216 final String group = (String) m.get("group"); 217 final FsPermission permission = toFsPermission((String) m.get("permission"), 218 (Boolean)m.get("aclBit"), (Boolean)m.get("encBit")); 219 final long aTime = ((Number) m.get("accessTime")).longValue(); 220 final long mTime = ((Number) m.get("modificationTime")).longValue(); 221 final long blockSize = ((Number) m.get("blockSize")).longValue(); 222 final short replication = ((Number) m.get("replication")).shortValue(); 223 final long fileId = m.containsKey("fileId") ? 224 ((Number) m.get("fileId")).longValue() : INodeId.GRANDFATHER_INODE_ID; 225 final int childrenNum = getInt(m, "childrenNum", -1); 226 final byte storagePolicy = m.containsKey("storagePolicy") ? 227 (byte) ((Number) m.get("storagePolicy")).longValue() : 228 BlockStoragePolicySuite.ID_UNSPECIFIED; 229 return new HdfsFileStatus(len, type == PathType.DIRECTORY, replication, 230 blockSize, mTime, aTime, permission, owner, group, symlink, 231 DFSUtil.string2Bytes(localName), fileId, childrenNum, null, storagePolicy); 232 } 233 234 /** Convert an ExtendedBlock to a Json map. */ 235 private static Map<String, Object> toJsonMap(final ExtendedBlock extendedblock) { 236 if (extendedblock == null) { 237 return null; 238 } 239 240 final Map<String, Object> m = new TreeMap<String, Object>(); 241 m.put("blockPoolId", extendedblock.getBlockPoolId()); 242 m.put("blockId", extendedblock.getBlockId()); 243 m.put("numBytes", extendedblock.getNumBytes()); 244 m.put("generationStamp", extendedblock.getGenerationStamp()); 245 return m; 246 } 247 248 /** Convert a Json map to an ExtendedBlock object. */ 249 private static ExtendedBlock toExtendedBlock(final Map<?, ?> m) { 250 if (m == null) { 251 return null; 252 } 253 254 final String blockPoolId = (String)m.get("blockPoolId"); 255 final long blockId = ((Number) m.get("blockId")).longValue(); 256 final long numBytes = ((Number) m.get("numBytes")).longValue(); 257 final long generationStamp = 258 ((Number) m.get("generationStamp")).longValue(); 259 return new ExtendedBlock(blockPoolId, blockId, numBytes, generationStamp); 260 } 261 262 /** Convert a DatanodeInfo to a Json map. */ 263 static Map<String, Object> toJsonMap(final DatanodeInfo datanodeinfo) { 264 if (datanodeinfo == null) { 265 return null; 266 } 267 268 // TODO: Fix storageID 269 final Map<String, Object> m = new TreeMap<String, Object>(); 270 m.put("ipAddr", datanodeinfo.getIpAddr()); 271 // 'name' is equivalent to ipAddr:xferPort. Older clients (1.x, 0.23.x) 272 // expects this instead of the two fields. 273 m.put("name", datanodeinfo.getXferAddr()); 274 m.put("hostName", datanodeinfo.getHostName()); 275 m.put("storageID", datanodeinfo.getDatanodeUuid()); 276 m.put("xferPort", datanodeinfo.getXferPort()); 277 m.put("infoPort", datanodeinfo.getInfoPort()); 278 m.put("infoSecurePort", datanodeinfo.getInfoSecurePort()); 279 m.put("ipcPort", datanodeinfo.getIpcPort()); 280 281 m.put("capacity", datanodeinfo.getCapacity()); 282 m.put("dfsUsed", datanodeinfo.getDfsUsed()); 283 m.put("remaining", datanodeinfo.getRemaining()); 284 m.put("blockPoolUsed", datanodeinfo.getBlockPoolUsed()); 285 m.put("cacheCapacity", datanodeinfo.getCacheCapacity()); 286 m.put("cacheUsed", datanodeinfo.getCacheUsed()); 287 m.put("lastUpdate", datanodeinfo.getLastUpdate()); 288 m.put("lastUpdateMonotonic", datanodeinfo.getLastUpdateMonotonic()); 289 m.put("xceiverCount", datanodeinfo.getXceiverCount()); 290 m.put("networkLocation", datanodeinfo.getNetworkLocation()); 291 m.put("adminState", datanodeinfo.getAdminState().name()); 292 return m; 293 } 294 295 private static int getInt(Map<?, ?> m, String key, final int defaultValue) { 296 Object value = m.get(key); 297 if (value == null) { 298 return defaultValue; 299 } 300 return ((Number) value).intValue(); 301 } 302 303 private static long getLong(Map<?, ?> m, String key, final long defaultValue) { 304 Object value = m.get(key); 305 if (value == null) { 306 return defaultValue; 307 } 308 return ((Number) value).longValue(); 309 } 310 311 private static String getString(Map<?, ?> m, String key, 312 final String defaultValue) { 313 Object value = m.get(key); 314 if (value == null) { 315 return defaultValue; 316 } 317 return (String) value; 318 } 319 320 static List<?> getList(Map<?, ?> m, String key) { 321 Object list = m.get(key); 322 if (list instanceof List<?>) { 323 return (List<?>) list; 324 } else { 325 return null; 326 } 327 } 328 329 /** Convert a Json map to an DatanodeInfo object. */ 330 static DatanodeInfo toDatanodeInfo(final Map<?, ?> m) 331 throws IOException { 332 if (m == null) { 333 return null; 334 } 335 336 // ipAddr and xferPort are the critical fields for accessing data. 337 // If any one of the two is missing, an exception needs to be thrown. 338 339 // Handle the case of old servers (1.x, 0.23.x) sending 'name' instead 340 // of ipAddr and xferPort. 341 int xferPort = getInt(m, "xferPort", -1); 342 Object tmpValue = m.get("ipAddr"); 343 String ipAddr = (tmpValue == null) ? null : (String)tmpValue; 344 if (ipAddr == null) { 345 tmpValue = m.get("name"); 346 if (tmpValue != null) { 347 String name = (String)tmpValue; 348 int colonIdx = name.indexOf(':'); 349 if (colonIdx > 0) { 350 ipAddr = name.substring(0, colonIdx); 351 xferPort = Integer.parseInt(name.substring(colonIdx +1)); 352 } else { 353 throw new IOException( 354 "Invalid value in server response: name=[" + name + "]"); 355 } 356 } else { 357 throw new IOException( 358 "Missing both 'ipAddr' and 'name' in server response."); 359 } 360 // ipAddr is non-null & non-empty string at this point. 361 } 362 363 // Check the validity of xferPort. 364 if (xferPort == -1) { 365 throw new IOException( 366 "Invalid or missing 'xferPort' in server response."); 367 } 368 369 // TODO: Fix storageID 370 return new DatanodeInfo( 371 ipAddr, 372 (String)m.get("hostName"), 373 (String)m.get("storageID"), 374 xferPort, 375 ((Number) m.get("infoPort")).intValue(), 376 getInt(m, "infoSecurePort", 0), 377 ((Number) m.get("ipcPort")).intValue(), 378 379 getLong(m, "capacity", 0l), 380 getLong(m, "dfsUsed", 0l), 381 getLong(m, "remaining", 0l), 382 getLong(m, "blockPoolUsed", 0l), 383 getLong(m, "cacheCapacity", 0l), 384 getLong(m, "cacheUsed", 0l), 385 getLong(m, "lastUpdate", 0l), 386 getLong(m, "lastUpdateMonotonic", 0l), 387 getInt(m, "xceiverCount", 0), 388 getString(m, "networkLocation", ""), 389 AdminStates.valueOf(getString(m, "adminState", "NORMAL"))); 390 } 391 392 /** Convert a DatanodeInfo[] to a Json array. */ 393 private static Object[] toJsonArray(final DatanodeInfo[] array) { 394 if (array == null) { 395 return null; 396 } else if (array.length == 0) { 397 return EMPTY_OBJECT_ARRAY; 398 } else { 399 final Object[] a = new Object[array.length]; 400 for(int i = 0; i < array.length; i++) { 401 a[i] = toJsonMap(array[i]); 402 } 403 return a; 404 } 405 } 406 407 /** Convert an Object[] to a DatanodeInfo[]. */ 408 private static DatanodeInfo[] toDatanodeInfoArray(final List<?> objects) 409 throws IOException { 410 if (objects == null) { 411 return null; 412 } else if (objects.isEmpty()) { 413 return EMPTY_DATANODE_INFO_ARRAY; 414 } else { 415 final DatanodeInfo[] array = new DatanodeInfo[objects.size()]; 416 int i = 0; 417 for (Object object : objects) { 418 array[i++] = toDatanodeInfo((Map<?, ?>) object); 419 } 420 return array; 421 } 422 } 423 424 /** Convert a LocatedBlock to a Json map. */ 425 private static Map<String, Object> toJsonMap(final LocatedBlock locatedblock 426 ) throws IOException { 427 if (locatedblock == null) { 428 return null; 429 } 430 431 final Map<String, Object> m = new TreeMap<String, Object>(); 432 m.put("blockToken", toJsonMap(locatedblock.getBlockToken())); 433 m.put("isCorrupt", locatedblock.isCorrupt()); 434 m.put("startOffset", locatedblock.getStartOffset()); 435 m.put("block", toJsonMap(locatedblock.getBlock())); 436 m.put("locations", toJsonArray(locatedblock.getLocations())); 437 m.put("cachedLocations", toJsonArray(locatedblock.getCachedLocations())); 438 return m; 439 } 440 441 /** Convert a Json map to LocatedBlock. */ 442 private static LocatedBlock toLocatedBlock(final Map<?, ?> m) throws IOException { 443 if (m == null) { 444 return null; 445 } 446 447 final ExtendedBlock b = toExtendedBlock((Map<?, ?>)m.get("block")); 448 final DatanodeInfo[] locations = toDatanodeInfoArray( 449 getList(m, "locations")); 450 final long startOffset = ((Number) m.get("startOffset")).longValue(); 451 final boolean isCorrupt = (Boolean)m.get("isCorrupt"); 452 final DatanodeInfo[] cachedLocations = toDatanodeInfoArray( 453 getList(m, "cachedLocations")); 454 455 final LocatedBlock locatedblock = new LocatedBlock(b, locations, 456 null, null, startOffset, isCorrupt, cachedLocations); 457 locatedblock.setBlockToken(toBlockToken((Map<?, ?>)m.get("blockToken"))); 458 return locatedblock; 459 } 460 461 /** Convert a LocatedBlock[] to a Json array. */ 462 private static Object[] toJsonArray(final List<LocatedBlock> array 463 ) throws IOException { 464 if (array == null) { 465 return null; 466 } else if (array.size() == 0) { 467 return EMPTY_OBJECT_ARRAY; 468 } else { 469 final Object[] a = new Object[array.size()]; 470 for(int i = 0; i < array.size(); i++) { 471 a[i] = toJsonMap(array.get(i)); 472 } 473 return a; 474 } 475 } 476 477 /** Convert an List of Object to a List of LocatedBlock. */ 478 private static List<LocatedBlock> toLocatedBlockList( 479 final List<?> objects) throws IOException { 480 if (objects == null) { 481 return null; 482 } else if (objects.isEmpty()) { 483 return Collections.emptyList(); 484 } else { 485 final List<LocatedBlock> list = new ArrayList<>(objects.size()); 486 for (Object object : objects) { 487 list.add(toLocatedBlock((Map<?, ?>) object)); 488 } 489 return list; 490 } 491 } 492 493 /** Convert LocatedBlocks to a Json string. */ 494 public static String toJsonString(final LocatedBlocks locatedblocks 495 ) throws IOException { 496 if (locatedblocks == null) { 497 return null; 498 } 499 500 final Map<String, Object> m = new TreeMap<String, Object>(); 501 m.put("fileLength", locatedblocks.getFileLength()); 502 m.put("isUnderConstruction", locatedblocks.isUnderConstruction()); 503 504 m.put("locatedBlocks", toJsonArray(locatedblocks.getLocatedBlocks())); 505 m.put("lastLocatedBlock", toJsonMap(locatedblocks.getLastLocatedBlock())); 506 m.put("isLastBlockComplete", locatedblocks.isLastBlockComplete()); 507 return toJsonString(LocatedBlocks.class, m); 508 } 509 510 /** Convert a Json map to LocatedBlock. */ 511 public static LocatedBlocks toLocatedBlocks(final Map<?, ?> json 512 ) throws IOException { 513 if (json == null) { 514 return null; 515 } 516 517 final Map<?, ?> m = (Map<?, ?>)json.get(LocatedBlocks.class.getSimpleName()); 518 final long fileLength = ((Number) m.get("fileLength")).longValue(); 519 final boolean isUnderConstruction = (Boolean)m.get("isUnderConstruction"); 520 final List<LocatedBlock> locatedBlocks = toLocatedBlockList( 521 getList(m, "locatedBlocks")); 522 final LocatedBlock lastLocatedBlock = toLocatedBlock( 523 (Map<?, ?>)m.get("lastLocatedBlock")); 524 final boolean isLastBlockComplete = (Boolean)m.get("isLastBlockComplete"); 525 return new LocatedBlocks(fileLength, isUnderConstruction, locatedBlocks, 526 lastLocatedBlock, isLastBlockComplete, null); 527 } 528 529 /** Convert a ContentSummary to a Json string. */ 530 public static String toJsonString(final ContentSummary contentsummary) { 531 if (contentsummary == null) { 532 return null; 533 } 534 535 final Map<String, Object> m = new TreeMap<String, Object>(); 536 m.put("length", contentsummary.getLength()); 537 m.put("fileCount", contentsummary.getFileCount()); 538 m.put("directoryCount", contentsummary.getDirectoryCount()); 539 m.put("quota", contentsummary.getQuota()); 540 m.put("spaceConsumed", contentsummary.getSpaceConsumed()); 541 m.put("spaceQuota", contentsummary.getSpaceQuota()); 542 return toJsonString(ContentSummary.class, m); 543 } 544 545 /** Convert a Json map to a ContentSummary. */ 546 public static ContentSummary toContentSummary(final Map<?, ?> json) { 547 if (json == null) { 548 return null; 549 } 550 551 final Map<?, ?> m = (Map<?, ?>)json.get(ContentSummary.class.getSimpleName()); 552 final long length = ((Number) m.get("length")).longValue(); 553 final long fileCount = ((Number) m.get("fileCount")).longValue(); 554 final long directoryCount = ((Number) m.get("directoryCount")).longValue(); 555 final long quota = ((Number) m.get("quota")).longValue(); 556 final long spaceConsumed = ((Number) m.get("spaceConsumed")).longValue(); 557 final long spaceQuota = ((Number) m.get("spaceQuota")).longValue(); 558 559 return new ContentSummary.Builder().length(length).fileCount(fileCount). 560 directoryCount(directoryCount).quota(quota).spaceConsumed(spaceConsumed). 561 spaceQuota(spaceQuota).build(); 562 } 563 564 /** Convert a MD5MD5CRC32FileChecksum to a Json string. */ 565 public static String toJsonString(final MD5MD5CRC32FileChecksum checksum) { 566 if (checksum == null) { 567 return null; 568 } 569 570 final Map<String, Object> m = new TreeMap<String, Object>(); 571 m.put("algorithm", checksum.getAlgorithmName()); 572 m.put("length", checksum.getLength()); 573 m.put("bytes", StringUtils.byteToHexString(checksum.getBytes())); 574 return toJsonString(FileChecksum.class, m); 575 } 576 577 /** Convert a Json map to a MD5MD5CRC32FileChecksum. */ 578 public static MD5MD5CRC32FileChecksum toMD5MD5CRC32FileChecksum( 579 final Map<?, ?> json) throws IOException { 580 if (json == null) { 581 return null; 582 } 583 584 final Map<?, ?> m = (Map<?, ?>)json.get(FileChecksum.class.getSimpleName()); 585 final String algorithm = (String)m.get("algorithm"); 586 final int length = ((Number) m.get("length")).intValue(); 587 final byte[] bytes = StringUtils.hexStringToByte((String)m.get("bytes")); 588 589 final DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes)); 590 final DataChecksum.Type crcType = 591 MD5MD5CRC32FileChecksum.getCrcTypeFromAlgorithmName(algorithm); 592 final MD5MD5CRC32FileChecksum checksum; 593 594 // Recreate what DFSClient would have returned. 595 switch(crcType) { 596 case CRC32: 597 checksum = new MD5MD5CRC32GzipFileChecksum(); 598 break; 599 case CRC32C: 600 checksum = new MD5MD5CRC32CastagnoliFileChecksum(); 601 break; 602 default: 603 throw new IOException("Unknown algorithm: " + algorithm); 604 } 605 checksum.readFields(in); 606 607 //check algorithm name 608 if (!checksum.getAlgorithmName().equals(algorithm)) { 609 throw new IOException("Algorithm not matched. Expected " + algorithm 610 + ", Received " + checksum.getAlgorithmName()); 611 } 612 //check length 613 if (length != checksum.getLength()) { 614 throw new IOException("Length not matched: length=" + length 615 + ", checksum.getLength()=" + checksum.getLength()); 616 } 617 618 return checksum; 619 } 620 /** Convert a AclStatus object to a Json string. */ 621 public static String toJsonString(final AclStatus status) { 622 if (status == null) { 623 return null; 624 } 625 626 final Map<String, Object> m = new TreeMap<String, Object>(); 627 m.put("owner", status.getOwner()); 628 m.put("group", status.getGroup()); 629 m.put("stickyBit", status.isStickyBit()); 630 631 final List<String> stringEntries = new ArrayList<>(); 632 for (AclEntry entry : status.getEntries()) { 633 stringEntries.add(entry.toString()); 634 } 635 m.put("entries", stringEntries); 636 637 FsPermission perm = status.getPermission(); 638 if (perm != null) { 639 m.put("permission", toString(perm)); 640 if (perm.getAclBit()) { 641 m.put("aclBit", true); 642 } 643 if (perm.getEncryptedBit()) { 644 m.put("encBit", true); 645 } 646 } 647 final Map<String, Map<String, Object>> finalMap = 648 new TreeMap<String, Map<String, Object>>(); 649 finalMap.put(AclStatus.class.getSimpleName(), m); 650 651 try { 652 return MAPPER.writeValueAsString(finalMap); 653 } catch (IOException ignored) { 654 } 655 return null; 656 } 657 658 /** Convert a Json map to a AclStatus object. */ 659 public static AclStatus toAclStatus(final Map<?, ?> json) { 660 if (json == null) { 661 return null; 662 } 663 664 final Map<?, ?> m = (Map<?, ?>) json.get(AclStatus.class.getSimpleName()); 665 666 AclStatus.Builder aclStatusBuilder = new AclStatus.Builder(); 667 aclStatusBuilder.owner((String) m.get("owner")); 668 aclStatusBuilder.group((String) m.get("group")); 669 aclStatusBuilder.stickyBit((Boolean) m.get("stickyBit")); 670 String permString = (String) m.get("permission"); 671 if (permString != null) { 672 final FsPermission permission = toFsPermission(permString, 673 (Boolean) m.get("aclBit"), (Boolean) m.get("encBit")); 674 aclStatusBuilder.setPermission(permission); 675 } 676 final List<?> entries = (List<?>) m.get("entries"); 677 678 List<AclEntry> aclEntryList = new ArrayList<AclEntry>(); 679 for (Object entry : entries) { 680 AclEntry aclEntry = AclEntry.parseAclEntry((String) entry, true); 681 aclEntryList.add(aclEntry); 682 } 683 aclStatusBuilder.addEntries(aclEntryList); 684 return aclStatusBuilder.build(); 685 } 686 687 private static Map<String, Object> toJsonMap(final XAttr xAttr, 688 final XAttrCodec encoding) throws IOException { 689 if (xAttr == null) { 690 return null; 691 } 692 693 final Map<String, Object> m = new TreeMap<String, Object>(); 694 m.put("name", XAttrHelper.getPrefixName(xAttr)); 695 m.put("value", xAttr.getValue() != null ? 696 XAttrCodec.encodeValue(xAttr.getValue(), encoding) : null); 697 return m; 698 } 699 700 private static Object[] toJsonArray(final List<XAttr> array, 701 final XAttrCodec encoding) throws IOException { 702 if (array == null) { 703 return null; 704 } else if (array.size() == 0) { 705 return EMPTY_OBJECT_ARRAY; 706 } else { 707 final Object[] a = new Object[array.size()]; 708 for(int i = 0; i < array.size(); i++) { 709 a[i] = toJsonMap(array.get(i), encoding); 710 } 711 return a; 712 } 713 } 714 715 public static String toJsonString(final List<XAttr> xAttrs, 716 final XAttrCodec encoding) throws IOException { 717 final Map<String, Object> finalMap = new TreeMap<String, Object>(); 718 finalMap.put("XAttrs", toJsonArray(xAttrs, encoding)); 719 return MAPPER.writeValueAsString(finalMap); 720 } 721 722 public static String toJsonString(final List<XAttr> xAttrs) 723 throws IOException { 724 final List<String> names = Lists.newArrayListWithCapacity(xAttrs.size()); 725 for (XAttr xAttr : xAttrs) { 726 names.add(XAttrHelper.getPrefixName(xAttr)); 727 } 728 String ret = MAPPER.writeValueAsString(names); 729 final Map<String, Object> finalMap = new TreeMap<String, Object>(); 730 finalMap.put("XAttrNames", ret); 731 return MAPPER.writeValueAsString(finalMap); 732 } 733 734 public static byte[] getXAttr(final Map<?, ?> json, final String name) 735 throws IOException { 736 if (json == null) { 737 return null; 738 } 739 740 Map<String, byte[]> xAttrs = toXAttrs(json); 741 if (xAttrs != null) { 742 return xAttrs.get(name); 743 } 744 745 return null; 746 } 747 748 public static Map<String, byte[]> toXAttrs(final Map<?, ?> json) 749 throws IOException { 750 if (json == null) { 751 return null; 752 } 753 return toXAttrMap(getList(json, "XAttrs")); 754 } 755 756 public static List<String> toXAttrNames(final Map<?, ?> json) 757 throws IOException { 758 if (json == null) { 759 return null; 760 } 761 762 final String namesInJson = (String) json.get("XAttrNames"); 763 ObjectReader reader = new ObjectMapper().reader(List.class); 764 final List<Object> xattrs = reader.readValue(namesInJson); 765 final List<String> names = 766 Lists.newArrayListWithCapacity(json.keySet().size()); 767 768 for (Object xattr : xattrs) { 769 names.add((String) xattr); 770 } 771 return names; 772 } 773 774 private static Map<String, byte[]> toXAttrMap(final List<?> objects) 775 throws IOException { 776 if (objects == null) { 777 return null; 778 } else if (objects.isEmpty()) { 779 return Maps.newHashMap(); 780 } else { 781 final Map<String, byte[]> xAttrs = Maps.newHashMap(); 782 for (Object object : objects) { 783 Map<?, ?> m = (Map<?, ?>) object; 784 String name = (String) m.get("name"); 785 String value = (String) m.get("value"); 786 xAttrs.put(name, decodeXAttrValue(value)); 787 } 788 return xAttrs; 789 } 790 } 791 792 private static byte[] decodeXAttrValue(String value) throws IOException { 793 if (value != null) { 794 return XAttrCodec.decodeValue(value); 795 } else { 796 return new byte[0]; 797 } 798 } 799}