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);
+  }
+}