Permalink
Browse files

HADOOP-7594. Support HTTP REST in HttpServer.

  • Loading branch information...
1 parent 53f7077 commit ae0a1bb59f10c6becb8d327036486c59d59cff89 Tsz-wo Sze committed Sep 6, 2011
View
2 CHANGES.txt
@@ -146,6 +146,8 @@ Release 0.20.205.0 - unreleased
HADOOP-7539. merge hadoop archive goodness from trunk to .20 (John George
via mahadev)
+ HADOOP-7594. Support HTTP REST in HttpServer. (szetszwo)
+
Release 0.20.204.0 - 2011-8-25
NEW FEATURES
View
17 ivy.xml
@@ -151,6 +151,23 @@
rev="${jetty-util.version}"
conf="jetty->master"/>
+ <dependency org="asm"
+ name="asm"
+ rev="${asm.version}"
+ conf="jetty->master"/>
+ <dependency org="com.sun.jersey"
+ name="jersey-core"
+ rev="${jersey-core.version}"
+ conf="jetty->master"/>
+ <dependency org="com.sun.jersey"
+ name="jersey-json"
+ rev="${jersey-json.version}"
+ conf="jetty->master"/>
+ <dependency org="com.sun.jersey"
+ name="jersey-server"
+ rev="${jersey-server.version}"
+ conf="jetty->master"/>
+
<dependency org="tomcat"
name="jasper-runtime"
rev="${jasper.version}"
View
4 ivy/libraries.properties
@@ -21,6 +21,7 @@ hadoop-gpl-compression.version=0.1.0
apacheant.version=1.7.0
ant-task.version=2.0.10
+asm.version=3.2
aspectj.version=1.6.5
checkstyle.version=4.2
@@ -57,6 +58,9 @@ jsp-2.1.version=6.1.14
jets3t.version=0.6.1
jetty.version=6.1.26
jetty-util.version=6.1.26
+jersey-core.version=1.8
+jersey-json.version=1.8
+jersey-server.version=1.8
junit.version=4.5
jdeb.version=0.8
jdiff.version=1.0.9
View
23 src/core/org/apache/hadoop/http/HttpServer.java
@@ -43,15 +43,14 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.CommonConfigurationKeys;
import org.apache.hadoop.jmx.JMXJsonServlet;
import org.apache.hadoop.log.LogLevel;
import org.apache.hadoop.security.Krb5AndCertsSslSocketConnector;
-import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.Krb5AndCertsSslSocketConnector.MODE;
+import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.authorize.AccessControlList;
import org.apache.hadoop.util.ReflectionUtils;
-import org.apache.hadoop.fs.CommonConfigurationKeys;
-
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.Server;
@@ -68,6 +67,8 @@
import org.mortbay.thread.QueuedThreadPool;
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
* is to serve up status information for the server.
@@ -307,6 +308,22 @@ public void setAttribute(Context context, String name, Object value) {
context.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.
* @param name The name of the servlet (can be passed as null)
View
28 src/test/org/apache/hadoop/http/TestHttpServer.java
@@ -48,14 +48,18 @@
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.CommonConfigurationKeys;
+import org.apache.hadoop.http.resource.JerseyResource;
import org.apache.hadoop.security.Groups;
import org.apache.hadoop.security.ShellBasedUnixGroupsMapping;
import org.apache.hadoop.security.authorize.AccessControlList;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.mortbay.util.ajax.JSON;
public class TestHttpServer {
+ static final Log LOG = LogFactory.getLog(TestHttpServer.class);
+
private HttpServer server;
private URL baseUrl;
@@ -68,7 +72,7 @@ public void doGet(HttpServletRequest request,
) throws ServletException, IOException {
PrintStream out = new PrintStream(response.getOutputStream());
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) {
out.print(key);
out.print(':');
@@ -94,7 +98,7 @@ public void doGet(HttpServletRequest request,
HttpServletResponse response
) throws ServletException, IOException {
PrintStream out = new PrintStream(response.getOutputStream());
- SortedSet<String> sortedKeys = new TreeSet();
+ SortedSet<String> sortedKeys = new TreeSet<String>();
Enumeration<String> keys = request.getParameterNames();
while(keys.hasMoreElements()) {
sortedKeys.add(keys.nextElement());
@@ -127,6 +131,8 @@ private String readOutput(URL url) throws IOException {
server = new HttpServer("test", "0.0.0.0", 0, true);
server.addServlet("echo", "/echo", EchoServlet.class);
server.addServlet("echomap", "/echomap", EchoMapServlet.class);
+ server.addJerseyResourcePackage(
+ JerseyResource.class.getPackage().getName(), "/jersey/*");
server.start();
int port = server.getPort();
baseUrl = new URL("http://localhost:" + port + "/");
@@ -158,9 +164,6 @@ private String readOutput(URL url) throws IOException {
*
*/
public static class DummyServletFilter implements Filter {
-
- private static final Log LOG = LogFactory.getLog(
- DummyServletFilter.class);
@Override
public void destroy() { }
@@ -306,4 +309,19 @@ public void testAuthorizationOfDefaultServlets() throws Exception {
}
myServer.stop();
}
+
+ @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()");
+ }
}
View
64 src/test/org/apache/hadoop/http/resource/JerseyResource.java
@@ -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();
+ }
+}

0 comments on commit ae0a1bb

Please sign in to comment.