1717 */
1818package org .apache .hadoop .hdfs .server .namenode ;
1919
20+ import com .fasterxml .jackson .core .JsonFactory ;
21+ import com .fasterxml .jackson .core .JsonGenerator ;
2022import org .apache .hadoop .classification .InterfaceAudience ;
2123import org .apache .hadoop .hdfs .server .blockmanagement .BlockManager ;
2224import org .apache .hadoop .net .NetUtils ;
2325import org .apache .hadoop .net .Node ;
2426import org .apache .hadoop .net .NodeBase ;
27+ import org .apache .hadoop .thirdparty .com .google .common .annotations .VisibleForTesting ;
2528import org .apache .hadoop .util .StringUtils ;
2629
2730import javax .servlet .ServletContext ;
2831import javax .servlet .http .HttpServletRequest ;
2932import javax .servlet .http .HttpServletResponse ;
33+ import javax .ws .rs .core .HttpHeaders ;
3034import java .io .IOException ;
3135import java .io .PrintStream ;
3236import java .util .ArrayList ;
@@ -44,19 +48,29 @@ public class NetworkTopologyServlet extends DfsServlet {
4448
4549 public static final String PATH_SPEC = "/topology" ;
4650
51+ protected static final String FORMAT_JSON = "json" ;
52+ protected static final String FORMAT_TEXT = "text" ;
53+
4754 @ Override
4855 public void doGet (HttpServletRequest request , HttpServletResponse response )
4956 throws IOException {
5057 final ServletContext context = getServletContext ();
58+
59+ String format = parseAcceptHeader (request );
60+ if (FORMAT_TEXT .equals (format )) {
61+ response .setContentType ("text/plain; charset=UTF-8" );
62+ } else if (FORMAT_JSON .equals (format )) {
63+ response .setContentType ("application/json; charset=UTF-8" );
64+ }
65+
5166 NameNode nn = NameNodeHttpServer .getNameNodeFromContext (context );
5267 BlockManager bm = nn .getNamesystem ().getBlockManager ();
5368 List <Node > leaves = bm .getDatanodeManager ().getNetworkTopology ()
5469 .getLeaves (NodeBase .ROOT );
5570
56- response .setContentType ("text/plain; charset=UTF-8" );
5771 try (PrintStream out = new PrintStream (
5872 response .getOutputStream (), false , "UTF-8" )) {
59- printTopology (out , leaves );
73+ printTopology (out , leaves , format );
6074 } catch (Throwable t ) {
6175 String errMsg = "Print network topology failed. "
6276 + StringUtils .stringifyException (t );
@@ -74,8 +88,10 @@ public void doGet(HttpServletRequest request, HttpServletResponse response)
7488 *
7589 * @param stream print stream
7690 * @param leaves leaves nodes under base scope
91+ * @param format the response format
7792 */
78- public void printTopology (PrintStream stream , List <Node > leaves ) {
93+ public void printTopology (PrintStream stream , List <Node > leaves ,
94+ String format ) throws BadFormatException , IOException {
7995 if (leaves .isEmpty ()) {
8096 stream .print ("No DataNodes" );
8197 return ;
@@ -95,6 +111,49 @@ public void printTopology(PrintStream stream, List<Node> leaves) {
95111 ArrayList <String > racks = new ArrayList <>(tree .keySet ());
96112 Collections .sort (racks );
97113
114+ if (FORMAT_JSON .equals (format )) {
115+ printJsonFormat (stream , tree , racks );
116+ } else if (FORMAT_TEXT .equals (format )) {
117+ printTextFormat (stream , tree , racks );
118+ } else {
119+ throw new BadFormatException ("Bad format: " + format );
120+ }
121+ }
122+
123+ private void printJsonFormat (PrintStream stream , Map <String ,
124+ TreeSet <String >> tree , ArrayList <String > racks ) throws IOException {
125+ JsonFactory dumpFactory = new JsonFactory ();
126+ JsonGenerator dumpGenerator = dumpFactory .createGenerator (stream );
127+ dumpGenerator .writeStartArray ();
128+
129+ for (String r : racks ) {
130+ dumpGenerator .writeStartObject ();
131+ dumpGenerator .writeFieldName (r );
132+ TreeSet <String > nodes = tree .get (r );
133+ dumpGenerator .writeStartArray ();
134+
135+ for (String n : nodes ) {
136+ dumpGenerator .writeStartObject ();
137+ dumpGenerator .writeStringField ("ip" , n );
138+ String hostname = NetUtils .getHostNameOfIP (n );
139+ if (hostname != null ) {
140+ dumpGenerator .writeStringField ("hostname" , hostname );
141+ }
142+ dumpGenerator .writeEndObject ();
143+ }
144+ dumpGenerator .writeEndArray ();
145+ dumpGenerator .writeEndObject ();
146+ }
147+ dumpGenerator .writeEndArray ();
148+ dumpGenerator .flush ();
149+
150+ if (!dumpGenerator .isClosed ()) {
151+ dumpGenerator .close ();
152+ }
153+ }
154+
155+ private void printTextFormat (PrintStream stream , Map <String ,
156+ TreeSet <String >> tree , ArrayList <String > racks ) {
98157 for (String r : racks ) {
99158 stream .println ("Rack: " + r );
100159 TreeSet <String > nodes = tree .get (r );
@@ -110,4 +169,19 @@ public void printTopology(PrintStream stream, List<Node> leaves) {
110169 stream .println ();
111170 }
112171 }
172+
173+ @ VisibleForTesting
174+ static String parseAcceptHeader (HttpServletRequest request ) {
175+ String format = request .getHeader (HttpHeaders .ACCEPT );
176+ return format != null && format .contains (FORMAT_JSON ) ?
177+ FORMAT_JSON : FORMAT_TEXT ;
178+ }
179+
180+ public static class BadFormatException extends Exception {
181+ private static final long serialVersionUID = 1L ;
182+
183+ public BadFormatException (String msg ) {
184+ super (msg );
185+ }
186+ }
113187}
0 commit comments