1 | /** |
---|
2 | * Licensed to the Apache Software Foundation (ASF) under one |
---|
3 | * or more contributor license agreements. See the NOTICE file |
---|
4 | * distributed with this work for additional information |
---|
5 | * regarding copyright ownership. The ASF licenses this file |
---|
6 | * to you under the Apache License, Version 2.0 (the |
---|
7 | * "License"); you may not use this file except in compliance |
---|
8 | * with the License. You may obtain a copy of the License at |
---|
9 | * |
---|
10 | * http://www.apache.org/licenses/LICENSE-2.0 |
---|
11 | * |
---|
12 | * Unless required by applicable law or agreed to in writing, software |
---|
13 | * distributed under the License is distributed on an "AS IS" BASIS, |
---|
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
---|
15 | * See the License for the specific language governing permissions and |
---|
16 | * limitations under the License. |
---|
17 | */ |
---|
18 | package org.apache.hadoop.hdfs.server.namenode; |
---|
19 | |
---|
20 | import org.apache.hadoop.fs.FileStatus; |
---|
21 | import org.apache.hadoop.hdfs.HftpFileSystem; |
---|
22 | import org.apache.hadoop.hdfs.protocol.ClientProtocol; |
---|
23 | import org.apache.hadoop.ipc.RemoteException; |
---|
24 | import org.apache.hadoop.security.UnixUserGroupInformation; |
---|
25 | import org.apache.hadoop.util.VersionInfo; |
---|
26 | |
---|
27 | import org.znerd.xmlenc.*; |
---|
28 | |
---|
29 | import java.io.IOException; |
---|
30 | import java.io.PrintWriter; |
---|
31 | import java.text.SimpleDateFormat; |
---|
32 | import java.util.Date; |
---|
33 | import java.util.HashMap; |
---|
34 | import java.util.Map; |
---|
35 | import java.util.Stack; |
---|
36 | import java.util.regex.Pattern; |
---|
37 | import java.util.regex.PatternSyntaxException; |
---|
38 | import javax.servlet.ServletException; |
---|
39 | import javax.servlet.http.HttpServletRequest; |
---|
40 | import javax.servlet.http.HttpServletResponse; |
---|
41 | |
---|
42 | /** |
---|
43 | * Obtain meta-information about a filesystem. |
---|
44 | * @see org.apache.hadoop.hdfs.HftpFileSystem |
---|
45 | */ |
---|
46 | public class ListPathsServlet extends DfsServlet { |
---|
47 | /** For java.io.Serializable */ |
---|
48 | private static final long serialVersionUID = 1L; |
---|
49 | |
---|
50 | public static final ThreadLocal<SimpleDateFormat> df = |
---|
51 | new ThreadLocal<SimpleDateFormat>() { |
---|
52 | protected SimpleDateFormat initialValue() { |
---|
53 | return HftpFileSystem.getDateFormat(); |
---|
54 | } |
---|
55 | }; |
---|
56 | |
---|
57 | /** |
---|
58 | * Write a node to output. |
---|
59 | * Node information includes path, modification, permission, owner and group. |
---|
60 | * For files, it also includes size, replication and block-size. |
---|
61 | */ |
---|
62 | static void writeInfo(FileStatus i, XMLOutputter doc) throws IOException { |
---|
63 | final SimpleDateFormat ldf = df.get(); |
---|
64 | doc.startTag(i.isDir() ? "directory" : "file"); |
---|
65 | doc.attribute("path", i.getPath().toUri().getPath()); |
---|
66 | doc.attribute("modified", ldf.format(new Date(i.getModificationTime()))); |
---|
67 | doc.attribute("accesstime", ldf.format(new Date(i.getAccessTime()))); |
---|
68 | if (!i.isDir()) { |
---|
69 | doc.attribute("size", String.valueOf(i.getLen())); |
---|
70 | doc.attribute("replication", String.valueOf(i.getReplication())); |
---|
71 | doc.attribute("blocksize", String.valueOf(i.getBlockSize())); |
---|
72 | } |
---|
73 | doc.attribute("permission", (i.isDir()? "d": "-") + i.getPermission()); |
---|
74 | doc.attribute("owner", i.getOwner()); |
---|
75 | doc.attribute("group", i.getGroup()); |
---|
76 | doc.endTag(); |
---|
77 | } |
---|
78 | |
---|
79 | /** |
---|
80 | * Build a map from the query string, setting values and defaults. |
---|
81 | */ |
---|
82 | protected Map<String,String> buildRoot(HttpServletRequest request, |
---|
83 | XMLOutputter doc) { |
---|
84 | final String path = request.getPathInfo() != null |
---|
85 | ? request.getPathInfo() : "/"; |
---|
86 | final String exclude = request.getParameter("exclude") != null |
---|
87 | ? request.getParameter("exclude") : "\\..*\\.crc"; |
---|
88 | final String filter = request.getParameter("filter") != null |
---|
89 | ? request.getParameter("filter") : ".*"; |
---|
90 | final boolean recur = request.getParameter("recursive") != null |
---|
91 | && "yes".equals(request.getParameter("recursive")); |
---|
92 | |
---|
93 | Map<String, String> root = new HashMap<String, String>(); |
---|
94 | root.put("path", path); |
---|
95 | root.put("recursive", recur ? "yes" : "no"); |
---|
96 | root.put("filter", filter); |
---|
97 | root.put("exclude", exclude); |
---|
98 | root.put("time", df.get().format(new Date())); |
---|
99 | root.put("version", VersionInfo.getVersion()); |
---|
100 | return root; |
---|
101 | } |
---|
102 | |
---|
103 | /** |
---|
104 | * Service a GET request as described below. |
---|
105 | * Request: |
---|
106 | * {@code |
---|
107 | * GET http://<nn>:<port>/listPaths[/<path>][<?option>[&option]*] HTTP/1.1 |
---|
108 | * } |
---|
109 | * |
---|
110 | * Where <i>option</i> (default) in: |
---|
111 | * recursive ("no") |
---|
112 | * filter (".*") |
---|
113 | * exclude ("\..*\.crc") |
---|
114 | * |
---|
115 | * Response: A flat list of files/directories in the following format: |
---|
116 | * {@code |
---|
117 | * <listing path="..." recursive="(yes|no)" filter="..." |
---|
118 | * time="yyyy-MM-dd hh:mm:ss UTC" version="..."> |
---|
119 | * <directory path="..." modified="yyyy-MM-dd hh:mm:ss"/> |
---|
120 | * <file path="..." modified="yyyy-MM-dd'T'hh:mm:ssZ" accesstime="yyyy-MM-dd'T'hh:mm:ssZ" |
---|
121 | * blocksize="..." |
---|
122 | * replication="..." size="..."/> |
---|
123 | * </listing> |
---|
124 | * } |
---|
125 | */ |
---|
126 | public void doGet(HttpServletRequest request, HttpServletResponse response) |
---|
127 | throws ServletException, IOException { |
---|
128 | final UnixUserGroupInformation ugi = getUGI(request); |
---|
129 | final PrintWriter out = response.getWriter(); |
---|
130 | final XMLOutputter doc = new XMLOutputter(out, "UTF-8"); |
---|
131 | try { |
---|
132 | final Map<String, String> root = buildRoot(request, doc); |
---|
133 | final String path = root.get("path"); |
---|
134 | final boolean recur = "yes".equals(root.get("recursive")); |
---|
135 | final Pattern filter = Pattern.compile(root.get("filter")); |
---|
136 | final Pattern exclude = Pattern.compile(root.get("exclude")); |
---|
137 | ClientProtocol nnproxy = createNameNodeProxy(ugi); |
---|
138 | |
---|
139 | doc.declaration(); |
---|
140 | doc.startTag("listing"); |
---|
141 | for (Map.Entry<String,String> m : root.entrySet()) { |
---|
142 | doc.attribute(m.getKey(), m.getValue()); |
---|
143 | } |
---|
144 | |
---|
145 | FileStatus base = nnproxy.getFileInfo(path); |
---|
146 | if ((base != null) && base.isDir()) { |
---|
147 | writeInfo(base, doc); |
---|
148 | } |
---|
149 | |
---|
150 | Stack<String> pathstack = new Stack<String>(); |
---|
151 | pathstack.push(path); |
---|
152 | while (!pathstack.empty()) { |
---|
153 | String p = pathstack.pop(); |
---|
154 | try { |
---|
155 | for (FileStatus i : nnproxy.getListing(p)) { |
---|
156 | if (exclude.matcher(i.getPath().getName()).matches() |
---|
157 | || !filter.matcher(i.getPath().getName()).matches()) { |
---|
158 | continue; |
---|
159 | } |
---|
160 | if (recur && i.isDir()) { |
---|
161 | pathstack.push(i.getPath().toUri().getPath()); |
---|
162 | } |
---|
163 | writeInfo(i, doc); |
---|
164 | } |
---|
165 | } |
---|
166 | catch(RemoteException re) {re.writeXml(p, doc);} |
---|
167 | } |
---|
168 | if (doc != null) { |
---|
169 | doc.endDocument(); |
---|
170 | } |
---|
171 | } finally { |
---|
172 | if (out != null) { |
---|
173 | out.close(); |
---|
174 | } |
---|
175 | } |
---|
176 | } |
---|
177 | } |
---|