You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by su...@apache.org on 2015/02/18 05:29:34 UTC

[49/50] [abbrv] knox git commit: Cleanup, logging and some tests KNOX-481

Cleanup, logging and some tests KNOX-481


Project: http://git-wip-us.apache.org/repos/asf/knox/repo
Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/2a78e7cc
Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/2a78e7cc
Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/2a78e7cc

Branch: refs/heads/KNOX-481
Commit: 2a78e7cc7fd00e8dcf948d3bf50a3f2547383000
Parents: 6866353
Author: Sumit Gupta <su...@apache.org>
Authored: Tue Feb 17 22:28:13 2015 -0500
Committer: Sumit Gupta <su...@apache.org>
Committed: Tue Feb 17 23:21:44 2015 -0500

----------------------------------------------------------------------
 .../apache/hadoop/gateway/GatewayMessages.java  |  10 ++
 .../gateway/config/impl/GatewayConfigImpl.java  |   7 +-
 .../impl/DispatchDeploymentContributor.java     |   1 -
 .../gateway/util/ServiceDefinitionsLoader.java  | 117 ++++++++++---------
 .../hadoop/gateway/GatewayGlobalConfigTest.java |  16 ++-
 ...viceDefinitionDeploymentContributorTest.java |  43 +++++++
 .../topology/xml/TopologyRulesModuleTest.java   |   3 -
 .../util/ServiceDefinitionsLoaderTest.java      |  49 ++++++++
 .../resources/conf-demo/conf/gateway-site.xml   |   7 +-
 .../resources/services/bar/2.0.0/service.xml    |  21 ++++
 .../resources/services/foo/1.0.0/rewrite.xml    |  21 ++++
 .../resources/services/foo/1.0.0/service.xml    |  23 ++++
 .../definition/ServiceDefinitionTest.java       |  44 +++++--
 .../resources/services/foo/1.0.0/rewrite.xml    |  21 ++++
 .../resources/services/foo/1.0.0/service.xml    |  39 +++++++
 ...NameNodeHaDispatchDeploymentContributor.java |  66 -----------
 .../hdfs/dispatch/WebHdfsHaDispatchFilter.java  |  36 ------
 ...gateway.deploy.ProviderDeploymentContributor |  19 ---
 ...NodeHaDispatchDeploymentContributorTest.java |  44 -------
 .../config/FilterConfigurationAdapter.java      |   1 -
 .../deploy/ServiceDeploymentContributor.java    |   5 +
 .../hadoop/gateway/topology/VersionTest.java    |  50 ++++++++
 22 files changed, 406 insertions(+), 237 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java
