HADOOP-7594. Support HTTP REST in HttpServer.
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1163858 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
2b016dac82
commit
19523b6a2b
@ -350,6 +350,8 @@ Release 0.23.0 - Unreleased
|
|||||||
HADOOP-7579. Rename package names from alfredo to auth.
|
HADOOP-7579. Rename package names from alfredo to auth.
|
||||||
(Alejandro Abdelnur via szetszwo)
|
(Alejandro Abdelnur via szetszwo)
|
||||||
|
|
||||||
|
HADOOP-7594. Support HTTP REST in HttpServer. (szetszwo)
|
||||||
|
|
||||||
OPTIMIZATIONS
|
OPTIMIZATIONS
|
||||||
|
|
||||||
HADOOP-7333. Performance improvement in PureJavaCrc32. (Eric Caspole
|
HADOOP-7333. Performance improvement in PureJavaCrc32. (Eric Caspole
|
||||||
|
@ -92,6 +92,28 @@
|
|||||||
<artifactId>jetty-util</artifactId>
|
<artifactId>jetty-util</artifactId>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>asm</groupId>
|
||||||
|
<artifactId>asm</artifactId>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.jersey</groupId>
|
||||||
|
<artifactId>jersey-core</artifactId>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.jersey</groupId>
|
||||||
|
<artifactId>jersey-json</artifactId>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.jersey</groupId>
|
||||||
|
<artifactId>jersey-server</artifactId>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>tomcat</groupId>
|
<groupId>tomcat</groupId>
|
||||||
<artifactId>jasper-compiler</artifactId>
|
<artifactId>jasper-compiler</artifactId>
|
||||||
|
@ -48,16 +48,12 @@
|
|||||||
import org.apache.hadoop.conf.ConfServlet;
|
import org.apache.hadoop.conf.ConfServlet;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.fs.CommonConfigurationKeys;
|
import org.apache.hadoop.fs.CommonConfigurationKeys;
|
||||||
import org.apache.hadoop.http.AdminAuthorizedServlet;
|
|
||||||
import org.apache.hadoop.http.FilterContainer;
|
|
||||||
import org.apache.hadoop.http.FilterInitializer;
|
|
||||||
import org.apache.hadoop.http.HtmlQuoting;
|
|
||||||
import org.apache.hadoop.jmx.JMXJsonServlet;
|
import org.apache.hadoop.jmx.JMXJsonServlet;
|
||||||
import org.apache.hadoop.log.LogLevel;
|
import org.apache.hadoop.log.LogLevel;
|
||||||
import org.apache.hadoop.metrics.MetricsServlet;
|
import org.apache.hadoop.metrics.MetricsServlet;
|
||||||
import org.apache.hadoop.security.Krb5AndCertsSslSocketConnector;
|
import org.apache.hadoop.security.Krb5AndCertsSslSocketConnector;
|
||||||
import org.apache.hadoop.security.UserGroupInformation;
|
|
||||||
import org.apache.hadoop.security.Krb5AndCertsSslSocketConnector.MODE;
|
import org.apache.hadoop.security.Krb5AndCertsSslSocketConnector.MODE;
|
||||||
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
import org.apache.hadoop.security.authorize.AccessControlList;
|
import org.apache.hadoop.security.authorize.AccessControlList;
|
||||||
import org.apache.hadoop.util.ReflectionUtils;
|
import org.apache.hadoop.util.ReflectionUtils;
|
||||||
import org.mortbay.io.Buffer;
|
import org.mortbay.io.Buffer;
|
||||||
@ -79,6 +75,8 @@
|
|||||||
import org.mortbay.thread.QueuedThreadPool;
|
import org.mortbay.thread.QueuedThreadPool;
|
||||||
import org.mortbay.util.MultiException;
|
import org.mortbay.util.MultiException;
|
||||||
|
|
||||||
|
import com.sun.jersey.spi.container.servlet.ServletContainer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a Jetty embedded server to answer http requests. The primary goal
|
* Create a Jetty embedded server to answer http requests. The primary goal
|
||||||
* is to serve up status information for the server.
|
* is to serve up status information for the server.
|
||||||
@ -325,6 +323,22 @@ public void setAttribute(String name, Object value) {
|
|||||||
webAppContext.setAttribute(name, value);
|
webAppContext.setAttribute(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a Jersey resource package.
|
||||||
|
* @param packageName The Java package name containing the Jersey resource.
|
||||||
|
* @param pathSpec The path spec for the servlet
|
||||||
|
*/
|
||||||
|
public void addJerseyResourcePackage(final String packageName,
|
||||||
|
final String pathSpec) {
|
||||||
|
LOG.info("addJerseyResourcePackage: packageName=" + packageName
|
||||||
|
+ ", pathSpec=" + pathSpec);
|
||||||
|
final ServletHolder sh = new ServletHolder(ServletContainer.class);
|
||||||
|
sh.setInitParameter("com.sun.jersey.config.property.resourceConfigClass",
|
||||||
|
"com.sun.jersey.api.core.PackagesResourceConfig");
|
||||||
|
sh.setInitParameter("com.sun.jersey.config.property.packages", packageName);
|
||||||
|
webAppContext.addServlet(sh, pathSpec);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a servlet in the server.
|
* Add a servlet in the server.
|
||||||
* @param name The name of the servlet (can be passed as null)
|
* @param name The name of the servlet (can be passed as null)
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.fs.CommonConfigurationKeys;
|
import org.apache.hadoop.fs.CommonConfigurationKeys;
|
||||||
import org.apache.hadoop.http.HttpServer.QuotingInputFilter.RequestQuoter;
|
import org.apache.hadoop.http.HttpServer.QuotingInputFilter.RequestQuoter;
|
||||||
|
import org.apache.hadoop.http.resource.JerseyResource;
|
||||||
import org.apache.hadoop.security.Groups;
|
import org.apache.hadoop.security.Groups;
|
||||||
import org.apache.hadoop.security.ShellBasedUnixGroupsMapping;
|
import org.apache.hadoop.security.ShellBasedUnixGroupsMapping;
|
||||||
import org.apache.hadoop.security.authorize.AccessControlList;
|
import org.apache.hadoop.security.authorize.AccessControlList;
|
||||||
@ -57,6 +58,7 @@
|
|||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
import org.mortbay.util.ajax.JSON;
|
||||||
|
|
||||||
public class TestHttpServer extends HttpServerFunctionalTest {
|
public class TestHttpServer extends HttpServerFunctionalTest {
|
||||||
static final Log LOG = LogFactory.getLog(TestHttpServer.class);
|
static final Log LOG = LogFactory.getLog(TestHttpServer.class);
|
||||||
@ -73,7 +75,7 @@ public void doGet(HttpServletRequest request,
|
|||||||
) throws ServletException, IOException {
|
) throws ServletException, IOException {
|
||||||
PrintWriter out = response.getWriter();
|
PrintWriter out = response.getWriter();
|
||||||
Map<String, String[]> params = request.getParameterMap();
|
Map<String, String[]> params = request.getParameterMap();
|
||||||
SortedSet<String> keys = new TreeSet(params.keySet());
|
SortedSet<String> keys = new TreeSet<String>(params.keySet());
|
||||||
for(String key: keys) {
|
for(String key: keys) {
|
||||||
out.print(key);
|
out.print(key);
|
||||||
out.print(':');
|
out.print(':');
|
||||||
@ -99,7 +101,7 @@ public void doGet(HttpServletRequest request,
|
|||||||
HttpServletResponse response
|
HttpServletResponse response
|
||||||
) throws ServletException, IOException {
|
) throws ServletException, IOException {
|
||||||
PrintWriter out = response.getWriter();
|
PrintWriter out = response.getWriter();
|
||||||
SortedSet<String> sortedKeys = new TreeSet();
|
SortedSet<String> sortedKeys = new TreeSet<String>();
|
||||||
Enumeration<String> keys = request.getParameterNames();
|
Enumeration<String> keys = request.getParameterNames();
|
||||||
while(keys.hasMoreElements()) {
|
while(keys.hasMoreElements()) {
|
||||||
sortedKeys.add(keys.nextElement());
|
sortedKeys.add(keys.nextElement());
|
||||||
@ -116,7 +118,6 @@ public void doGet(HttpServletRequest request,
|
|||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public static class HtmlContentServlet extends HttpServlet {
|
public static class HtmlContentServlet extends HttpServlet {
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
@Override
|
||||||
public void doGet(HttpServletRequest request,
|
public void doGet(HttpServletRequest request,
|
||||||
HttpServletResponse response
|
HttpServletResponse response
|
||||||
@ -135,6 +136,8 @@ public void doGet(HttpServletRequest request,
|
|||||||
server.addServlet("echo", "/echo", EchoServlet.class);
|
server.addServlet("echo", "/echo", EchoServlet.class);
|
||||||
server.addServlet("echomap", "/echomap", EchoMapServlet.class);
|
server.addServlet("echomap", "/echomap", EchoMapServlet.class);
|
||||||
server.addServlet("htmlcontent", "/htmlcontent", HtmlContentServlet.class);
|
server.addServlet("htmlcontent", "/htmlcontent", HtmlContentServlet.class);
|
||||||
|
server.addJerseyResourcePackage(
|
||||||
|
JerseyResource.class.getPackage().getName(), "/jersey/*");
|
||||||
server.start();
|
server.start();
|
||||||
baseUrl = getServerURL(server);
|
baseUrl = getServerURL(server);
|
||||||
LOG.info("HTTP server started: "+ baseUrl);
|
LOG.info("HTTP server started: "+ baseUrl);
|
||||||
@ -405,4 +408,18 @@ public void testRequestQuoterWithNotNull() throws Exception {
|
|||||||
values, parameterValues));
|
values, parameterValues));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static Map<String, Object> parse(String jsonString) {
|
||||||
|
return (Map<String, Object>)JSON.parse(jsonString);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testJersey() throws Exception {
|
||||||
|
LOG.info("BEGIN testJersey()");
|
||||||
|
final String js = readOutput(new URL(baseUrl, "/jersey/foo?op=bar"));
|
||||||
|
final Map<String, Object> m = parse(js);
|
||||||
|
LOG.info("m=" + m);
|
||||||
|
assertEquals("foo", m.get(JerseyResource.PATH));
|
||||||
|
assertEquals("bar", m.get(JerseyResource.OP));
|
||||||
|
LOG.info("END testJersey()");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.http.resource;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
import javax.ws.rs.DefaultValue;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.mortbay.util.ajax.JSON;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple Jersey resource class TestHttpServer.
|
||||||
|
* The servlet simply puts the path and the op parameter in a map
|
||||||
|
* and return it in JSON format in the response.
|
||||||
|
*/
|
||||||
|
@Path("")
|
||||||
|
public class JerseyResource {
|
||||||
|
static final Log LOG = LogFactory.getLog(JerseyResource.class);
|
||||||
|
|
||||||
|
public static final String PATH = "path";
|
||||||
|
public static final String OP = "op";
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("{" + PATH + ":.*}")
|
||||||
|
@Produces({MediaType.APPLICATION_JSON})
|
||||||
|
public Response get(
|
||||||
|
@PathParam(PATH) @DefaultValue("UNKNOWN_" + PATH) final String path,
|
||||||
|
@QueryParam(OP) @DefaultValue("UNKNOWN_" + OP) final String op
|
||||||
|
) throws IOException {
|
||||||
|
LOG.info("get: " + PATH + "=" + path + ", " + OP + "=" + op);
|
||||||
|
|
||||||
|
final Map<String, Object> m = new TreeMap<String, Object>();
|
||||||
|
m.put(PATH, path);
|
||||||
|
m.put(OP, op);
|
||||||
|
final String js = JSON.toString(m);
|
||||||
|
return Response.ok(js).type(MediaType.APPLICATION_JSON).build();
|
||||||
|
}
|
||||||
|
}
|
@ -168,6 +168,28 @@
|
|||||||
<artifactId>jetty-util</artifactId>
|
<artifactId>jetty-util</artifactId>
|
||||||
<version>6.1.26</version>
|
<version>6.1.26</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>asm</groupId>
|
||||||
|
<artifactId>asm</artifactId>
|
||||||
|
<version>3.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.jersey</groupId>
|
||||||
|
<artifactId>jersey-core</artifactId>
|
||||||
|
<version>1.8</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.jersey</groupId>
|
||||||
|
<artifactId>jersey-json</artifactId>
|
||||||
|
<version>1.8</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.jersey</groupId>
|
||||||
|
<artifactId>jersey-server</artifactId>
|
||||||
|
<version>1.8</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>tomcat</groupId>
|
<groupId>tomcat</groupId>
|
||||||
<artifactId>jasper-compiler</artifactId>
|
<artifactId>jasper-compiler</artifactId>
|
||||||
|
Loading…
Reference in New Issue
Block a user