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