index 72ab1c2..78f0d83 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java
@@ -333,4 +333,14 @@ public interface GatewayMessages {
 
   @Message( level = MessageLevel.INFO, text = "Configured stacks directory is {0}" )
   void usingStacksDirectory(String path);
+
+  @Message( level = MessageLevel.ERROR, text = "Failed to load {0} file : {1}" )
+  void failedToLoadServiceDefinition(String fileName, @StackTrace( level = MessageLevel.DEBUG ) Exception e);
+
+  @Message( level = MessageLevel.DEBUG, text = "No rewrite file found in service directory {0}" )
+  void noRewriteFileFound(String path);
+
+  @Message( level = MessageLevel.DEBUG, text = "Added Service definition name: {0}, role : {1}, version : {2}" )
+  void addedServiceDefinition(String serviceName, String serviceRole, String version);
+
 }

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-server/src/main/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImpl.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImpl.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImpl.java
index 09b9040..a1a3f3c 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImpl.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImpl.java
@@ -75,7 +75,7 @@ public class GatewayConfigImpl extends Configuration implements GatewayConfig {
 
   private static final String GATEWAY_CONFIG_FILE_PREFIX = "gateway";
 
-  private static final String STACKS_SERVICES_DIRECTORY = "services";
+  private static final String DEFAULT_STACKS_SERVICES_DIR = "services";
 
   public static final String[] GATEWAY_CONFIG_FILENAMES = {
       GATEWAY_CONFIG_DIR_PREFIX + "/" + GATEWAY_CONFIG_FILE_PREFIX + "-default.xml",
@@ -102,6 +102,7 @@ public class GatewayConfigImpl extends Configuration implements GatewayConfig {
   public static final String DEPLOYMENT_DIR = GATEWAY_CONFIG_FILE_PREFIX + ".deployment.dir";
   public static final String SECURITY_DIR = GATEWAY_CONFIG_FILE_PREFIX + ".security.dir";
   public static final String DATA_DIR = GATEWAY_CONFIG_FILE_PREFIX + ".data.dir";
+  public static final String STACKS_SERVICES_DIR = GATEWAY_CONFIG_FILE_PREFIX + ".services.dir";
   public static final String HADOOP_CONF_DIR = GATEWAY_CONFIG_FILE_PREFIX + ".hadoop.conf.dir";
   public static final String FRONTEND_URL = GATEWAY_CONFIG_FILE_PREFIX + ".frontend.url";
   private static final String TRUST_ALL_CERTS = GATEWAY_CONFIG_FILE_PREFIX + ".trust.all.certs";
@@ -177,9 +178,9 @@ public class GatewayConfigImpl extends Configuration implements GatewayConfig {
 
   @Override
   public String getGatewayStacksDir() {
-    return getGatewayDataDir() + File.separator + STACKS_SERVICES_DIRECTORY;
+    return get(STACKS_SERVICES_DIR, getGatewayDataDir() + File.separator + DEFAULT_STACKS_SERVICES_DIR);
   }
- 
+
   @Override
   public String getHadoopConfDir() {
     return get( HADOOP_CONF_DIR );

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-server/src/main/java/org/apache/hadoop/gateway/deploy/impl/DispatchDeploymentContributor.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/deploy/impl/DispatchDeploymentContributor.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/deploy/impl/DispatchDeploymentContributor.java
index 30f2c65..b7dccb0 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/deploy/impl/DispatchDeploymentContributor.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/deploy/impl/DispatchDeploymentContributor.java
@@ -66,7 +66,6 @@ public class DispatchDeploymentContributor extends ProviderDeploymentContributor
         }
       }
     }
-
     if( context.getGatewayConfig().isHadoopKerberosSecured() ) {
       filter.param().name("kerberos").value("true");
     }

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-server/src/main/java/org/apache/hadoop/gateway/util/ServiceDefinitionsLoader.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/util/ServiceDefinitionsLoader.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/util/ServiceDefinitionsLoader.java
index 3d41605..9691ac0 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/util/ServiceDefinitionsLoader.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/util/ServiceDefinitionsLoader.java
@@ -20,76 +20,89 @@ package org.apache.hadoop.gateway.util;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.filefilter.IOFileFilter;
 import org.apache.commons.io.filefilter.TrueFileFilter;
+import org.apache.hadoop.gateway.GatewayMessages;
 import org.apache.hadoop.gateway.deploy.ServiceDeploymentContributor;
 import org.apache.hadoop.gateway.deploy.impl.ServiceDefinitionDeploymentContributor;
 import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteRulesDescriptor;
 import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteRulesDescriptorFactory;
+import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
 import org.apache.hadoop.gateway.service.definition.ServiceDefinition;
 
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBException;
 import javax.xml.bind.Unmarshaller;
-import java.io.*;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
 
 public class ServiceDefinitionsLoader {
+  private static GatewayMessages log = MessagesFactory.get(GatewayMessages.class);
 
-    public static Set<ServiceDeploymentContributor> loadServiceDefinitions(File servicesDir) {
-        Set<ServiceDeploymentContributor> contributors = new HashSet<ServiceDeploymentContributor>();
-        if (servicesDir.exists() && servicesDir.isDirectory()) {
-            JAXBContext context = null;
-            try {
-                context = JAXBContext.newInstance(ServiceDefinition.class);
-                Unmarshaller unmarshaller = context.createUnmarshaller();
-                Collection<File> files = FileUtils.listFiles(servicesDir, new IOFileFilter() {
-                    @Override
-                    public boolean accept(File file) {
-                        return file.getName().contains("service");
-                    }
+  private static String SERVICE_FILE_NAME = "service";
 
-                    @Override
-                    public boolean accept(File dir, String name) {
-                        return name.contains("service");
-                    }
-                }, TrueFileFilter.INSTANCE);
-                for (File file : files) {
-                    try {
-                        FileInputStream inputStream = new FileInputStream(file);
-                        ServiceDefinition definition = (ServiceDefinition) unmarshaller.unmarshal(inputStream);
-                        //look for rewrite rules as a sibling (for now)
-                        UrlRewriteRulesDescriptor rewriteRulesDescriptor = loadRewriteRules(file.getParentFile());
-                        contributors.add(new ServiceDefinitionDeploymentContributor(definition, rewriteRulesDescriptor));
-                    } catch (FileNotFoundException e) {
-                        e.printStackTrace();
-                    }
-                }
-            } catch (JAXBException e) {
-                e.printStackTrace();
-            }
+  private static String REWRITE_FILE = "rewrite.xml";
+
+  public static Set<ServiceDeploymentContributor> loadServiceDefinitions(File servicesDir) {
+    Set<ServiceDeploymentContributor> contributors = new HashSet<ServiceDeploymentContributor>();
+    if ( servicesDir.exists() && servicesDir.isDirectory() ) {
+      try {
+        JAXBContext context = JAXBContext.newInstance(ServiceDefinition.class);
+        Unmarshaller unmarshaller = context.createUnmarshaller();
+        Collection<File> files = FileUtils.listFiles(servicesDir, new IOFileFilter() {
+          @Override
+          public boolean accept(File file) {
+            return file.getName().contains(SERVICE_FILE_NAME);
+          }
+          @Override
+          public boolean accept(File dir, String name) {
+            return name.contains(SERVICE_FILE_NAME);
+          }
+        }, TrueFileFilter.INSTANCE);
+        for ( File file : files ) {
+          try {
+            FileInputStream inputStream = new FileInputStream(file);
+            ServiceDefinition definition = (ServiceDefinition) unmarshaller.unmarshal(inputStream);
+            //look for rewrite rules as a sibling (for now)
+            UrlRewriteRulesDescriptor rewriteRulesDescriptor = loadRewriteRules(file.getParentFile());
+            contributors.add(new ServiceDefinitionDeploymentContributor(definition, rewriteRulesDescriptor));
+            log.addedServiceDefinition(definition.getName(), definition.getRole(), definition.getVersion());
+          } catch ( FileNotFoundException e ) {
+            log.failedToLoadServiceDefinition(file.getAbsolutePath(), e);
+          }
         }
-        return contributors;
+      } catch ( JAXBException e ) {
+        log.failedToLoadServiceDefinition(SERVICE_FILE_NAME, e);
+      }
     }
+    return contributors;
+  }
 
-    private static UrlRewriteRulesDescriptor loadRewriteRules(File servicesDir) {
-        File rewriteFile = new File(servicesDir, "rewrite.xml");
-        if (rewriteFile.exists()) {
-            InputStream stream = null;
-            try {
-                stream = new FileInputStream(rewriteFile);
-                Reader reader = new InputStreamReader(stream);
-                UrlRewriteRulesDescriptor rules = UrlRewriteRulesDescriptorFactory.load(
-                        "xml", reader);
-                reader.close();
-                stream.close();
-                return rules;
-            } catch (FileNotFoundException e) {
-                e.printStackTrace();
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-        }
-        return null;
+  private static UrlRewriteRulesDescriptor loadRewriteRules(File servicesDir) {
+    File rewriteFile = new File(servicesDir, REWRITE_FILE);
+    if ( rewriteFile.exists() ) {
+      InputStream stream = null;
+      try {
+        stream = new FileInputStream(rewriteFile);
+        Reader reader = new InputStreamReader(stream);
+        UrlRewriteRulesDescriptor rules = UrlRewriteRulesDescriptorFactory.load(
+            "xml", reader);
+        reader.close();
+        stream.close();
+        return rules;
+      } catch ( FileNotFoundException e ) {
+        log.failedToLoadServiceDefinition(rewriteFile.getAbsolutePath(), e);
+      } catch ( IOException e ) {
+        log.failedToLoadServiceDefinition(rewriteFile.getAbsolutePath(), e);
+      }
     }
+    log.noRewriteFileFound(servicesDir.getAbsolutePath());
+    return null;
+  }
 }

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-server/src/test/java/org/apache/hadoop/gateway/GatewayGlobalConfigTest.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/GatewayGlobalConfigTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/GatewayGlobalConfigTest.java
index d9957bd..45e98ca 100644
--- a/gateway-server/src/test/java/org/apache/hadoop/gateway/GatewayGlobalConfigTest.java
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/GatewayGlobalConfigTest.java
@@ -19,15 +19,15 @@ package org.apache.hadoop.gateway;
 
 import org.apache.hadoop.gateway.config.GatewayConfig;
 import org.apache.hadoop.gateway.config.impl.GatewayConfigImpl;
+import org.easymock.internal.matchers.EndsWith;
+import org.hamcrest.Matchers;
 import org.junit.Test;
 
 import java.io.File;
 import java.net.URL;
 
 import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 
 public class GatewayGlobalConfigTest {
 
@@ -169,5 +169,15 @@ public class GatewayGlobalConfigTest {
         .getGatewayDataDir()));
   }
 
+  @Test
+  public void testStacksServicesDir() {
+    System.clearProperty(GatewayConfigImpl.GATEWAY_HOME_VAR);
+    GatewayConfig config = new GatewayConfigImpl();
+    assertThat(config.getGatewayStacksDir(), Matchers.endsWith("data/services"));
+    String homeDirName = getHomeDirName("conf-demo/conf/gateway-site.xml");
+    System.setProperty(GatewayConfigImpl.GATEWAY_HOME_VAR, homeDirName);
+    config = new GatewayConfigImpl();
+    assertEquals("target/test", config.getGatewayStacksDir());
+  }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-server/src/test/java/org/apache/hadoop/gateway/deploy/impl/ServiceDefinitionDeploymentContributorTest.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/deploy/impl/ServiceDefinitionDeploymentContributorTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/deploy/impl/ServiceDefinitionDeploymentContributorTest.java
new file mode 100644
index 0000000..c18f977
--- /dev/null
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/deploy/impl/ServiceDefinitionDeploymentContributorTest.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.hadoop.gateway.deploy.impl;
+
+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 ServiceDefinitionDeploymentContributorTest {
+
+  @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 ServiceDefinitionDeploymentContributor ) {
+        fail("The ServiceDefinition deployment contributor is not meant to be loaded using the service loader mechanism");
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/xml/TopologyRulesModuleTest.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/xml/TopologyRulesModuleTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/xml/TopologyRulesModuleTest.java
index 85836fc..21934f1 100644
--- a/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/xml/TopologyRulesModuleTest.java
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/xml/TopologyRulesModuleTest.java
@@ -17,9 +17,6 @@
  */
 package org.apache.hadoop.gateway.topology.xml;
 
-import org.apache.commons.collections.keyvalue.MultiKey;
-import org.apache.commons.collections.map.HashedMap;
-import org.apache.commons.collections.map.MultiKeyMap;
 import org.apache.commons.digester3.Digester;
 import org.apache.commons.digester3.binder.DigesterLoader;
 import org.apache.hadoop.gateway.topology.Provider;

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-server/src/test/java/org/apache/hadoop/gateway/util/ServiceDefinitionsLoaderTest.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/util/ServiceDefinitionsLoaderTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/util/ServiceDefinitionsLoaderTest.java
new file mode 100644
index 0000000..d602813
--- /dev/null
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/util/ServiceDefinitionsLoaderTest.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
+ *
+ *     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.util;
+
+import org.apache.hadoop.gateway.deploy.ServiceDeploymentContributor;
+import org.junit.Test;
+
+import java.io.File;
+import java.net.URL;
+import java.util.Set;
+
+import static org.junit.Assert.*;
+
+public class ServiceDefinitionsLoaderTest {
+
+  @Test
+  public void testServiceDefinitionLoading() {
+    URL url = ClassLoader.getSystemResource("services");
+    Set<ServiceDeploymentContributor> contributors = ServiceDefinitionsLoader.loadServiceDefinitions(new File(url.getFile()));
+    assertNotNull(contributors);
+    assertEquals(2, contributors.size());
+    for (ServiceDeploymentContributor contributor : contributors) {
+      if (contributor.getName().equals("foo")) {
+        assertEquals("1.0.0", contributor.getVersion().toString());
+        assertEquals("FOO", contributor.getRole());
+      } else if (contributor.getName().equals("bar")) {
+        assertEquals("2.0.0", contributor.getVersion().toString());
+        assertEquals("BAR", contributor.getRole());
+      } else {
+        fail("the loaded services don't match the test input");
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-server/src/test/resources/conf-demo/conf/gateway-site.xml
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/resources/conf-demo/conf/gateway-site.xml b/gateway-server/src/test/resources/conf-demo/conf/gateway-site.xml
index aaee777..3225adc 100644
--- a/gateway-server/src/test/resources/conf-demo/conf/gateway-site.xml
+++ b/gateway-server/src/test/resources/conf-demo/conf/gateway-site.xml
@@ -69,6 +69,9 @@ limitations under the License.
         <value>target/testDataDir</value>
         <description>The path that contains Gateway Data (Security and deployments)</description>
     </property>
-    
-
+     <property>
+        <name>gateway.services.dir</name>
+        <value>target/test</value>
+        <description>The path that contains the service definitions</description>
+    </property>
 </configuration>

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-server/src/test/resources/services/bar/2.0.0/service.xml
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/resources/services/bar/2.0.0/service.xml b/gateway-server/src/test/resources/services/bar/2.0.0/service.xml
new file mode 100644
index 0000000..1cd6cc3
--- /dev/null
+++ b/gateway-server/src/test/resources/services/bar/2.0.0/service.xml
@@ -0,0 +1,21 @@
+<!--
+   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.
+-->
+<service role="BAR" name="bar" version="2.0.0">
+    <routes>
+        <route path="/bar/?**"/>
+    </routes>
+</service>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-server/src/test/resources/services/foo/1.0.0/rewrite.xml
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/resources/services/foo/1.0.0/rewrite.xml b/gateway-server/src/test/resources/services/foo/1.0.0/rewrite.xml
new file mode 100644
index 0000000..761bd4b
--- /dev/null
+++ b/gateway-server/src/test/resources/services/foo/1.0.0/rewrite.xml
@@ -0,0 +1,21 @@
+<!--
+   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.
+-->
+<rules>
+    <rule dir="IN" name="FOO/foo/inbound" pattern="*://*:*/**/foo">
+        <rewrite template="{$serviceUrl[FOO]}"/>
+    </rule>
+</rules>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-server/src/test/resources/services/foo/1.0.0/service.xml
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/resources/services/foo/1.0.0/service.xml b/gateway-server/src/test/resources/services/foo/1.0.0/service.xml
new file mode 100644
index 0000000..f739b0b
--- /dev/null
+++ b/gateway-server/src/test/resources/services/foo/1.0.0/service.xml
@@ -0,0 +1,23 @@
+<!--
+   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.
+-->
+<service role="FOO" name="foo" version="1.0.0">
+    <routes>
+        <route path="/foo/?**">
+            <rewrite apply="FOO/foo/inbound" to="request.url"/>
+        </route>
+    </routes>
+</service>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-service-definitions/src/test/java/org/apache/hadoop/gateway/service/definition/ServiceDefinitionTest.java
----------------------------------------------------------------------
diff --git a/gateway-service-definitions/src/test/java/org/apache/hadoop/gateway/service/definition/ServiceDefinitionTest.java b/gateway-service-definitions/src/test/java/org/apache/hadoop/gateway/service/definition/ServiceDefinitionTest.java
index 62fb23e..5d1a544 100644
--- a/gateway-service-definitions/src/test/java/org/apache/hadoop/gateway/service/definition/ServiceDefinitionTest.java
+++ b/gateway-service-definitions/src/test/java/org/apache/hadoop/gateway/service/definition/ServiceDefinitionTest.java
@@ -24,9 +24,7 @@ import javax.xml.bind.Unmarshaller;
 import java.net.URL;
 import java.util.List;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
+import static org.junit.Assert.*;
 
 public class ServiceDefinitionTest {
 
@@ -34,15 +32,46 @@ public class ServiceDefinitionTest {
   public void testUnmarshalling() throws Exception {
     JAXBContext context = JAXBContext.newInstance(ServiceDefinition.class);
     Unmarshaller unmarshaller = context.createUnmarshaller();
+    URL url = ClassLoader.getSystemResource("services/foo/1.0.0/service.xml");
+    ServiceDefinition definition = (ServiceDefinition) unmarshaller.unmarshal(url.openStream());
+    assertEquals("foo", definition.getName());
+    assertEquals("FOO", definition.getRole());
+    assertEquals("1.0.0", definition.getVersion());
+    assertEquals("custom-client", definition.getDispatch().getContributorName());
+    assertEquals("ha-client", definition.getDispatch().getHaContributorName());
+    List<Policy> policies = definition.getPolicies();
+    assertEquals(5, policies.size());
+    String[] policyOrder = new String[]{"webappsec", "authentication", "rewrite", "identity-assertion", "authorization"};
+    for (int i=0; i< policyOrder.length; i++ ) {
+      assertEquals(policyOrder[i], policies.get(i).getRole());
+    }
+    List<Route> routes = definition.getRoutes();
+    assertNotNull(routes);
+    assertEquals(1, routes.size());
+    Route route = routes.get(0);
+    assertEquals("/foo/?**", route.getPath());
+    assertEquals("http-client", route.getDispatch().getContributorName());
+    policies = route.getPolicies();
+    assertEquals(5, policies.size());
+    policyOrder = new String[]{"webappsec", "federation", "identity-assertion", "authorization", "rewrite"};
+    for (int i=0; i< policyOrder.length; i++ ) {
+      assertEquals(policyOrder[i], policies.get(i).getRole());
+    }
+  }
+
+  @Test
+  public void testUnmarshallingCommonServices() throws Exception {
+    JAXBContext context = JAXBContext.newInstance(ServiceDefinition.class);
+    Unmarshaller unmarshaller = context.createUnmarshaller();
     URL url = ClassLoader.getSystemResource("services/yarn-rm/2.5.0/service.xml");
     ServiceDefinition definition = (ServiceDefinition) unmarshaller.unmarshal(url.openStream());
     assertEquals("resourcemanager", definition.getName());
     assertEquals("RESOURCEMANAGER", definition.getRole());
     assertEquals("2.5.0", definition.getVersion());
-    List<Route> bindings = definition.getRoutes();
-    assertNotNull(bindings);
-    assertEquals(12, bindings.size());
-    assertNotNull(bindings.get(0).getPath());
+    List<Route> routes = definition.getRoutes();
+    assertNotNull(routes);
+    assertEquals(12, routes.size());
+    assertNotNull(routes.get(0).getPath());
     url = ClassLoader.getSystemResource("services/hbase/0.98.0/service.xml");
     definition = (ServiceDefinition) unmarshaller.unmarshal(url.openStream());
     assertNotNull(definition.getDispatch());
@@ -53,4 +82,5 @@ public class ServiceDefinitionTest {
     assertEquals("org.apache.hadoop.gateway.hdfs.dispatch.HdfsDispatch", definition.getDispatch().getClassName());
     assertEquals("org.apache.hadoop.gateway.hdfs.dispatch.WebHdfsHaHttpClientDispatch", definition.getDispatch().getHaClassName());
   }
+
 }

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-service-definitions/src/test/resources/services/foo/1.0.0/rewrite.xml
----------------------------------------------------------------------
diff --git a/gateway-service-definitions/src/test/resources/services/foo/1.0.0/rewrite.xml b/gateway-service-definitions/src/test/resources/services/foo/1.0.0/rewrite.xml
new file mode 100644
index 0000000..761bd4b
--- /dev/null
+++ b/gateway-service-definitions/src/test/resources/services/foo/1.0.0/rewrite.xml
@@ -0,0 +1,21 @@
+<!--
+   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.
+-->
+<rules>
+    <rule dir="IN" name="FOO/foo/inbound" pattern="*://*:*/**/foo">
+        <rewrite template="{$serviceUrl[FOO]}"/>
+    </rule>
+</rules>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-service-definitions/src/test/resources/services/foo/1.0.0/service.xml
----------------------------------------------------------------------
diff --git a/gateway-service-definitions/src/test/resources/services/foo/1.0.0/service.xml b/gateway-service-definitions/src/test/resources/services/foo/1.0.0/service.xml
new file mode 100644
index 0000000..21a10f1
--- /dev/null
+++ b/gateway-service-definitions/src/test/resources/services/foo/1.0.0/service.xml
@@ -0,0 +1,39 @@
+<!--
+   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.
+-->
+<service role="FOO" name="foo" version="1.0.0">
+    <policies>
+        <policy role="webappsec"/>
+        <policy role="authentication"/>
+        <policy role="rewrite"/>
+        <policy role="identity-assertion"/>
+        <policy role="authorization"/>
+    </policies>
+    <routes>
+        <route path="/foo/?**">
+            <rewrite apply="FOO/foo/inbound" to="request.url"/>
+            <policies>
+                <policy role="webappsec"/>
+                <policy role="federation"/>
+                <policy role="identity-assertion"/>
+                <policy role="authorization"/>
+                <policy role="rewrite"/>
+            </policies>
+            <dispatch contributor-name="http-client" />
+        </route>
+    </routes>
+    <dispatch contributor-name="custom-client" ha-contributor-name="ha-client"/>
+</service>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-service-webhdfs/src/main/java/org/apache/hadoop/gateway/hdfs/NameNodeHaDispatchDeploymentContributor.java
----------------------------------------------------------------------
diff --git a/gateway-service-webhdfs/src/main/java/org/apache/hadoop/gateway/hdfs/NameNodeHaDispatchDeploymentContributor.java b/gateway-service-webhdfs/src/main/java/org/apache/hadoop/gateway/hdfs/NameNodeHaDispatchDeploymentContributor.java
deleted file mode 100644
index d43cf1b..0000000
--- a/gateway-service-webhdfs/src/main/java/org/apache/hadoop/gateway/hdfs/NameNodeHaDispatchDeploymentContributor.java
+++ /dev/null
@@ -1,66 +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.hdfs;
-
-import org.apache.hadoop.gateway.deploy.DeploymentContext;
-import org.apache.hadoop.gateway.deploy.ProviderDeploymentContributorBase;
-import org.apache.hadoop.gateway.descriptor.FilterDescriptor;
-import org.apache.hadoop.gateway.descriptor.FilterParamDescriptor;
-import org.apache.hadoop.gateway.descriptor.ResourceDescriptor;
-import org.apache.hadoop.gateway.dispatch.GatewayDispatchFilter;
-import org.apache.hadoop.gateway.hdfs.dispatch.WebHdfsHaDispatchFilter;
-import org.apache.hadoop.gateway.hdfs.dispatch.WebHdfsHaHttpClientDispatch;
-import org.apache.hadoop.gateway.topology.Provider;
-import org.apache.hadoop.gateway.topology.Service;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-public class NameNodeHaDispatchDeploymentContributor extends ProviderDeploymentContributorBase {
-
-   private static final String ROLE = "dispatch";
-
-   private static final String NAME = "ha-hdfs";
-
-   private static final String DISPATCH_IMPL_PARAM = "dispatch-impl";
-
-  @Override
-   public String getRole() {
-      return ROLE;
-   }
-
-   @Override
-   public String getName() {
-      return NAME;
-   }
-
-   @Override
-   public void contributeFilter(DeploymentContext context, Provider provider, Service service, ResourceDescriptor resource, List<FilterParamDescriptor> params) {
-      if (params == null) {
-         params = new ArrayList<FilterParamDescriptor>();
-      }
-//      params.add(resource.createFilterParam().name(WebHdfsHaHttpClientDispatch.RESOURCE_ROLE_ATTRIBUTE).value(resource.role()));
-      Map<String, String> providerParams = provider.getParams();
-      for (Map.Entry<String, String> entry : providerParams.entrySet()) {
-         params.add(resource.createFilterParam().name(entry.getKey().toLowerCase()).value(entry.getValue()));
-      }
-      FilterDescriptor filter = resource.addFilter().name(getName()).role(getRole()).impl(WebHdfsHaDispatchFilter.class).params(params);
-      filter.param().name(DISPATCH_IMPL_PARAM).value(WebHdfsHaHttpClientDispatch.class.getName());
-   }
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-service-webhdfs/src/main/java/org/apache/hadoop/gateway/hdfs/dispatch/WebHdfsHaDispatchFilter.java
----------------------------------------------------------------------
diff --git a/gateway-service-webhdfs/src/main/java/org/apache/hadoop/gateway/hdfs/dispatch/WebHdfsHaDispatchFilter.java b/gateway-service-webhdfs/src/main/java/org/apache/hadoop/gateway/hdfs/dispatch/WebHdfsHaDispatchFilter.java
deleted file mode 100644
index be0fe18..0000000
--- a/gateway-service-webhdfs/src/main/java/org/apache/hadoop/gateway/hdfs/dispatch/WebHdfsHaDispatchFilter.java
+++ /dev/null
@@ -1,36 +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.hdfs.dispatch;
-
-import org.apache.hadoop.gateway.dispatch.GatewayDispatchFilter;
-import org.apache.hadoop.gateway.ha.provider.HaProvider;
-import org.apache.hadoop.gateway.ha.provider.HaServletContextListener;
-
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-
-public class WebHdfsHaDispatchFilter extends GatewayDispatchFilter {
-
-  @Override
-  public void init(FilterConfig filterConfig) throws ServletException {
-    super.init(filterConfig);
-    HaProvider haProvider = HaServletContextListener.getHaProvider(filterConfig.getServletContext());
-    ((WebHdfsHaHttpClientDispatch)getDispatch()).setHaProvider(haProvider);
-    getDispatch().init();
-  }
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-service-webhdfs/src/main/resources/META-INF/services/org.apache.hadoop.gateway.deploy.ProviderDeploymentContributor
----------------------------------------------------------------------
diff --git a/gateway-service-webhdfs/src/main/resources/META-INF/services/org.apache.hadoop.gateway.deploy.ProviderDeploymentContributor b/gateway-service-webhdfs/src/main/resources/META-INF/services/org.apache.hadoop.gateway.deploy.ProviderDeploymentContributor
deleted file mode 100644
index fc4074d..0000000
--- a/gateway-service-webhdfs/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.hdfs.NameNodeHaDispatchDeploymentContributor

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-service-webhdfs/src/test/java/org/apache/hadoop/gateway/hdfs/NameNodeHaDispatchDeploymentContributorTest.java
----------------------------------------------------------------------
diff --git a/gateway-service-webhdfs/src/test/java/org/apache/hadoop/gateway/hdfs/NameNodeHaDispatchDeploymentContributorTest.java b/gateway-service-webhdfs/src/test/java/org/apache/hadoop/gateway/hdfs/NameNodeHaDispatchDeploymentContributorTest.java
deleted file mode 100644
index 596ac81..0000000
--- a/gateway-service-webhdfs/src/test/java/org/apache/hadoop/gateway/hdfs/NameNodeHaDispatchDeploymentContributorTest.java
+++ /dev/null
@@ -1,44 +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.hdfs;
-
-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 NameNodeHaDispatchDeploymentContributorTest {
-
-   @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 NameNodeHaDispatchDeploymentContributor) {
-            return;
-         }
-      }
-      fail( "Failed to find " + NameNodeHaDispatchDeploymentContributor.class.getName() + " via service loader." );
-   }
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-spi/src/main/java/org/apache/hadoop/gateway/config/FilterConfigurationAdapter.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/config/FilterConfigurationAdapter.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/config/FilterConfigurationAdapter.java
index 0bf1e6f..882597c 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/config/FilterConfigurationAdapter.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/config/FilterConfigurationAdapter.java
@@ -17,7 +17,6 @@
  */
 package org.apache.hadoop.gateway.config;
 
-
 import javax.servlet.FilterConfig;
 
 public class FilterConfigurationAdapter implements ConfigurationAdapter {

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-spi/src/main/java/org/apache/hadoop/gateway/deploy/ServiceDeploymentContributor.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/deploy/ServiceDeploymentContributor.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/deploy/ServiceDeploymentContributor.java
index 19bc1d6..4b2b110 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/deploy/ServiceDeploymentContributor.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/deploy/ServiceDeploymentContributor.java
@@ -28,6 +28,11 @@ public interface ServiceDeploymentContributor {
   // The name of this service deployment contributor.  Not used yet.
   String getName();
 
+  /**
+   * Returns the version of the deployment contributor. This helps in providing versioned
+   * contributions for service versions.
+   * @return the version
+   */
   Version getVersion();
 
   // Called after provider initializeContribution methods and in arbitrary order relative to other service contributors.

http://git-wip-us.apache.org/repos/asf/knox/blob/2a78e7cc/gateway-spi/src/test/java/org/apache/hadoop/gateway/topology/VersionTest.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/test/java/org/apache/hadoop/gateway/topology/VersionTest.java b/gateway-spi/src/test/java/org/apache/hadoop/gateway/topology/VersionTest.java
new file mode 100644
index 0000000..a01b804
--- /dev/null
+++ b/gateway-spi/src/test/java/org/apache/hadoop/gateway/topology/VersionTest.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
+ *
+ *     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.topology;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class VersionTest {
+
+  @Test
+  public void testDefaultVersion() {
+    Version version = new Version();
+    assertEquals(0, version.getMajor());
+    assertEquals(0, version.getMinor());
+    assertEquals(0, version.getPatch());
+    assertEquals("0.0.0", version.toString());
+  }
+
+  @Test
+  public void testVersion() {
+    Version version = new Version("1.2.3");
+    assertEquals(1, version.getMajor());
+    assertEquals(2, version.getMinor());
+    assertEquals(3, version.getPatch());
+    assertEquals("1.2.3", version.toString());
+    version = new Version(4, 5, 6);
+    assertEquals(4, version.getMajor());
+    assertEquals(5, version.getMinor());
+    assertEquals(6, version.getPatch());
+    assertEquals("4.5.6", version.toString());
+    Version other = new Version("4.5.6");
+    assertTrue(version.equals(other));
+  }
+}