Updated Branches: refs/heads/trunk 49de3a349 -> 90f00a2a4
AMBARI-4335. Configure Jetty to return errors as JSON. (mpapirkovskyy) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/90f00a2a Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/90f00a2a Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/90f00a2a Branch: refs/heads/trunk Commit: 90f00a2a4267a7a94e8c89ade790ca7b71d8199a Parents: 49de3a3 Author: Myroslav Papirkovskyy <[email protected]> Authored: Thu Jan 23 18:28:01 2014 +0200 Committer: Myroslav Papirkovskyy <[email protected]> Committed: Thu Jan 23 18:28:01 2014 +0200 ---------------------------------------------------------------------- .../ambari/server/api/AmbariErrorHandler.java | 62 +++++++++++ .../ambari/server/controller/AmbariServer.java | 3 + .../server/controller/ControllerModule.java | 3 + .../server/api/AmbariErrorHandlerTest.java | 104 +++++++++++++++++++ 4 files changed, 172 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/90f00a2a/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariErrorHandler.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariErrorHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariErrorHandler.java new file mode 100644 index 0000000..ee4e56f --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariErrorHandler.java @@ -0,0 +1,62 @@ +/* + * 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.ambari.server.api; + +import com.google.gson.Gson; +import com.google.inject.Inject; +import com.google.inject.name.Named; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http.MimeTypes; +import org.eclipse.jetty.server.AbstractHttpConnection; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.ErrorHandler; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +public class AmbariErrorHandler extends ErrorHandler { + private final Gson gson; + + @Inject + public AmbariErrorHandler(@Named("prettyGson") Gson prettyGson) { + this.gson = prettyGson; + } + + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { + AbstractHttpConnection connection = AbstractHttpConnection.getCurrentConnection(); + connection.getRequest().setHandled(true); + + response.setContentType(MimeTypes.TEXT_PLAIN); + + Map<String, Object> errorMap = new LinkedHashMap<String, Object>(); + int code = connection.getResponse().getStatus(); + errorMap.put("status", code); + String message = connection.getResponse().getReason(); + if (message == null) { + message = HttpStatus.getMessage(code); + } + errorMap.put("message", message); + + gson.toJson(errorMap, response.getWriter()); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/90f00a2a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java index e745994..00f1b74 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java @@ -31,6 +31,7 @@ import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.actionmanager.ActionManager; import org.apache.ambari.server.agent.HeartBeatHandler; import org.apache.ambari.server.agent.rest.AgentResource; +import org.apache.ambari.server.api.AmbariErrorHandler; import org.apache.ambari.server.api.AmbariPersistFilter; import org.apache.ambari.server.api.rest.BootStrapResource; import org.apache.ambari.server.api.services.AmbariMetaInfo; @@ -167,6 +168,8 @@ public class AmbariServer { ServletContextHandler root = new ServletContextHandler(server, CONTEXT_PATH, ServletContextHandler.SECURITY | ServletContextHandler.SESSIONS); + root.setErrorHandler(injector.getInstance(AmbariErrorHandler.class)); + //Changing session cookie name to avoid conflicts root.getSessionHandler().getSessionManager().setSessionCookie("AMBARISESSIONID"); http://git-wip-us.apache.org/repos/asf/ambari/blob/90f00a2a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java index 2b93e54..adb78c3 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java @@ -76,6 +76,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Properties; +import com.google.gson.GsonBuilder; import static org.eclipse.persistence.config.PersistenceUnitProperties.CREATE_JDBC_DDL_FILE; import static org.eclipse.persistence.config.PersistenceUnitProperties.CREATE_ONLY; import static org.eclipse.persistence.config.PersistenceUnitProperties.CREATE_OR_EXTEND; @@ -98,6 +99,7 @@ public class ControllerModule extends AbstractModule { private final Configuration configuration; private final HostsMap hostsMap; private boolean dbInitNeeded; + private final Gson prettyGson = new GsonBuilder().serializeNulls().setPrettyPrinting().create(); public ControllerModule() throws Exception { configuration = new Configuration(); @@ -116,6 +118,7 @@ public class ControllerModule extends AbstractModule { bind(Configuration.class).toInstance(configuration); bind(HostsMap.class).toInstance(hostsMap); bind(PasswordEncoder.class).toInstance(new StandardPasswordEncoder()); + bind(Gson.class).annotatedWith(Names.named("prettyGson")).toInstance(prettyGson); install(buildJpaPersistModule()); http://git-wip-us.apache.org/repos/asf/ambari/blob/90f00a2a/ambari-server/src/test/java/org/apache/ambari/server/api/AmbariErrorHandlerTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/AmbariErrorHandlerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/AmbariErrorHandlerTest.java new file mode 100644 index 0000000..fb41f6e --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/api/AmbariErrorHandlerTest.java @@ -0,0 +1,104 @@ +/* + * 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.ambari.server.api; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; +import com.sun.jersey.api.client.*; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.DefaultServlet; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.Test; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +public class AmbariErrorHandlerTest { + Gson gson = new Gson(); + + + @Test + public void testHandle() throws Exception { + + } + + @Test + public void testErrorWithJetty() throws Exception { + Server server = new Server(0); + + ServletContextHandler root = new ServletContextHandler(server, "/", + ServletContextHandler.SECURITY | ServletContextHandler.SESSIONS); + + root.addServlet(HelloServlet.class, "/hello"); + root.addServlet(DefaultServlet.class, "/"); + root.setErrorHandler(new AmbariErrorHandler(gson)); + + server.start(); + + int localPort = server.getConnectors()[0].getLocalPort(); + + Client client = new Client(); + WebResource resource = client.resource("http://localhost:" + localPort + "/"); + + + ClientResponse successResponse = resource.path("hello").get(ClientResponse.class); + assertEquals(HttpServletResponse.SC_OK, successResponse.getStatus()); + + ClientResponse failResponse = resource.path("fail").get(ClientResponse.class); + + assertEquals(HttpServletResponse.SC_NOT_FOUND, failResponse.getStatus()); + + try { + String response = failResponse.getEntity(String.class); + System.out.println(response); + Map map; + map = gson.fromJson(response, Map.class); + System.out.println(map); + assertNotNull("Incorrect response status", map.get("status")); + assertNotNull("Incorrect response message", map.get("message")); + } catch (JsonSyntaxException e1) { + fail("Incorrect response"); + } + + + server.stop(); + } + + + @SuppressWarnings("serial") + public static class HelloServlet extends HttpServlet { + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.setContentType("text/html"); + response.setStatus(HttpServletResponse.SC_OK); + response.getWriter().println("hello"); + } + + } +}
