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.XAttrHelper; 025import org.apache.hadoop.hdfs.protocol.*; 026import org.apache.hadoop.ipc.RemoteException; 027import org.apache.hadoop.security.token.Token; 028import org.apache.hadoop.security.token.TokenIdentifier; 029import org.apache.hadoop.util.StringUtils; 030import org.codehaus.jackson.map.ObjectMapper; 031 032import com.google.common.collect.Lists; 033 034import java.io.IOException; 035import java.util.*; 036 037/** JSON Utilities */ 038public class JsonUtil { 039 private static final Object[] EMPTY_OBJECT_ARRAY = {}; 040 041 // Reuse ObjectMapper instance for improving performance. 042 // ObjectMapper is thread safe as long as we always configure instance 043 // before use. We don't have a re-entrant call pattern in WebHDFS, 044 // so we just need to worry about thread-safety. 045 private static final ObjectMapper MAPPER = new ObjectMapper(); 046 047 /** Convert a token object to a Json string. */ 048 public static String toJsonString(final Token<? extends TokenIdentifier> token 049 ) throws IOException { 050 return toJsonString(Token.class, toJsonMap(token)); 051 } 052 053 private static Map<String, Object> toJsonMap( 054 final Token<? extends TokenIdentifier> token) throws IOException { 055 if (token == null) { 056 return null; 057 } 058 059 final Map<String, Object> m = new TreeMap<String, Object>(); 060 m.put("urlString", token.encodeToUrlString()); 061 return m; 062 } 063 064 /** Convert an exception object to a Json string. */ 065 public static String toJsonString(final Exception e) { 066 final Map<String, Object> m = new TreeMap<String, Object>(); 067 m.put("exception", e.getClass().getSimpleName()); 068 m.put("message", e.getMessage()); 069 m.put("javaClassName", e.getClass().getName()); 070 return toJsonString(RemoteException.class, m); 071 } 072 073 private static String toJsonString(final Class<?> clazz, final Object value) { 074 return toJsonString(clazz.getSimpleName(), value); 075 } 076 077 /** Convert a key-value pair to a Json string. */ 078 public static String toJsonString(final String key, final Object value) { 079 final Map<String, Object> m = new TreeMap<String, Object>(); 080 m.put(key, value); 081 try { 082 return MAPPER.writeValueAsString(m); 083 } catch (IOException ignored) { 084 } 085 return null; 086 } 087 088 /** Convert a FsPermission object to a string. */ 089 private static String toString(final FsPermission permission) { 090 return String.format("%o", permission.toShort()); 091 } 092 093 /** Convert a HdfsFileStatus object to a Json string. */ 094 public static String toJsonString(final HdfsFileStatus status, 095 boolean includeType) { 096 if (status == null) { 097 return null; 098 } 099 final Map<String, Object> m = new TreeMap<String, Object>(); 100 m.put("pathSuffix", status.getLocalName()); 101 m.put("type", WebHdfsConstants.PathType.valueOf(status)); 102 if (status.isSymlink()) { 103 m.put("symlink", status.getSymlink()); 104 } 105 106 m.put("length", status.getLen()); 107 m.put("owner", status.getOwner()); 108 m.put("group", status.getGroup()); 109 FsPermission perm = status.getPermission(); 110 m.put("permission", toString(perm)); 111 if (perm.getAclBit()) { 112 m.put("aclBit", true); 113 } 114 if (perm.getEncryptedBit()) { 115 m.put("encBit", true); 116 } 117 m.put("accessTime", status.getAccessTime()); 118 m.put("modificationTime", status.getModificationTime()); 119 m.put("blockSize", status.getBlockSize()); 120 m.put("replication", status.getReplication()); 121 m.put("fileId", status.getFileId()); 122 m.put("childrenNum", status.getChildrenNum()); 123 m.put("storagePolicy", status.getStoragePolicy()); 124 try { 125 return includeType ? 126 toJsonString(FileStatus.class, m) : MAPPER.writeValueAsString(m); 127 } catch (IOException ignored) { 128 } 129 return null; 130 } 131 132 /** Convert an ExtendedBlock to a Json map. */ 133 private static Map<String, Object> toJsonMap(final ExtendedBlock extendedblock) { 134 if (extendedblock == null) { 135 return null; 136 } 137 138 final Map<String, Object> m = new TreeMap<String, Object>(); 139 m.put("blockPoolId", extendedblock.getBlockPoolId()); 140 m.put("blockId", extendedblock.getBlockId()); 141 m.put("numBytes", extendedblock.getNumBytes()); 142 m.put("generationStamp", extendedblock.getGenerationStamp()); 143 return m; 144 } 145 146 /** Convert a DatanodeInfo to a Json map. */ 147 static Map<String, Object> toJsonMap(final DatanodeInfo datanodeinfo) { 148 if (datanodeinfo == null) { 149 return null; 150 } 151 152 // TODO: Fix storageID 153 final Map<String, Object> m = new TreeMap<String, Object>(); 154 m.put("ipAddr", datanodeinfo.getIpAddr()); 155 // 'name' is equivalent to ipAddr:xferPort. Older clients (1.x, 0.23.x) 156 // expects this instead of the two fields. 157 m.put("name", datanodeinfo.getXferAddr()); 158 m.put("hostName", datanodeinfo.getHostName()); 159 m.put("storageID", datanodeinfo.getDatanodeUuid()); 160 m.put("xferPort", datanodeinfo.getXferPort()); 161 m.put("infoPort", datanodeinfo.getInfoPort()); 162 m.put("infoSecurePort", datanodeinfo.getInfoSecurePort()); 163 m.put("ipcPort", datanodeinfo.getIpcPort()); 164 165 m.put("capacity", datanodeinfo.getCapacity()); 166 m.put("dfsUsed", datanodeinfo.getDfsUsed()); 167 m.put("remaining", datanodeinfo.getRemaining()); 168 m.put("blockPoolUsed", datanodeinfo.getBlockPoolUsed()); 169 m.put("cacheCapacity", datanodeinfo.getCacheCapacity()); 170 m.put("cacheUsed", datanodeinfo.getCacheUsed()); 171 m.put("lastUpdate", datanodeinfo.getLastUpdate()); 172 m.put("lastUpdateMonotonic", datanodeinfo.getLastUpdateMonotonic()); 173 m.put("xceiverCount", datanodeinfo.getXceiverCount()); 174 m.put("networkLocation", datanodeinfo.getNetworkLocation()); 175 m.put("adminState", datanodeinfo.getAdminState().name()); 176 if (datanodeinfo.getUpgradeDomain() != null) { 177 m.put("upgradeDomain", datanodeinfo.getUpgradeDomain()); 178 } 179 return m; 180 } 181 182 /** Convert a DatanodeInfo[] to a Json array. */ 183 private static Object[] toJsonArray(final DatanodeInfo[] array) { 184 if (array == null) { 185 return null; 186 } else if (array.length == 0) { 187 return EMPTY_OBJECT_ARRAY; 188 } else { 189 final Object[] a = new Object[array.length]; 190 for(int i = 0; i < array.length; i++) { 191 a[i] = toJsonMap(array[i]); 192 } 193 return a; 194 } 195 } 196 197 /** Convert a StorageType[] to a Json array. */ 198 private static Object[] toJsonArray(final StorageType[] array) { 199 if (array == null) { 200 return null; 201 } else if (array.length == 0) { 202 return EMPTY_OBJECT_ARRAY; 203 } else { 204 final Object[] a = new Object[array.length]; 205 for(int i = 0; i < array.length; i++) { 206 a[i] = array[i]; 207 } 208 return a; 209 } 210 } 211 212 /** Convert a LocatedBlock to a Json map. */ 213 private static Map<String, Object> toJsonMap(final LocatedBlock locatedblock 214 ) throws IOException { 215 if (locatedblock == null) { 216 return null; 217 } 218 219 final Map<String, Object> m = new TreeMap<String, Object>(); 220 m.put("blockToken", toJsonMap(locatedblock.getBlockToken())); 221 m.put("isCorrupt", locatedblock.isCorrupt()); 222 m.put("startOffset", locatedblock.getStartOffset()); 223 m.put("block", toJsonMap(locatedblock.getBlock())); 224 m.put("storageTypes", toJsonArray(locatedblock.getStorageTypes())); 225 m.put("locations", toJsonArray(locatedblock.getLocations())); 226 m.put("cachedLocations", toJsonArray(locatedblock.getCachedLocations())); 227 return m; 228 } 229 230 /** Convert a LocatedBlock[] to a Json array. */ 231 private static Object[] toJsonArray(final List<LocatedBlock> array 232 ) throws IOException { 233 if (array == null) { 234 return null; 235 } else if (array.size() == 0) { 236 return EMPTY_OBJECT_ARRAY; 237 } else { 238 final Object[] a = new Object[array.size()]; 239 for(int i = 0; i < array.size(); i++) { 240 a[i] = toJsonMap(array.get(i)); 241 } 242 return a; 243 } 244 } 245 246 /** Convert LocatedBlocks to a Json string. */ 247 public static String toJsonString(final LocatedBlocks locatedblocks 248 ) throws IOException { 249 if (locatedblocks == null) { 250 return null; 251 } 252 253 final Map<String, Object> m = new TreeMap<String, Object>(); 254 m.put("fileLength", locatedblocks.getFileLength()); 255 m.put("isUnderConstruction", locatedblocks.isUnderConstruction()); 256 257 m.put("locatedBlocks", toJsonArray(locatedblocks.getLocatedBlocks())); 258 m.put("lastLocatedBlock", toJsonMap(locatedblocks.getLastLocatedBlock())); 259 m.put("isLastBlockComplete", locatedblocks.isLastBlockComplete()); 260 return toJsonString(LocatedBlocks.class, m); 261 } 262 263 /** Convert a ContentSummary to a Json string. */ 264 public static String toJsonString(final ContentSummary contentsummary) { 265 if (contentsummary == null) { 266 return null; 267 } 268 269 final Map<String, Object> m = new TreeMap<String, Object>(); 270 m.put("length", contentsummary.getLength()); 271 m.put("fileCount", contentsummary.getFileCount()); 272 m.put("directoryCount", contentsummary.getDirectoryCount()); 273 m.put("quota", contentsummary.getQuota()); 274 m.put("spaceConsumed", contentsummary.getSpaceConsumed()); 275 m.put("spaceQuota", contentsummary.getSpaceQuota()); 276 final Map<String, Map<String, Long>> typeQuota = 277 new TreeMap<String, Map<String, Long>>(); 278 for (StorageType t : StorageType.getTypesSupportingQuota()) { 279 long tQuota = contentsummary.getTypeQuota(t); 280 if (tQuota != HdfsConstants.QUOTA_RESET) { 281 Map<String, Long> type = typeQuota.get(t.toString()); 282 if (type == null) { 283 type = new TreeMap<String, Long>(); 284 typeQuota.put(t.toString(), type); 285 } 286 type.put("quota", contentsummary.getTypeQuota(t)); 287 type.put("consumed", contentsummary.getTypeConsumed(t)); 288 } 289 } 290 m.put("typeQuota", typeQuota); 291 return toJsonString(ContentSummary.class, m); 292 } 293 294 /** Convert a MD5MD5CRC32FileChecksum to a Json string. */ 295 public static String toJsonString(final MD5MD5CRC32FileChecksum checksum) { 296 if (checksum == null) { 297 return null; 298 } 299 300 final Map<String, Object> m = new TreeMap<String, Object>(); 301 m.put("algorithm", checksum.getAlgorithmName()); 302 m.put("length", checksum.getLength()); 303 m.put("bytes", StringUtils.byteToHexString(checksum.getBytes())); 304 return toJsonString(FileChecksum.class, m); 305 } 306 307 /** Convert a AclStatus object to a Json string. */ 308 public static String toJsonString(final AclStatus status) { 309 if (status == null) { 310 return null; 311 } 312 313 final Map<String, Object> m = new TreeMap<String, Object>(); 314 m.put("owner", status.getOwner()); 315 m.put("group", status.getGroup()); 316 m.put("stickyBit", status.isStickyBit()); 317 318 final List<String> stringEntries = new ArrayList<>(); 319 for (AclEntry entry : status.getEntries()) { 320 stringEntries.add(entry.toStringStable()); 321 } 322 m.put("entries", stringEntries); 323 324 FsPermission perm = status.getPermission(); 325 if (perm != null) { 326 m.put("permission", toString(perm)); 327 if (perm.getAclBit()) { 328 m.put("aclBit", true); 329 } 330 if (perm.getEncryptedBit()) { 331 m.put("encBit", true); 332 } 333 } 334 final Map<String, Map<String, Object>> finalMap = 335 new TreeMap<String, Map<String, Object>>(); 336 finalMap.put(AclStatus.class.getSimpleName(), m); 337 338 try { 339 return MAPPER.writeValueAsString(finalMap); 340 } catch (IOException ignored) { 341 } 342 return null; 343 } 344 345 private static Map<String, Object> toJsonMap(final XAttr xAttr, 346 final XAttrCodec encoding) throws IOException { 347 if (xAttr == null) { 348 return null; 349 } 350 351 final Map<String, Object> m = new TreeMap<String, Object>(); 352 m.put("name", XAttrHelper.getPrefixedName(xAttr)); 353 m.put("value", xAttr.getValue() != null ? 354 XAttrCodec.encodeValue(xAttr.getValue(), encoding) : null); 355 return m; 356 } 357 358 private static Object[] toJsonArray(final List<XAttr> array, 359 final XAttrCodec encoding) throws IOException { 360 if (array == null) { 361 return null; 362 } else if (array.size() == 0) { 363 return EMPTY_OBJECT_ARRAY; 364 } else { 365 final Object[] a = new Object[array.size()]; 366 for(int i = 0; i < array.size(); i++) { 367 a[i] = toJsonMap(array.get(i), encoding); 368 } 369 return a; 370 } 371 } 372 373 public static String toJsonString(final List<XAttr> xAttrs, 374 final XAttrCodec encoding) throws IOException { 375 final Map<String, Object> finalMap = new TreeMap<String, Object>(); 376 finalMap.put("XAttrs", toJsonArray(xAttrs, encoding)); 377 return MAPPER.writeValueAsString(finalMap); 378 } 379 380 public static String toJsonString(final List<XAttr> xAttrs) 381 throws IOException { 382 final List<String> names = Lists.newArrayListWithCapacity(xAttrs.size()); 383 for (XAttr xAttr : xAttrs) { 384 names.add(XAttrHelper.getPrefixedName(xAttr)); 385 } 386 String ret = MAPPER.writeValueAsString(names); 387 final Map<String, Object> finalMap = new TreeMap<String, Object>(); 388 finalMap.put("XAttrNames", ret); 389 return MAPPER.writeValueAsString(finalMap); 390 } 391 392 public static String toJsonString(Object obj) throws IOException { 393 return MAPPER.writeValueAsString(obj); 394 } 395 396 public static String toJsonString(BlockStoragePolicy[] storagePolicies) { 397 final Map<String, Object> blockStoragePolicies = new TreeMap<>(); 398 Object[] a = null; 399 if (storagePolicies != null && storagePolicies.length > 0) { 400 a = new Object[storagePolicies.length]; 401 for (int i = 0; i < storagePolicies.length; i++) { 402 a[i] = toJsonMap(storagePolicies[i]); 403 } 404 } 405 blockStoragePolicies.put("BlockStoragePolicy", a); 406 return toJsonString("BlockStoragePolicies", blockStoragePolicies); 407 } 408 409 private static Object toJsonMap(BlockStoragePolicy blockStoragePolicy) { 410 final Map<String, Object> m = new TreeMap<String, Object>(); 411 m.put("id", blockStoragePolicy.getId()); 412 m.put("name", blockStoragePolicy.getName()); 413 m.put("storageTypes", blockStoragePolicy.getStorageTypes()); 414 m.put("creationFallbacks", blockStoragePolicy.getCreationFallbacks()); 415 m.put("replicationFallbacks", blockStoragePolicy.getReplicationFallbacks()); 416 m.put("copyOnCreateFile", blockStoragePolicy.isCopyOnCreateFile()); 417 return m; 418 } 419 420 public static String toJsonString(BlockStoragePolicy storagePolicy) { 421 return toJsonString(BlockStoragePolicy.class, toJsonMap(storagePolicy)); 422 } 423}