You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by sw...@apache.org on 2014/07/23 23:54:50 UTC
git commit: AMBARI-6587. Views: exception on server restart after
creating view instance.
Repository: ambari
Updated Branches:
refs/heads/trunk 49d7a3da8 -> 67a106c94
AMBARI-6587. Views: exception on server restart after creating view instance.
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/67a106c9
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/67a106c9
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/67a106c9
Branch: refs/heads/trunk
Commit: 67a106c9496180e17f5068dd02e30520f7469bbf
Parents: 49d7a3d
Author: Siddharth Wagle <sw...@hortonworks.com>
Authored: Wed Jul 23 14:52:10 2014 -0700
Committer: Siddharth Wagle <sw...@hortonworks.com>
Committed: Wed Jul 23 14:52:47 2014 -0700
----------------------------------------------------------------------
.../ambari/server/controller/AmbariServer.java | 21 ++--
.../server/controller/FailsafeHandlerList.java | 103 +++++++++++++++++++
.../controller/FailsafeServletResponse.java | 59 +++++++++++
.../controller/FailsafeHandlerListTest.java | 71 +++++++++++++
.../controller/FailsafeServletResponseTest.java | 54 ++++++++++
5 files changed, 297 insertions(+), 11 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/67a106c9/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 497d3f7..1ea8311 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
@@ -87,7 +87,6 @@ import org.apache.ambari.server.view.ViewRegistry;
import org.apache.ambari.view.SystemException;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
import org.eclipse.jetty.servlet.DefaultServlet;
@@ -303,12 +302,12 @@ public class AmbariServer {
root.addServlet(sh, "/api/v1/*");
sh.setInitOrder(2);
- HandlerList handlerList = new HandlerList();
+ FailsafeHandlerList handlerList = new FailsafeHandlerList();
try {
ViewRegistry viewRegistry = ViewRegistry.getInstance();
for (ViewInstanceEntity entity : viewRegistry.readViewArchives(configs)){
- handlerList.addHandler(viewRegistry.getWebAppContext(entity));
+ handlerList.addFailsafeHandler(viewRegistry.getWebAppContext(entity));
}
} catch (SystemException e) {
LOG.error("Caught exception deploying views.", e);
@@ -506,7 +505,7 @@ public class AmbariServer {
LOG.info("DB store version is compatible");
}
-
+
public void stop() throws Exception {
try {
server.stop();
@@ -545,7 +544,7 @@ public class AmbariServer {
ViewRegistry.init(injector.getInstance(ViewDAO.class), injector.getInstance(ViewInstanceDAO.class),
injector.getInstance(ResourceDAO.class), injector.getInstance(ResourceTypeDAO.class));
}
-
+
/**
* Sets up proxy authentication. This must be done before the server is
* initialized since <code>AmbariMetaInfo</code> requires potential URL
@@ -554,13 +553,13 @@ public class AmbariServer {
static void setupProxyAuth() {
final String proxyUser = System.getProperty("http.proxyUser");
final String proxyPass = System.getProperty("http.proxyPassword");
-
+
// to skip some hosts from proxy, pipe-separate names using, i.e.:
// -Dhttp.nonProxyHosts=*.domain.com|host.internal.net
-
+
if (null != proxyUser && null != proxyPass) {
LOG.info("Proxy authentication enabled");
-
+
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
@@ -570,17 +569,17 @@ public class AmbariServer {
} else {
LOG.debug("Proxy authentication not specified");
}
- }
+ }
public static void main(String[] args) throws Exception {
Injector injector = Guice.createInjector(new ControllerModule());
-
+
AmbariServer server = null;
try {
LOG.info("Getting the controller");
setupProxyAuth();
-
+
injector.getInstance(GuiceJpaInitializer.class);
server = injector.getInstance(AmbariServer.class);
CertificateManager certMan = injector.getInstance(CertificateManager.class);
http://git-wip-us.apache.org/repos/asf/ambari/blob/67a106c9/ambari-server/src/main/java/org/apache/ambari/server/controller/FailsafeHandlerList.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/FailsafeHandlerList.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/FailsafeHandlerList.java
new file mode 100644
index 0000000..48ec626
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/FailsafeHandlerList.java
@@ -0,0 +1,103 @@
+/**
+ * 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.controller;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.HandlerCollection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This extension of {@link HandlerCollection} will call each contained handler
+ * in turn until the response is committed, a positive response status is set or
+ * an exception from important handler is thrown. Handlers added via
+ * {@link #addFailsafeHandler(Handler)} do not stop the polling when they raise
+ * an exception.
+ *
+ */
+public class FailsafeHandlerList extends HandlerCollection {
+
+ /**
+ * Logger.
+ */
+ private static Logger LOG = LoggerFactory.getLogger(FailsafeHandlerList.class);
+
+ /**
+ * Fail-safe handlers do not stop the processing of the request if they raise an exception.
+ */
+ private final List<Handler> failsafeHandlers = new ArrayList<Handler>();
+
+ /**
+ * Adds handler to collection and marks it as fail-safe.
+ *
+ * @param handler failsafe handler
+ */
+ public void addFailsafeHandler(Handler handler) {
+ addHandler(handler);
+ failsafeHandlers.add(handler);
+ }
+
+ @Override
+ public void removeHandler(Handler handler) {
+ super.removeHandler(handler);
+ failsafeHandlers.remove(handler);
+ }
+
+ /**
+ * @see Handler#handle(String, Request, HttpServletRequest,
+ * HttpServletResponse)
+ */
+ @Override
+ public void handle(String target, Request baseRequest,
+ HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException {
+ final Handler[] handlers = getHandlers();
+
+ if (handlers != null && isStarted()) {
+ for (int i = 0; i < handlers.length; i++) {
+ final Handler handler = handlers[i];
+ if (failsafeHandlers.contains(handler)) {
+ try {
+ final FailsafeServletResponse responseWrapper = new FailsafeServletResponse(response);
+ handler.handle(target, baseRequest, request, responseWrapper);
+ if (responseWrapper.isRequestFailed()) {
+ response.reset();
+ baseRequest.setHandled(false);
+ }
+ } catch (Exception ex) {
+ LOG.warn("Fail-safe handler failed to process request, continuing handler polling", ex);
+ continue;
+ }
+ } else {
+ handler.handle(target, baseRequest, request, response);
+ }
+ if (baseRequest.isHandled()) {
+ return;
+ }
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/67a106c9/ambari-server/src/main/java/org/apache/ambari/server/controller/FailsafeServletResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/FailsafeServletResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/FailsafeServletResponse.java
new file mode 100644
index 0000000..bad6e22
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/FailsafeServletResponse.java
@@ -0,0 +1,59 @@
+/**
+ * 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.controller;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+/**
+ * Wraps standard wrapper for {@link HttpServletResponse} to cancel sending
+ * errors on failed requests.
+ */
+public class FailsafeServletResponse extends HttpServletResponseWrapper {
+ private boolean error;
+
+ /**
+ * Constructor.
+ *
+ * @param response response to be wrapped
+ */
+ public FailsafeServletResponse(HttpServletResponse response) {
+ super(response);
+ }
+
+ @Override
+ public void sendError(int sc) throws IOException {
+ error = true;
+ }
+
+ @Override
+ public void sendError(int sc, String msg) throws IOException {
+ error = true;
+ }
+
+ /**
+ * Indicates that request failed to execute.
+ *
+ * @return true if request failed
+ */
+ public boolean isRequestFailed() {
+ return error;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/67a106c9/ambari-server/src/test/java/org/apache/ambari/server/controller/FailsafeHandlerListTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/FailsafeHandlerListTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/FailsafeHandlerListTest.java
new file mode 100644
index 0000000..8d1ba0d
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/FailsafeHandlerListTest.java
@@ -0,0 +1,71 @@
+/**
+ * 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.controller;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.easymock.EasyMock;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Request;
+import org.junit.Test;
+
+/**
+ * Tests the {@link FailsafeHandlerList} class
+ */
+public class FailsafeHandlerListTest {
+ @Test
+ public void testHandleWithFailures() throws Exception {
+ final FailsafeHandlerList handlerList = EasyMock
+ .createMockBuilder(FailsafeHandlerList.class).withConstructor()
+ .addMockedMethod("isStarted").createMock();
+ EasyMock.expect(handlerList.isStarted()).andReturn(false).times(3).andReturn(true).anyTimes();
+ final Handler normalHandler1 = EasyMock.createNiceMock(Handler.class);
+ final Handler normalHandler2 = EasyMock.createNiceMock(Handler.class);
+ final Handler failureHandler = EasyMock.createNiceMock(Handler.class);
+ final HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
+ final HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
+ normalHandler1.handle(EasyMock.<String> anyObject(),
+ EasyMock.<Request> anyObject(),
+ EasyMock.<HttpServletRequest> anyObject(),
+ EasyMock.<HttpServletResponse> anyObject());
+ EasyMock.expectLastCall().once();
+ normalHandler2.handle(EasyMock.<String> anyObject(),
+ EasyMock.<Request> anyObject(),
+ EasyMock.<HttpServletRequest> anyObject(),
+ EasyMock.<HttpServletResponse> anyObject());
+ EasyMock.expectLastCall().once();
+ failureHandler.handle(EasyMock.<String> anyObject(),
+ EasyMock.<Request> anyObject(),
+ EasyMock.<HttpServletRequest> anyObject(),
+ EasyMock.<HttpServletResponse> anyObject());
+ EasyMock.expectLastCall().andThrow(new IOException());
+ EasyMock.replay(handlerList, normalHandler1, normalHandler2, failureHandler);
+
+ handlerList.addFailsafeHandler(normalHandler1);
+ handlerList.addFailsafeHandler(failureHandler);
+ handlerList.addFailsafeHandler(normalHandler2);
+ handlerList.start();
+ handlerList.handle("", new Request(), request, response);
+
+ EasyMock.verify(handlerList, normalHandler1, normalHandler2, failureHandler);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/67a106c9/ambari-server/src/test/java/org/apache/ambari/server/controller/FailsafeServletResponseTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/FailsafeServletResponseTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/FailsafeServletResponseTest.java
new file mode 100644
index 0000000..249a3f5
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/FailsafeServletResponseTest.java
@@ -0,0 +1,54 @@
+/**
+ * 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.controller;
+
+import javax.servlet.http.HttpServletResponse;
+
+import junit.framework.Assert;
+
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
+import org.junit.Test;
+
+/**
+ * Tests the {@link FailsafeServletResponse} class
+ */
+public class FailsafeServletResponseTest {
+ @Test
+ public void testRequestFailure() throws Exception {
+ final HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
+ final FailsafeServletResponse responseWrapper = new FailsafeServletResponse(response);
+ final IAnswer<Void> answer = new IAnswer<Void>() {
+ @Override
+ public Void answer() throws Throwable {
+ Assert.fail("Original response should not commit errors");
+ return null;
+ }
+ };
+ response.sendError(0);
+ EasyMock.expectLastCall().andAnswer(answer).anyTimes();
+ response.sendError(0, "");
+ EasyMock.expectLastCall().andAnswer(answer).anyTimes();
+ EasyMock.replay(response);
+ responseWrapper.sendError(0);
+ responseWrapper.sendError(0, "");
+ Assert.assertTrue(responseWrapper.isRequestFailed());
+ EasyMock.verify(response);
+ }
+}