You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by mo...@apache.org on 2017/09/01 13:17:43 UTC

[45/64] [partial] knox git commit: KNOX-998 - Refactoring save 1

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/hadoop/gateway/ha/provider/impl/HaServiceConfigConstants.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/hadoop/gateway/ha/provider/impl/HaServiceConfigConstants.java b/gateway-provider-ha/src/main/java/org/apache/hadoop/gateway/ha/provider/impl/HaServiceConfigConstants.java
deleted file mode 100644
index 1d84819..0000000
--- a/gateway-provider-ha/src/main/java/org/apache/hadoop/gateway/ha/provider/impl/HaServiceConfigConstants.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * 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
- * <p/>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p/>
- * 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.gateway.ha.provider.impl;
-
-public interface HaServiceConfigConstants {
-
-   public static final String CONFIG_PAIRS_DELIMITER = ";";
-
-   public static final String CONFIG_PAIR_DELIMITER = "=";
-
-   public static final String CONFIG_PARAM_MAX_FAILOVER_ATTEMPTS = "maxFailoverAttempts";
-
-   public static final String CONFIG_PARAM_FAILOVER_SLEEP = "failoverSleep";
-
-   public static final String CONFIG_PARAM_MAX_RETRY_ATTEMPTS = "maxRetryAttempts";
-
-   public static final String CONFIG_PARAM_RETRY_SLEEP = "retrySleep";
-
-   public static final String CONFIG_PARAM_ENABLED = "enabled";
-
-   public static final String CONFIG_PARAM_ZOOKEEPER_ENSEMBLE = "zookeeperEnsemble";
-
-   public static final String CONFIG_PARAM_ZOOKEEPER_NAMESPACE = "zookeeperNamespace";
-
-   public static final int DEFAULT_MAX_FAILOVER_ATTEMPTS = 3;
-
-   public static final int DEFAULT_FAILOVER_SLEEP = 1000;
-
-   public static final int DEFAULT_MAX_RETRY_ATTEMPTS = 3;
-
-   public static final int DEFAULT_RETRY_SLEEP = 1000;
-
-   public static final boolean DEFAULT_ENABLED = true;
-
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/hadoop/gateway/ha/provider/impl/i18n/HaMessages.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/hadoop/gateway/ha/provider/impl/i18n/HaMessages.java b/gateway-provider-ha/src/main/java/org/apache/hadoop/gateway/ha/provider/impl/i18n/HaMessages.java
deleted file mode 100644
index 1bad024..0000000
--- a/gateway-provider-ha/src/main/java/org/apache/hadoop/gateway/ha/provider/impl/i18n/HaMessages.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * 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.gateway.ha.provider.impl.i18n;
-
-import org.apache.hadoop.gateway.i18n.messages.Message;
-import org.apache.hadoop.gateway.i18n.messages.MessageLevel;
-import org.apache.hadoop.gateway.i18n.messages.Messages;
-
-@Messages(logger = "org.apache.hadoop.gateway")
-public interface HaMessages {
-
-   @Message(level = MessageLevel.ERROR, text = "Failed to Write HA Descriptor: {0}")
-   void failedToWriteHaDescriptor(Exception e);
-
-   @Message(level = MessageLevel.ERROR, text = "Failed to load HA Descriptor: {0}")
-   void failedToLoadHaDescriptor(Exception e);
-
-   @Message(level = MessageLevel.INFO, text = "No Active URL was found for service: {0}")
-   void noActiveUrlFound(String serviceName);
-
-   @Message(level = MessageLevel.INFO, text = "No Service by this name was found: {0}")
-   void noServiceFound(String serviceName);
-
-   @Message(level = MessageLevel.DEBUG, text = "Moving failed URL to the bottom {0}, new top is {1}")
-   void markedFailedUrl(String failedUrl, String top);
-
-  @Message(level = MessageLevel.ERROR, text = "Failed to get Zookeeper URLs : {0}")
-  void failedToGetZookeeperUrls(Exception e);
-
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/deploy/HaProviderDeploymentContributor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/deploy/HaProviderDeploymentContributor.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/deploy/HaProviderDeploymentContributor.java
new file mode 100644
index 0000000..2f3664f
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/deploy/HaProviderDeploymentContributor.java
@@ -0,0 +1,98 @@
+/**
+ * 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.knox.gateway.ha.deploy;
+
+import org.apache.knox.gateway.deploy.DeploymentContext;
+import org.apache.knox.gateway.deploy.ProviderDeploymentContributorBase;
+import org.apache.knox.gateway.descriptor.FilterParamDescriptor;
+import org.apache.knox.gateway.descriptor.ResourceDescriptor;
+import org.apache.knox.gateway.ha.provider.HaDescriptor;
+import org.apache.knox.gateway.ha.provider.HaServiceConfig;
+import org.apache.knox.gateway.ha.provider.HaServletContextListener;
+import org.apache.knox.gateway.ha.provider.impl.HaDescriptorFactory;
+import org.apache.knox.gateway.ha.provider.impl.HaDescriptorManager;
+import org.apache.knox.gateway.ha.provider.impl.i18n.HaMessages;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.topology.Provider;
+import org.apache.knox.gateway.topology.Service;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+public class HaProviderDeploymentContributor extends ProviderDeploymentContributorBase {
+
+   private static final String PROVIDER_ROLE_NAME = "ha";
+
+   private static final String PROVIDER_IMPL_NAME = "HaProvider";
+
+   private static final String HA_DESCRIPTOR_NAME = "ha.provider.descriptor";
+
+   private static final HaMessages LOG = MessagesFactory.get(HaMessages.class);
+
+   @Override
+   public String getRole() {
+      return PROVIDER_ROLE_NAME;
+   }
+
+   @Override
+   public String getName() {
+      return PROVIDER_IMPL_NAME;
+   }
+
+   @Override
+   public void contributeProvider(DeploymentContext context, Provider provider) {
+      Map<String, String> params = provider.getParams();
+      HaDescriptor descriptor = HaDescriptorFactory.createDescriptor();
+      for (Entry<String, String> entry : params.entrySet()) {
+         HaServiceConfig config = HaDescriptorFactory.createServiceConfig(entry.getKey(), entry.getValue());
+         descriptor.addServiceConfig(config);
+      }
+      StringWriter writer = new StringWriter();
+      try {
+         HaDescriptorManager.store(descriptor, writer);
+      } catch (IOException e) {
+         LOG.failedToWriteHaDescriptor(e);
+      }
+      String asset = writer.toString();
+      context.getWebArchive().addAsWebInfResource(
+            new StringAsset(asset),
+            HaServletContextListener.DESCRIPTOR_DEFAULT_FILE_NAME);
+      context.addDescriptor(HA_DESCRIPTOR_NAME, descriptor);
+   }
+
+   @Override
+   public void finalizeContribution(DeploymentContext context) {
+      if (context.getDescriptor(HA_DESCRIPTOR_NAME) != null) {
+         // Tell the provider the location of the descriptor.
+         // Doing this here instead of in 'contributeProvider' so that this ServletContextListener comes after the gateway services have been set.
+         context.getWebAppDescriptor().createListener().listenerClass(HaServletContextListener.class.getName());
+         context.getWebAppDescriptor().createContextParam()
+               .paramName(HaServletContextListener.DESCRIPTOR_LOCATION_INIT_PARAM_NAME)
+               .paramValue(HaServletContextListener.DESCRIPTOR_DEFAULT_LOCATION);
+      }
+   }
+
+   @Override
+   public void contributeFilter(DeploymentContext context, Provider provider, Service service, ResourceDescriptor resource, List<FilterParamDescriptor> params) {
+      //no op
+   }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/dispatch/DefaultHaDispatch.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/dispatch/DefaultHaDispatch.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/dispatch/DefaultHaDispatch.java
new file mode 100644
index 0000000..0afb539
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/dispatch/DefaultHaDispatch.java
@@ -0,0 +1,130 @@
+/**
+ * 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.knox.gateway.ha.dispatch;
+
+import org.apache.knox.gateway.config.Configure;
+import org.apache.knox.gateway.config.Optional;
+import org.apache.knox.gateway.dispatch.DefaultDispatch;
+import org.apache.knox.gateway.filter.AbstractGatewayFilter;
+import org.apache.knox.gateway.ha.dispatch.i18n.HaDispatchMessages;
+import org.apache.knox.gateway.ha.provider.HaProvider;
+import org.apache.knox.gateway.ha.provider.HaServiceConfig;
+import org.apache.knox.gateway.ha.provider.impl.HaServiceConfigConstants;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.client.methods.HttpUriRequest;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.net.URI;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Default HA dispatch class that has a very basic failover mechanism
+ */
+public class DefaultHaDispatch extends DefaultDispatch {
+
+  protected static final String FAILOVER_COUNTER_ATTRIBUTE = "dispatch.ha.failover.counter";
+
+  private static final HaDispatchMessages LOG = MessagesFactory.get(HaDispatchMessages.class);
+
+  private int maxFailoverAttempts = HaServiceConfigConstants.DEFAULT_MAX_FAILOVER_ATTEMPTS;
+
+  private int failoverSleep = HaServiceConfigConstants.DEFAULT_FAILOVER_SLEEP;
+
+  private HaProvider haProvider;
+
+  @Optional
+  @Configure
+  private String serviceRole;
+
+  @Override
+  public void init() {
+    super.init();
+    LOG.initializingForResourceRole(getServiceRole());
+    if ( haProvider != null ) {
+      HaServiceConfig serviceConfig = haProvider.getHaDescriptor().getServiceConfig(getServiceRole());
+      maxFailoverAttempts = serviceConfig.getMaxFailoverAttempts();
+      failoverSleep = serviceConfig.getFailoverSleep();
+    }
+  }
+
+  public String getServiceRole() {
+    return serviceRole;
+  }
+
+  public void setServiceRole(String serviceRole) {
+    this.serviceRole = serviceRole;
+  }
+
+  public HaProvider getHaProvider() {
+    return haProvider;
+  }
+
+  @Configure
+  public void setHaProvider(HaProvider haProvider) {
+    this.haProvider = haProvider;
+  }
+
+  @Override
+  protected void executeRequest(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest, HttpServletResponse outboundResponse) throws IOException {
+    HttpResponse inboundResponse = null;
+    try {
+      inboundResponse = executeOutboundRequest(outboundRequest);
+      writeOutboundResponse(outboundRequest, inboundRequest, outboundResponse, inboundResponse);
+    } catch ( IOException e ) {
+      LOG.errorConnectingToServer(outboundRequest.getURI().toString(), e);
+      failoverRequest(outboundRequest, inboundRequest, outboundResponse, inboundResponse, e);
+    }
+  }
+
+
+  private void failoverRequest(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest, HttpServletResponse outboundResponse, HttpResponse inboundResponse, Exception exception) throws IOException {
+    LOG.failingOverRequest(outboundRequest.getURI().toString());
+    AtomicInteger counter = (AtomicInteger) inboundRequest.getAttribute(FAILOVER_COUNTER_ATTRIBUTE);
+    if ( counter == null ) {
+      counter = new AtomicInteger(0);
+    }
+    inboundRequest.setAttribute(FAILOVER_COUNTER_ATTRIBUTE, counter);
+    if ( counter.incrementAndGet() <= maxFailoverAttempts ) {
+      haProvider.markFailedURL(getServiceRole(), outboundRequest.getURI().toString());
+      //null out target url so that rewriters run again
+      inboundRequest.setAttribute(AbstractGatewayFilter.TARGET_REQUEST_URL_ATTRIBUTE_NAME, null);
+      URI uri = getDispatchUrl(inboundRequest);
+      ((HttpRequestBase) outboundRequest).setURI(uri);
+      if ( failoverSleep > 0 ) {
+        try {
+          Thread.sleep(failoverSleep);
+        } catch ( InterruptedException e ) {
+          LOG.failoverSleepFailed(getServiceRole(), e);
+        }
+      }
+      executeRequest(outboundRequest, inboundRequest, outboundResponse);
+    } else {
+      LOG.maxFailoverAttemptsReached(maxFailoverAttempts, getServiceRole());
+      if ( inboundResponse != null ) {
+        writeOutboundResponse(outboundRequest, inboundRequest, outboundResponse, inboundResponse);
+      } else {
+        throw new IOException(exception);
+      }
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/dispatch/i18n/HaDispatchMessages.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/dispatch/i18n/HaDispatchMessages.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/dispatch/i18n/HaDispatchMessages.java
new file mode 100644
index 0000000..8efc773
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/dispatch/i18n/HaDispatchMessages.java
@@ -0,0 +1,41 @@
+/**
+ * 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.knox.gateway.ha.dispatch.i18n;
+
+import org.apache.knox.gateway.i18n.messages.Message;
+import org.apache.knox.gateway.i18n.messages.MessageLevel;
+import org.apache.knox.gateway.i18n.messages.Messages;
+import org.apache.knox.gateway.i18n.messages.StackTrace;
+
+@Messages(logger = "org.apache.hadoop.gateway")
+public interface HaDispatchMessages {
+  @Message(level = MessageLevel.INFO, text = "Initializing Ha Dispatch for: {0}")
+  void initializingForResourceRole(String resourceRole);
+
+  @Message(level = MessageLevel.INFO, text = "Could not connect to server: {0} {1}")
+  void errorConnectingToServer(String uri, @StackTrace(level = MessageLevel.DEBUG) Exception e);
+
+  @Message(level = MessageLevel.INFO, text = "Failing over request to a different server: {0}")
+  void failingOverRequest(String uri);
+
+  @Message(level = MessageLevel.INFO, text = "Maximum attempts {0} to failover reached for service: {1}")
+  void maxFailoverAttemptsReached(int attempts, String service);
+
+  @Message(level = MessageLevel.INFO, text = "Error occurred while trying to sleep for failover : {0} {1}")
+  void failoverSleepFailed(String service, @StackTrace(level = MessageLevel.DEBUG) Exception e);
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/HaDescriptor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/HaDescriptor.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/HaDescriptor.java
new file mode 100644
index 0000000..a7e5ea2
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/HaDescriptor.java
@@ -0,0 +1,34 @@
+/**
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.knox.gateway.ha.provider;
+
+import java.util.List;
+
+public interface HaDescriptor {
+
+   public void addServiceConfig(HaServiceConfig serviceConfig);
+
+   public HaServiceConfig getServiceConfig(String serviceName);
+
+   public List<String> getServiceNames();
+
+   public List<String> getEnabledServiceNames();
+
+   public List<HaServiceConfig> getServiceConfigs();
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/HaProvider.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/HaProvider.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/HaProvider.java
new file mode 100644
index 0000000..c11be70
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/HaProvider.java
@@ -0,0 +1,67 @@
+/**
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.knox.gateway.ha.provider;
+
+import java.util.List;
+
+public interface HaProvider {
+
+   public HaDescriptor getHaDescriptor();
+
+   /**
+    * Add a service name (role) as a HA service with the URLs that it is configured for
+    *
+    * @param serviceName the name of the service
+    * @param urls        the list of urls that can be used for that service
+    */
+   public void addHaService(String serviceName, List<String> urls);
+
+   /**
+    * Returns whether the service is enabled for HA
+    *
+    * @param serviceName the name of the service
+    * @return true if the service is enabled; false otherwise
+    */
+   public boolean isHaEnabled(String serviceName);
+
+   /**
+    * Returns the current URL that is known to be active for the service
+    *
+    * @param serviceName the name of the service
+    * @return the URL as a string or null if the service name is not found
+    */
+   public String getActiveURL(String serviceName);
+
+   /**
+    * Sets a given URL that is known to be active for the service
+    *
+    * @param serviceName the name of the service
+    * @param url the active url
+    */
+   public void setActiveURL(String serviceName, String url);
+
+   /**
+    * Mark the URL for the service as one that has failed. This method puts changes the active URL to
+    * the next available URL for the service.
+    *
+    * @param serviceName the name of the service
+    * @param url         the URL that has failed in some way
+    */
+   public void markFailedURL(String serviceName, String url);
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/HaServiceConfig.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/HaServiceConfig.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/HaServiceConfig.java
new file mode 100644
index 0000000..690137c
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/HaServiceConfig.java
@@ -0,0 +1,53 @@
+/**
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.knox.gateway.ha.provider;
+
+public interface HaServiceConfig {
+
+   public void setServiceName(String name);
+
+   public String getServiceName();
+
+   public boolean isEnabled();
+
+   public void setEnabled(boolean enabled);
+
+   public void setMaxFailoverAttempts(int limit);
+
+   public int getMaxFailoverAttempts();
+
+   public void setFailoverSleep(int sleep);
+
+   public int getFailoverSleep();
+
+   public void setMaxRetryAttempts(int limit);
+
+   public int getMaxRetryAttempts();
+
+   public void setRetrySleep(int sleep);
+
+   public int getRetrySleep();
+
+   public String getZookeeperEnsemble();
+
+   public void setZookeeperEnsemble(String zookeeperEnsemble);
+
+   public String getZookeeperNamespace();
+
+   public void setZookeeperNamespace(String zookeeperNamespace);
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/HaServletContextListener.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/HaServletContextListener.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/HaServletContextListener.java
new file mode 100644
index 0000000..20a39ac
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/HaServletContextListener.java
@@ -0,0 +1,116 @@
+/**
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.knox.gateway.ha.provider;
+
+import org.apache.knox.gateway.ha.provider.impl.DefaultHaProvider;
+import org.apache.knox.gateway.ha.provider.impl.HaDescriptorManager;
+import org.apache.knox.gateway.ha.provider.impl.i18n.HaMessages;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.services.GatewayServices;
+import org.apache.knox.gateway.services.registry.ServiceRegistry;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.List;
+
+public class HaServletContextListener implements ServletContextListener {
+
+   public static final String PROVIDER_ATTRIBUTE_NAME = "haProvider";
+
+   public static final String DESCRIPTOR_LOCATION_INIT_PARAM_NAME = "haDescriptorLocation";
+
+   public static final String DESCRIPTOR_DEFAULT_FILE_NAME = "ha.xml";
+
+   public static final String DESCRIPTOR_DEFAULT_LOCATION = "/WEB-INF/" + DESCRIPTOR_DEFAULT_FILE_NAME;
+
+   private static final HaMessages LOG = MessagesFactory.get(HaMessages.class);
+
+
+   @Override
+   public void contextInitialized(ServletContextEvent event) {
+      HaDescriptor descriptor;
+      ServletContext servletContext = event.getServletContext();
+      try {
+         URL url = locateDescriptor(servletContext);
+         descriptor = loadDescriptor(url);
+      } catch (IOException e) {
+         throw new IllegalStateException(e);
+      }
+      setupHaProvider(descriptor, servletContext);
+   }
+
+   @Override
+   public void contextDestroyed(ServletContextEvent event) {
+      event.getServletContext().removeAttribute(PROVIDER_ATTRIBUTE_NAME);
+   }
+
+   public static HaProvider getHaProvider(ServletContext context) {
+      return (HaProvider) context.getAttribute(PROVIDER_ATTRIBUTE_NAME);
+   }
+
+   private void setupHaProvider(HaDescriptor descriptor, ServletContext servletContext) {
+      GatewayServices services = (GatewayServices) servletContext.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
+      String clusterName = (String) servletContext.getAttribute(GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE);
+      ServiceRegistry serviceRegistry = services.getService(GatewayServices.SERVICE_REGISTRY_SERVICE);
+      HaProvider provider = new DefaultHaProvider(descriptor);
+      List<String> serviceNames = descriptor.getEnabledServiceNames();
+      for (String serviceName : serviceNames) {
+         provider.addHaService(serviceName, serviceRegistry.lookupServiceURLs(clusterName, serviceName));
+      }
+      servletContext.setAttribute(PROVIDER_ATTRIBUTE_NAME, provider);
+   }
+
+   private static URL locateDescriptor(ServletContext context) throws IOException {
+      String param = context.getInitParameter(DESCRIPTOR_LOCATION_INIT_PARAM_NAME);
+      if (param == null) {
+         param = DESCRIPTOR_DEFAULT_LOCATION;
+      }
+      URL url;
+      try {
+         url = context.getResource(param);
+      } catch (MalformedURLException e) {
+         // Ignore it and try using the value directly as a URL.
+         url = null;
+      }
+      if (url == null) {
+         url = new URL(param);
+      }
+      if (url == null) {
+         throw new FileNotFoundException(param);
+      }
+      return url;
+   }
+
+   private static HaDescriptor loadDescriptor(URL url) throws IOException {
+      InputStream stream = url.openStream();
+      HaDescriptor descriptor = HaDescriptorManager.load(stream);
+      try {
+         stream.close();
+      } catch (IOException e) {
+         LOG.failedToLoadHaDescriptor(e);
+      }
+      return descriptor;
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/URLManager.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/URLManager.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/URLManager.java
new file mode 100644
index 0000000..c5ee870
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/URLManager.java
@@ -0,0 +1,37 @@
+/**
+ * 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.knox.gateway.ha.provider;
+
+import java.util.List;
+
+public interface URLManager {
+
+  public boolean supportsConfig(HaServiceConfig config);
+
+  public void setConfig(HaServiceConfig config);
+
+  public String getActiveURL();
+
+  public void setActiveURL(String url);
+
+  public List<String> getURLs();
+
+  public void setURLs(List<String> urls);
+
+  public void markFailed(String url);
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/URLManagerLoader.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/URLManagerLoader.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/URLManagerLoader.java
new file mode 100644
index 0000000..df7ba21
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/URLManagerLoader.java
@@ -0,0 +1,43 @@
+/**
+ * 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.knox.gateway.ha.provider;
+
+import org.apache.knox.gateway.ha.provider.impl.DefaultURLManager;
+
+import java.util.Iterator;
+import java.util.ServiceLoader;
+
+public class URLManagerLoader {
+
+  public static URLManager loadURLManager(HaServiceConfig config) {
+    if (config != null) {
+      ServiceLoader<URLManager> loader = ServiceLoader.load(URLManager.class);
+      if ( loader != null ) {
+        Iterator<URLManager> iterator = loader.iterator();
+        while ( iterator.hasNext() ) {
+          URLManager urlManager = iterator.next();
+          if ( urlManager.supportsConfig(config) ) {
+            urlManager.setConfig(config);
+            return urlManager;
+          }
+        }
+      }
+    }
+    return new DefaultURLManager();
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/DefaultHaDescriptor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/DefaultHaDescriptor.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/DefaultHaDescriptor.java
new file mode 100644
index 0000000..b201bbe
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/DefaultHaDescriptor.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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.knox.gateway.ha.provider.impl;
+
+import com.google.common.collect.Lists;
+import org.apache.knox.gateway.ha.provider.HaDescriptor;
+import org.apache.knox.gateway.ha.provider.HaServiceConfig;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class DefaultHaDescriptor implements HaDescriptor {
+
+   private ConcurrentHashMap<String, HaServiceConfig> serviceConfigs;
+
+   public DefaultHaDescriptor() {
+      serviceConfigs = new ConcurrentHashMap<>();
+   }
+
+   @Override
+   public void addServiceConfig(HaServiceConfig serviceConfig) {
+      if (serviceConfig == null) {
+         throw new IllegalArgumentException("Service config must not be null");
+      }
+      serviceConfigs.put(serviceConfig.getServiceName(), serviceConfig);
+   }
+
+   @Override
+   public HaServiceConfig getServiceConfig(String serviceName) {
+      return serviceConfigs.get(serviceName);
+   }
+
+   @Override
+   public List<HaServiceConfig> getServiceConfigs() {
+      return Lists.newArrayList(serviceConfigs.values());
+   }
+
+   @Override
+   public List<String> getServiceNames() {
+      return Lists.newArrayList(serviceConfigs.keySet());
+   }
+
+   @Override
+   public List<String> getEnabledServiceNames() {
+      ArrayList<String> services = new ArrayList<String>(serviceConfigs.size());
+      Collection<HaServiceConfig> configs = serviceConfigs.values();
+      for (HaServiceConfig config : configs) {
+         if (config.isEnabled()) {
+            services.add(config.getServiceName());
+         }
+      }
+      return services;
+   }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/DefaultHaProvider.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/DefaultHaProvider.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/DefaultHaProvider.java
new file mode 100644
index 0000000..0039a26
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/DefaultHaProvider.java
@@ -0,0 +1,96 @@
+/**
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.knox.gateway.ha.provider.impl;
+
+import org.apache.knox.gateway.ha.provider.HaDescriptor;
+import org.apache.knox.gateway.ha.provider.HaProvider;
+import org.apache.knox.gateway.ha.provider.HaServiceConfig;
+import org.apache.knox.gateway.ha.provider.URLManager;
+import org.apache.knox.gateway.ha.provider.URLManagerLoader;
+import org.apache.knox.gateway.ha.provider.impl.i18n.HaMessages;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class DefaultHaProvider implements HaProvider {
+
+  private static final HaMessages LOG = MessagesFactory.get(HaMessages.class);
+
+  private HaDescriptor descriptor;
+
+  private ConcurrentHashMap<String, URLManager> haServices;
+
+  public DefaultHaProvider(HaDescriptor descriptor) {
+    if ( descriptor == null ) {
+      throw new IllegalArgumentException("Descriptor can not be null");
+    }
+    this.descriptor = descriptor;
+    haServices = new ConcurrentHashMap<>();
+  }
+
+  @Override
+  public HaDescriptor getHaDescriptor() {
+    return descriptor;
+  }
+
+  @Override
+  public void addHaService(String serviceName, List<String> urls) {
+    HaServiceConfig haServiceConfig = descriptor.getServiceConfig(serviceName);
+    URLManager manager = URLManagerLoader.loadURLManager(haServiceConfig);
+    manager.setURLs(urls);
+    haServices.put(serviceName, manager);
+  }
+
+  @Override
+  public boolean isHaEnabled(String serviceName) {
+    HaServiceConfig config = descriptor.getServiceConfig(serviceName);
+    if ( config != null && config.isEnabled() ) {
+      return true;
+    }
+    return false;
+  }
+
+  @Override
+  public String getActiveURL(String serviceName) {
+    if ( haServices.containsKey(serviceName) ) {
+      return haServices.get(serviceName).getActiveURL();
+    }
+    LOG.noActiveUrlFound(serviceName);
+    return null;
+  }
+
+  @Override
+  public void setActiveURL(String serviceName, String url) {
+    if ( haServices.containsKey(serviceName) ) {
+      haServices.get(serviceName).setActiveURL(url);
+    } else {
+      LOG.noServiceFound(serviceName);
+    }
+
+  }
+
+  @Override
+  public void markFailedURL(String serviceName, String url) {
+    if ( haServices.containsKey(serviceName) ) {
+      haServices.get(serviceName).markFailed(url);
+    } else {
+      LOG.noServiceFound(serviceName);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/DefaultHaServiceConfig.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/DefaultHaServiceConfig.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/DefaultHaServiceConfig.java
new file mode 100644
index 0000000..99a0583
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/DefaultHaServiceConfig.java
@@ -0,0 +1,124 @@
+/**
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.knox.gateway.ha.provider.impl;
+
+import org.apache.knox.gateway.ha.provider.HaServiceConfig;
+
+public class DefaultHaServiceConfig implements HaServiceConfig, HaServiceConfigConstants {
+
+  private String name;
+
+  private boolean enabled = DEFAULT_ENABLED;
+
+  private int maxFailoverAttempts = DEFAULT_MAX_FAILOVER_ATTEMPTS;
+
+  private int failoverSleep = DEFAULT_FAILOVER_SLEEP;
+
+  private int maxRetryAttempts = DEFAULT_MAX_RETRY_ATTEMPTS;
+
+  private int retrySleep = DEFAULT_RETRY_SLEEP;
+
+  private String zookeeperEnsemble;
+
+  private String zookeeperNamespace;
+
+  public DefaultHaServiceConfig(String name) {
+    this.name = name;
+  }
+
+  @Override
+
+  public String getServiceName() {
+    return name;
+  }
+
+  @Override
+  public void setServiceName(String name) {
+    this.name = name;
+  }
+
+  @Override
+  public boolean isEnabled() {
+    return enabled;
+  }
+
+  @Override
+  public void setEnabled(boolean enabled) {
+    this.enabled = enabled;
+  }
+
+  @Override
+  public int getMaxFailoverAttempts() {
+    return maxFailoverAttempts;
+  }
+
+  @Override
+  public void setMaxFailoverAttempts(int maxFailoverAttempts) {
+    this.maxFailoverAttempts = maxFailoverAttempts;
+  }
+
+  @Override
+  public int getFailoverSleep() {
+    return failoverSleep;
+  }
+
+  @Override
+  public void setFailoverSleep(int failoverSleep) {
+    this.failoverSleep = failoverSleep;
+  }
+
+  @Override
+  public int getMaxRetryAttempts() {
+    return maxRetryAttempts;
+  }
+
+  @Override
+  public void setMaxRetryAttempts(int maxRetryAttempts) {
+    this.maxRetryAttempts = maxRetryAttempts;
+  }
+
+  @Override
+  public int getRetrySleep() {
+    return retrySleep;
+  }
+
+  @Override
+  public void setRetrySleep(int retrySleep) {
+    this.retrySleep = retrySleep;
+  }
+
+  @Override
+  public String getZookeeperEnsemble() {
+    return zookeeperEnsemble;
+  }
+
+  @Override
+  public void setZookeeperEnsemble(String zookeeperEnsemble) {
+    this.zookeeperEnsemble = zookeeperEnsemble;
+  }
+
+  @Override
+  public String getZookeeperNamespace() {
+    return zookeeperNamespace;
+  }
+
+  @Override
+  public void setZookeeperNamespace(String zookeeperNamespace) {
+    this.zookeeperNamespace = zookeeperNamespace;
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/DefaultURLManager.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/DefaultURLManager.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/DefaultURLManager.java
new file mode 100644
index 0000000..a309c19
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/DefaultURLManager.java
@@ -0,0 +1,100 @@
+/**
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.knox.gateway.ha.provider.impl;
+
+import com.google.common.collect.Lists;
+import org.apache.knox.gateway.ha.provider.HaServiceConfig;
+import org.apache.knox.gateway.ha.provider.URLManager;
+import org.apache.knox.gateway.ha.provider.impl.i18n.HaMessages;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+
+import java.net.URI;
+import java.util.List;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+public class DefaultURLManager implements URLManager {
+
+  private static final HaMessages LOG = MessagesFactory.get(HaMessages.class);
+
+  private ConcurrentLinkedQueue<String> urls = new ConcurrentLinkedQueue<>();
+
+  public DefaultURLManager() {
+  }
+
+  @Override
+  public boolean supportsConfig(HaServiceConfig config) {
+    return true;
+  }
+
+  @Override
+  public void setConfig(HaServiceConfig config) {
+    //no-op
+  }
+
+  @Override
+  public String getActiveURL() {
+    return urls.peek();
+  }
+
+  @Override
+  public synchronized void setActiveURL(String url) {
+    String top = urls.peek();
+    if (top.equalsIgnoreCase(url)) {
+      return;
+    }
+    if (urls.contains(url)) {
+      urls.remove(url);
+      List<String> remainingList = getURLs();
+      urls.clear();
+      urls.add(url);
+      urls.addAll(remainingList);
+    }
+  }
+
+  @Override
+  public List<String> getURLs() {
+    return Lists.newArrayList(urls.iterator());
+  }
+
+  @Override
+  public synchronized void setURLs(List<String> urls) {
+    if ( urls != null && !urls.isEmpty()) {
+      this.urls.clear();
+      this.urls.addAll(urls);
+    }
+  }
+
+  @Override
+  public synchronized void markFailed(String url) {
+    String top = urls.peek();
+    boolean pushToBottom = false;
+    URI topUri = URI.create(top);
+    URI incomingUri = URI.create(url);
+    String topHostPort = topUri.getHost() + ":" + topUri.getPort();
+    String incomingHostPort = incomingUri.getHost() + ":" + incomingUri.getPort();
+    if ( topHostPort.equals(incomingHostPort) ) {
+      pushToBottom = true;
+    }
+    //put the failed url at the bottom
+    if ( pushToBottom ) {
+      String failed = urls.poll();
+      urls.offer(failed);
+      LOG.markedFailedUrl(failed, urls.peek());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HS2ZookeeperURLManager.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HS2ZookeeperURLManager.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HS2ZookeeperURLManager.java
new file mode 100644
index 0000000..f3322ec
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HS2ZookeeperURLManager.java
@@ -0,0 +1,145 @@
+/**
+ * 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.knox.gateway.ha.provider.impl;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+import org.apache.knox.gateway.ha.provider.HaServiceConfig;
+import org.apache.knox.gateway.ha.provider.impl.i18n.HaMessages;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class HS2ZookeeperURLManager extends DefaultURLManager {
+
+  private static final HaMessages LOG = MessagesFactory.get(HaMessages.class);
+
+  private static final Pattern kvPattern = Pattern.compile("([^=;]*)=([^;]*)[;]?");
+
+  private String zooKeeperEnsemble;
+
+  private String zooKeeperNamespace;
+
+  private HashSet<String> failedSet;
+
+  public HS2ZookeeperURLManager() {
+    failedSet = new LinkedHashSet<>();
+  }
+
+  @Override
+  public boolean supportsConfig(HaServiceConfig config) {
+    if (!config.getServiceName().equalsIgnoreCase("HIVE")) {
+      return false;
+    }
+    String zookeeperEnsemble = config.getZookeeperEnsemble();
+    String zookeeperNamespace = config.getZookeeperNamespace();
+    if ( zookeeperEnsemble != null && zookeeperNamespace != null && zookeeperEnsemble.trim().length() > 0 && zookeeperNamespace.trim().length() > 0) {
+      return true;
+    }
+    return false;
+  }
+
+  @Override
+  public void setConfig(HaServiceConfig config) {
+    zooKeeperEnsemble = config.getZookeeperEnsemble();
+    zooKeeperNamespace = config.getZookeeperNamespace();
+    setURLs(lookupURLs());
+  }
+
+  public List<String> lookupURLs() {
+    List<String> serverHosts = new ArrayList<>();
+    CuratorFramework zooKeeperClient =
+        CuratorFrameworkFactory.builder().connectString(zooKeeperEnsemble)
+            .retryPolicy(new ExponentialBackoffRetry(1000, 3)).build();
+    try {
+      zooKeeperClient.start();
+      List<String> serverNodes = zooKeeperClient.getChildren().forPath("/" + zooKeeperNamespace);
+      for ( String serverNode : serverNodes ) {
+        String serverInfo =
+            new String(
+                zooKeeperClient.getData().forPath("/" + zooKeeperNamespace + "/" + serverNode),
+                Charset.forName("UTF-8"));
+        String serverURL = constructURL(serverInfo);
+        serverHosts.add(serverURL);
+      }
+    } catch ( Exception e ) {
+      LOG.failedToGetZookeeperUrls(e);
+      throw new RuntimeException(e);
+    } finally {
+      // Close the client connection with ZooKeeper
+      if ( zooKeeperClient != null ) {
+        zooKeeperClient.close();
+      }
+    }
+    return serverHosts;
+  }
+
+  private String constructURL(String serverInfo) {
+    Matcher matcher = kvPattern.matcher(serverInfo);
+    String scheme = "http";
+    String host = null;
+    String port = "10001";
+    String httpPath = "cliservice";
+    while (matcher.find()) {
+      if ( (matcher.group(1) != null) && matcher.group(2) != null ) {
+        switch ( matcher.group(1) ) {
+          case "hive.server2.thrift.bind.host" :
+            host = matcher.group(2);
+            break;
+          case "hive.server2.thrift.http.port" :
+            port = matcher.group(2);
+            break;
+          case "hive.server2.thrift.http.path" :
+            httpPath = matcher.group(2);
+            break;
+          case "hive.server2.use.SSL" :
+            if (Boolean.parseBoolean(matcher.group(2))) {
+              scheme = "https";
+            }
+        }
+      }
+    }
+    StringBuffer buffer = new StringBuffer();
+    buffer.append(scheme);
+    buffer.append("://");
+    buffer.append(host);
+    buffer.append(":");
+    buffer.append(port);
+    buffer.append("/");
+    buffer.append(httpPath);
+    return buffer.toString();
+  }
+
+  @Override
+  public synchronized void markFailed(String url) {
+    failedSet.add(url);
+    //refresh the list when we have hit all urls once
+    if (failedSet.size() >= getURLs().size()) {
+      failedSet.clear();
+      setURLs(lookupURLs());
+    }
+    super.markFailed(url);
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HaDescriptorConstants.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HaDescriptorConstants.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HaDescriptorConstants.java
new file mode 100644
index 0000000..5ea6b4a
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HaDescriptorConstants.java
@@ -0,0 +1,49 @@
+/**
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.knox.gateway.ha.provider.impl;
+
+/**
+ * The constants for xml elements and attributes are meant to help render/consume the following:
+ * <p/>
+ * <ha>
+ * <service name='foo' failoverLimit='3' enabled='true'/>
+ * </ha>
+ */
+public interface HaDescriptorConstants {
+
+   public static final String ROOT_ELEMENT = "ha";
+
+   public static final String SERVICE_ELEMENT = "service";
+
+   public static final String SERVICE_NAME_ATTRIBUTE = "name";
+
+   public static final String MAX_FAILOVER_ATTEMPTS = "maxFailoverAttempts";
+
+   public static final String FAILOVER_SLEEP = "failoverSleep";
+
+   public static final String MAX_RETRY_ATTEMPTS = "maxRetryAttempts";
+
+   public static final String RETRY_SLEEP = "retrySleep";
+
+   public static final String ENABLED_ATTRIBUTE = "enabled";
+
+   public static final String ZOOKEEPER_ENSEMBLE = "zookeeperEnsemble";
+
+   public static final String ZOOKEEPER_NAMESPACE = "zookeeperNamespace";
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HaDescriptorFactory.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HaDescriptorFactory.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HaDescriptorFactory.java
new file mode 100644
index 0000000..741d7c5
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HaDescriptorFactory.java
@@ -0,0 +1,94 @@
+/**
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.knox.gateway.ha.provider.impl;
+
+import org.apache.knox.gateway.ha.provider.HaDescriptor;
+import org.apache.knox.gateway.ha.provider.HaServiceConfig;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public abstract class HaDescriptorFactory implements HaServiceConfigConstants {
+
+   public static HaDescriptor createDescriptor() {
+      return new DefaultHaDescriptor();
+   }
+
+   public static HaServiceConfig createServiceConfig(String serviceName, String config) {
+      Map<String, String> configMap = parseHaConfiguration(config);
+      String enabledValue = configMap.get(CONFIG_PARAM_ENABLED);
+      String maxFailoverAttempts = configMap.get(CONFIG_PARAM_MAX_FAILOVER_ATTEMPTS);
+      String failoverSleep = configMap.get(CONFIG_PARAM_FAILOVER_SLEEP);
+      String maxRetryAttempts = configMap.get(CONFIG_PARAM_MAX_RETRY_ATTEMPTS);
+      String retrySleep = configMap.get(CONFIG_PARAM_RETRY_SLEEP);
+      String zookeeperEnsemble = configMap.get(CONFIG_PARAM_ZOOKEEPER_ENSEMBLE);
+      String zookeeperNamespace = configMap.get(CONFIG_PARAM_ZOOKEEPER_NAMESPACE);
+      return createServiceConfig(serviceName, enabledValue, maxFailoverAttempts,
+          failoverSleep, maxRetryAttempts, retrySleep,
+          zookeeperEnsemble, zookeeperNamespace);
+   }
+
+   public static HaServiceConfig createServiceConfig(String serviceName, String enabledValue,
+                                                     String maxFailoverAttemptsValue, String failoverSleepValue,
+                                                     String maxRetryAttemptsValue, String retrySleepValue,
+                                                     String zookeeperEnsemble, String zookeeperNamespace) {
+      boolean enabled = DEFAULT_ENABLED;
+      int maxFailoverAttempts = DEFAULT_MAX_FAILOVER_ATTEMPTS;
+      int failoverSleep = DEFAULT_FAILOVER_SLEEP;
+      int maxRetryAttempts = DEFAULT_MAX_RETRY_ATTEMPTS;
+      int retrySleep = DEFAULT_RETRY_SLEEP;
+      if (enabledValue != null && enabledValue.trim().length() > 0) {
+         enabled = Boolean.parseBoolean(enabledValue);
+      }
+      if (maxFailoverAttemptsValue != null && maxFailoverAttemptsValue.trim().length() > 0) {
+         maxFailoverAttempts = Integer.parseInt(maxFailoverAttemptsValue);
+      }
+      if (failoverSleepValue != null && failoverSleepValue.trim().length() > 0) {
+         failoverSleep = Integer.parseInt(failoverSleepValue);
+      }
+      if (maxRetryAttemptsValue != null && maxRetryAttemptsValue.trim().length() > 0) {
+         maxRetryAttempts = Integer.parseInt(maxRetryAttemptsValue);
+      }
+      if (retrySleepValue != null && retrySleepValue.trim().length() > 0) {
+         retrySleep = Integer.parseInt(retrySleepValue);
+      }
+      DefaultHaServiceConfig serviceConfig = new DefaultHaServiceConfig(serviceName);
+      serviceConfig.setEnabled(enabled);
+      serviceConfig.setMaxFailoverAttempts(maxFailoverAttempts);
+      serviceConfig.setFailoverSleep(failoverSleep);
+      serviceConfig.setMaxRetryAttempts(maxRetryAttempts);
+      serviceConfig.setRetrySleep(retrySleep);
+      serviceConfig.setZookeeperEnsemble(zookeeperEnsemble);
+      serviceConfig.setZookeeperNamespace(zookeeperNamespace);
+      return serviceConfig;
+   }
+
+   private static Map<String, String> parseHaConfiguration(String configuration) {
+      Map<String, String> parameters = new HashMap<>();
+      if (configuration != null) {
+         String[] pairs = configuration.split(CONFIG_PAIRS_DELIMITER);
+         for (String pair : pairs) {
+            String[] tokens = pair.split(CONFIG_PAIR_DELIMITER);
+            if (tokens.length == 2) {
+               parameters.put(tokens[0], tokens[1]);
+            }
+         }
+      }
+      return parameters;
+   }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HaDescriptorManager.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HaDescriptorManager.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HaDescriptorManager.java
new file mode 100644
index 0000000..5e5402d
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HaDescriptorManager.java
@@ -0,0 +1,109 @@
+/**
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.knox.gateway.ha.provider.impl;
+
+import org.apache.knox.gateway.ha.provider.HaDescriptor;
+import org.apache.knox.gateway.ha.provider.HaServiceConfig;
+import org.apache.knox.gateway.ha.provider.impl.i18n.HaMessages;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.util.XmlUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+import java.util.List;
+
+public class HaDescriptorManager implements HaDescriptorConstants {
+
+   private static final HaMessages LOG = MessagesFactory.get(HaMessages.class);
+
+   public static void store(HaDescriptor descriptor, Writer writer) throws IOException {
+      try {
+         Document document = XmlUtils.createDocument();
+
+         Element root = document.createElement(ROOT_ELEMENT);
+         document.appendChild(root);
+
+         List<HaServiceConfig> serviceConfigs = descriptor.getServiceConfigs();
+         if (serviceConfigs != null && !serviceConfigs.isEmpty()) {
+            for (HaServiceConfig config : serviceConfigs) {
+               Element serviceElement = document.createElement(SERVICE_ELEMENT);
+               serviceElement.setAttribute(SERVICE_NAME_ATTRIBUTE, config.getServiceName());
+               serviceElement.setAttribute(MAX_FAILOVER_ATTEMPTS, Integer.toString(config.getMaxFailoverAttempts()));
+               serviceElement.setAttribute(FAILOVER_SLEEP, Integer.toString(config.getFailoverSleep()));
+               serviceElement.setAttribute(MAX_RETRY_ATTEMPTS, Integer.toString(config.getMaxRetryAttempts()));
+               serviceElement.setAttribute(RETRY_SLEEP, Integer.toString(config.getRetrySleep()));
+               serviceElement.setAttribute(ENABLED_ATTRIBUTE, Boolean.toString(config.isEnabled()));
+               if (config.getZookeeperEnsemble() != null) {
+                 serviceElement.setAttribute(ZOOKEEPER_ENSEMBLE, config.getZookeeperEnsemble());
+               }
+               if (config.getZookeeperNamespace() != null) {
+                 serviceElement.setAttribute(ZOOKEEPER_NAMESPACE, config.getZookeeperNamespace());
+               }
+               root.appendChild(serviceElement);
+            }
+         }
+
+         Transformer t = XmlUtils.getTransformer( true, true, 2, false );
+         XmlUtils.writeXml( document, writer, t );
+      } catch (ParserConfigurationException e) {
+         LOG.failedToWriteHaDescriptor(e);
+         throw new IOException(e);
+      } catch (TransformerException e) {
+         LOG.failedToWriteHaDescriptor(e);
+         throw new IOException(e);
+      }
+   }
+
+   public static HaDescriptor load(InputStream inputStream) throws IOException {
+      HaDescriptor descriptor = HaDescriptorFactory.createDescriptor();
+      try {
+         Document document = XmlUtils.readXml( inputStream );
+         NodeList nodeList = document.getElementsByTagName(SERVICE_ELEMENT);
+         if (nodeList != null && nodeList.getLength() > 0) {
+            for (int i = 0; i < nodeList.getLength(); i++) {
+               Element element = (Element) nodeList.item(i);
+               HaServiceConfig config = HaDescriptorFactory.createServiceConfig(element.getAttribute(SERVICE_NAME_ATTRIBUTE),
+                     element.getAttribute(ENABLED_ATTRIBUTE),
+                     element.getAttribute(MAX_FAILOVER_ATTEMPTS),
+                     element.getAttribute(FAILOVER_SLEEP),
+                     element.getAttribute(MAX_RETRY_ATTEMPTS),
+                     element.getAttribute(RETRY_SLEEP),
+                     element.getAttribute(ZOOKEEPER_ENSEMBLE),
+                     element.getAttribute(ZOOKEEPER_NAMESPACE));
+               descriptor.addServiceConfig(config);
+            }
+         }
+      } catch (ParserConfigurationException e) {
+         LOG.failedToLoadHaDescriptor(e);
+         throw new IOException(e);
+      } catch (SAXException e) {
+         LOG.failedToLoadHaDescriptor(e);
+         throw new IOException(e);
+      }
+      return descriptor;
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HaServiceConfigConstants.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HaServiceConfigConstants.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HaServiceConfigConstants.java
new file mode 100644
index 0000000..6cec6cc
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HaServiceConfigConstants.java
@@ -0,0 +1,50 @@
+/**
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.knox.gateway.ha.provider.impl;
+
+public interface HaServiceConfigConstants {
+
+   public static final String CONFIG_PAIRS_DELIMITER = ";";
+
+   public static final String CONFIG_PAIR_DELIMITER = "=";
+
+   public static final String CONFIG_PARAM_MAX_FAILOVER_ATTEMPTS = "maxFailoverAttempts";
+
+   public static final String CONFIG_PARAM_FAILOVER_SLEEP = "failoverSleep";
+
+   public static final String CONFIG_PARAM_MAX_RETRY_ATTEMPTS = "maxRetryAttempts";
+
+   public static final String CONFIG_PARAM_RETRY_SLEEP = "retrySleep";
+
+   public static final String CONFIG_PARAM_ENABLED = "enabled";
+
+   public static final String CONFIG_PARAM_ZOOKEEPER_ENSEMBLE = "zookeeperEnsemble";
+
+   public static final String CONFIG_PARAM_ZOOKEEPER_NAMESPACE = "zookeeperNamespace";
+
+   public static final int DEFAULT_MAX_FAILOVER_ATTEMPTS = 3;
+
+   public static final int DEFAULT_FAILOVER_SLEEP = 1000;
+
+   public static final int DEFAULT_MAX_RETRY_ATTEMPTS = 3;
+
+   public static final int DEFAULT_RETRY_SLEEP = 1000;
+
+   public static final boolean DEFAULT_ENABLED = true;
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/i18n/HaMessages.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/i18n/HaMessages.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/i18n/HaMessages.java
new file mode 100644
index 0000000..3848c46
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/i18n/HaMessages.java
@@ -0,0 +1,45 @@
+/**
+ * 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.knox.gateway.ha.provider.impl.i18n;
+
+import org.apache.knox.gateway.i18n.messages.Message;
+import org.apache.knox.gateway.i18n.messages.MessageLevel;
+import org.apache.knox.gateway.i18n.messages.Messages;
+
+@Messages(logger = "org.apache.hadoop.gateway")
+public interface HaMessages {
+
+   @Message(level = MessageLevel.ERROR, text = "Failed to Write HA Descriptor: {0}")
+   void failedToWriteHaDescriptor(Exception e);
+
+   @Message(level = MessageLevel.ERROR, text = "Failed to load HA Descriptor: {0}")
+   void failedToLoadHaDescriptor(Exception e);
+
+   @Message(level = MessageLevel.INFO, text = "No Active URL was found for service: {0}")
+   void noActiveUrlFound(String serviceName);
+
+   @Message(level = MessageLevel.INFO, text = "No Service by this name was found: {0}")
+   void noServiceFound(String serviceName);
+
+   @Message(level = MessageLevel.DEBUG, text = "Moving failed URL to the bottom {0}, new top is {1}")
+   void markedFailedUrl(String failedUrl, String top);
+
+  @Message(level = MessageLevel.ERROR, text = "Failed to get Zookeeper URLs : {0}")
+  void failedToGetZookeeperUrls(Exception e);
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.hadoop.gateway.deploy.ProviderDeploymentContributor
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.hadoop.gateway.deploy.ProviderDeploymentContributor b/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.hadoop.gateway.deploy.ProviderDeploymentContributor
deleted file mode 100644
index 995a093..0000000
--- a/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.hadoop.gateway.deploy.ProviderDeploymentContributor
+++ /dev/null
@@ -1,19 +0,0 @@
-##########################################################################
-# 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.
-##########################################################################
-
-org.apache.hadoop.gateway.ha.deploy.HaProviderDeploymentContributor

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.hadoop.gateway.ha.provider.URLManager
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.hadoop.gateway.ha.provider.URLManager b/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.hadoop.gateway.ha.provider.URLManager
deleted file mode 100644
index d1ec0b9..0000000
--- a/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.hadoop.gateway.ha.provider.URLManager
+++ /dev/null
@@ -1,19 +0,0 @@
-##########################################################################
-# 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.
-##########################################################################
-
-org.apache.hadoop.gateway.ha.provider.impl.HS2ZookeeperURLManager
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.knox.gateway.deploy.ProviderDeploymentContributor
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.knox.gateway.deploy.ProviderDeploymentContributor b/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.knox.gateway.deploy.ProviderDeploymentContributor
new file mode 100644
index 0000000..4e1a86a
--- /dev/null
+++ b/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.knox.gateway.deploy.ProviderDeploymentContributor
@@ -0,0 +1,19 @@
+##########################################################################
+# 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.
+##########################################################################
+
+org.apache.knox.gateway.ha.deploy.HaProviderDeploymentContributor

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.knox.gateway.ha.provider.URLManager
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.knox.gateway.ha.provider.URLManager b/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.knox.gateway.ha.provider.URLManager
new file mode 100644
index 0000000..e579be8
--- /dev/null
+++ b/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.knox.gateway.ha.provider.URLManager
@@ -0,0 +1,19 @@
+##########################################################################
+# 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.
+##########################################################################
+
+org.apache.knox.gateway.ha.provider.impl.HS2ZookeeperURLManager
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/test/java/org/apache/hadoop/gateway/ha/deploy/HaProviderDeploymentContributorTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/test/java/org/apache/hadoop/gateway/ha/deploy/HaProviderDeploymentContributorTest.java b/gateway-provider-ha/src/test/java/org/apache/hadoop/gateway/ha/deploy/HaProviderDeploymentContributorTest.java
deleted file mode 100644
index c39ca85..0000000
--- a/gateway-provider-ha/src/test/java/org/apache/hadoop/gateway/ha/deploy/HaProviderDeploymentContributorTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * 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
- * <p/>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p/>
- * 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.gateway.ha.deploy;
-
-import org.apache.hadoop.gateway.deploy.ProviderDeploymentContributor;
-import org.junit.Test;
-
-import java.util.Iterator;
-import java.util.ServiceLoader;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.fail;
-
-
-public class HaProviderDeploymentContributorTest {
-
-   @Test
-   public void testServiceLoader() throws Exception {
-      ServiceLoader loader = ServiceLoader.load( ProviderDeploymentContributor.class );
-      Iterator iterator = loader.iterator();
-      assertThat( "Service iterator empty.", iterator.hasNext() );
-      while( iterator.hasNext() ) {
-         Object object = iterator.next();
-         if( object instanceof HaProviderDeploymentContributor ) {
-            return;
-         }
-      }
-      fail( "Failed to find " + HaProviderDeploymentContributor.class.getName() + " via service loader." );
-   }
-
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-ha/src/test/java/org/apache/hadoop/gateway/ha/dispatch/DefaultHaDispatchTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/test/java/org/apache/hadoop/gateway/ha/dispatch/DefaultHaDispatchTest.java b/gateway-provider-ha/src/test/java/org/apache/hadoop/gateway/ha/dispatch/DefaultHaDispatchTest.java
deleted file mode 100644
index 0436532..0000000
--- a/gateway-provider-ha/src/test/java/org/apache/hadoop/gateway/ha/dispatch/DefaultHaDispatchTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/**
- * 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.gateway.ha.dispatch;
-
-import org.apache.hadoop.gateway.ha.provider.HaDescriptor;
-import org.apache.hadoop.gateway.ha.provider.HaProvider;
-import org.apache.hadoop.gateway.ha.provider.HaServletContextListener;
-import org.apache.hadoop.gateway.ha.provider.impl.DefaultHaProvider;
-import org.apache.hadoop.gateway.ha.provider.impl.HaDescriptorFactory;
-import org.apache.hadoop.gateway.servlet.SynchronousServletOutputStreamAdapter;
-import org.apache.http.client.methods.HttpRequestBase;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.params.BasicHttpParams;
-import org.easymock.EasyMock;
-import org.easymock.IAnswer;
-import org.junit.Assert;
-import org.junit.Test;
-
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.concurrent.atomic.AtomicInteger;
-
-public class DefaultHaDispatchTest {
-
-  @Test
-  public void testConnectivityFailover() throws Exception {
-    String serviceName = "OOZIE";
-    HaDescriptor descriptor = HaDescriptorFactory.createDescriptor();
-    descriptor.addServiceConfig(HaDescriptorFactory.createServiceConfig(serviceName, "true", "1", "1000", "2", "1000", null, null));
-    HaProvider provider = new DefaultHaProvider(descriptor);
-    URI uri1 = new URI( "http://unreachable-host" );
-    URI uri2 = new URI( "http://reachable-host" );
-    ArrayList<String> urlList = new ArrayList<String>();
-    urlList.add(uri1.toString());
-    urlList.add(uri2.toString());
-    provider.addHaService(serviceName, urlList);
-    FilterConfig filterConfig = EasyMock.createNiceMock(FilterConfig.class);
-    ServletContext servletContext = EasyMock.createNiceMock(ServletContext.class);
-
-    EasyMock.expect(filterConfig.getServletContext()).andReturn(servletContext).anyTimes();
-    EasyMock.expect(servletContext.getAttribute(HaServletContextListener.PROVIDER_ATTRIBUTE_NAME)).andReturn(provider).anyTimes();
-
-    BasicHttpParams params = new BasicHttpParams();
-
-    HttpUriRequest outboundRequest = EasyMock.createNiceMock(HttpRequestBase.class);
-    EasyMock.expect(outboundRequest.getMethod()).andReturn( "GET" ).anyTimes();
-    EasyMock.expect(outboundRequest.getURI()).andReturn( uri1  ).anyTimes();
-    EasyMock.expect(outboundRequest.getParams()).andReturn( params ).anyTimes();
-
-    HttpServletRequest inboundRequest = EasyMock.createNiceMock(HttpServletRequest.class);
-    EasyMock.expect(inboundRequest.getRequestURL()).andReturn( new StringBuffer(uri2.toString()) ).once();
-    EasyMock.expect(inboundRequest.getAttribute("dispatch.ha.failover.counter")).andReturn(new AtomicInteger(0)).once();
-    EasyMock.expect(inboundRequest.getAttribute("dispatch.ha.failover.counter")).andReturn(new AtomicInteger(1)).once();
-
-    HttpServletResponse outboundResponse = EasyMock.createNiceMock(HttpServletResponse.class);
-    EasyMock.expect(outboundResponse.getOutputStream()).andAnswer( new IAnswer<SynchronousServletOutputStreamAdapter>() {
-      @Override
-      public SynchronousServletOutputStreamAdapter answer() throws Throwable {
-        return new SynchronousServletOutputStreamAdapter() {
-          @Override
-          public void write( int b ) throws IOException {
-            throw new IOException( "unreachable-host" );
-          }
-        };
-      }
-    }).once();
-    EasyMock.replay(filterConfig, servletContext, outboundRequest, inboundRequest, outboundResponse);
-    Assert.assertEquals(uri1.toString(), provider.getActiveURL(serviceName));
-    DefaultHaDispatch dispatch = new DefaultHaDispatch();
-    dispatch.setHttpClient(new DefaultHttpClient());
-    dispatch.setHaProvider(provider);
-    dispatch.setServiceRole(serviceName);
-    dispatch.init();
-    long startTime = System.currentTimeMillis();
-    try {
-      dispatch.executeRequest(outboundRequest, inboundRequest, outboundResponse);
-    } catch (IOException e) {
-      //this is expected after the failover limit is reached
-    }
-    long elapsedTime = System.currentTimeMillis() - startTime;
-    Assert.assertEquals(uri2.toString(), provider.getActiveURL(serviceName));
-    //test to make sure the sleep took place
-    Assert.assertTrue(elapsedTime > 1000);
-  }
-}