http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-service-yarn-rm/src/main/resources/org/apache/hadoop/gateway/yarn/rm/ResourceManagerDeploymentContributor/rewrite.xml
----------------------------------------------------------------------
diff --git 
a/gateway-service-yarn-rm/src/main/resources/org/apache/hadoop/gateway/yarn/rm/ResourceManagerDeploymentContributor/rewrite.xml
 
b/gateway-service-yarn-rm/src/main/resources/org/apache/hadoop/gateway/yarn/rm/ResourceManagerDeploymentContributor/rewrite.xml
deleted file mode 100644
index 95ce2a3..0000000
--- 
a/gateway-service-yarn-rm/src/main/resources/org/apache/hadoop/gateway/yarn/rm/ResourceManagerDeploymentContributor/rewrite.xml
+++ /dev/null
@@ -1,193 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<!--
-   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="RESOURCEMANAGER/resourcemanager/inbound/root" 
pattern="*://*:*/**/resourcemanager/v1/?{**}">
-        <rewrite template="{$serviceUrl[RESOURCEMANAGER]}/v1/?{**}"/>
-    </rule>
-
-    <rule dir="IN" name="RESOURCEMANAGER/resourcemanager/inbound/path" 
pattern="*://*:*/**/resourcemanager/v1/{path=**}?{**}">
-        <rewrite template="{$serviceUrl[RESOURCEMANAGER]}/v1/{path=**}/?{**}"/>
-    </rule>
-
-    <rule dir="IN" name="RESOURCEMANAGER/resourcemanager/inbound/proxy" 
pattern="*://*:*/**/resourcemanager/proxy/{appid=*}/ws/v1/{path=**}?{**}">
-        <decrypt-query/>
-        <match 
pattern="*://*:*/**/resourcemanager/proxy/{appid=*}/ws/v1/{path=**}?{scheme}?{host}?{port}?{**}"/>
-        <rewrite 
template="{scheme}://{host}:{port}/proxy/{appid=*}/ws/v1/{path=**}?{**}"/>
-    </rule>
-
-    <rule dir="OUT" name="RESOURCEMANAGER/resourcemanager/url/outbound">
-        <match pattern="*://*:*/**?**"/>
-               <rewrite template=""/>
-    </rule>
-    <rule dir="OUT" 
name="RESOURCEMANAGER/resourcemanager/trackingUrlHistory/outbound">
-        <match 
pattern="{scheme}://{host}:{port}/proxy/{appid=*}/jobhistory/job/**"/>
-               <rewrite template=""/>
-    </rule>
-    <rule dir="OUT" 
name="RESOURCEMANAGER/resourcemanager/trackingUrlAM/outbound">
-        <match pattern="{scheme}://{host}:{port}/proxy/{appid=*}"/>
-               <rewrite 
template="{$frontend[url]}/resourcemanager/proxy/{appid=*}?{scheme}?host={$hostmap(host)}?{port}?{**}"/>
-               <encrypt-query/>
-    </rule>
-    <rule dir="OUT" name="RESOURCEMANAGER/resourcemanager/hostport/outbound">
-        <match pattern="*:*"/>
-               <rewrite template=""/>
-    </rule>
-    <rule dir="OUT" name="RESOURCEMANAGER/resourcemanager/logsLink/outbound">
-        <match pattern="//*:*/**?**"/>
-               <rewrite template=""/>
-    </rule>
-    <rule dir="OUT" name="RESOURCEMANAGER/resourcemanager/host/outbound">
-               <rewrite template=""/>
-    </rule>
-    <rule dir="OUT" name="RESOURCEMANAGER/resourcemanager/nodeId/outbound">
-        <match pattern="{host=*}:{port=*}"/>
-        <encrypt template="{host}:{port}" param="encaddr"/>
-        <rewrite template="{encaddr}"/>
-    </rule>
-    <rule dir="IN" name="RESOURCEMANAGER/resourcemanager/nodeId/inbound">
-        <match 
pattern="*://*:*/**/resourcemanager/v1/cluster/nodes/{addr=*}?{**}"/>
-        <decrypt param="addr"/>
-        <rewrite 
template="{$serviceUrl[RESOURCEMANAGER]}/v1/cluster/nodes/{addr}?{**}"/>
-    </rule>
-
-    <filter name="RESOURCEMANAGER/resourcemanager/apps/outbound">
-        <content type="*/json">
-               <buffer path="$.apps.app[*]">
-                       <detect path="$.trackingUI" value="History">
-                                       <apply path="$.trackingUrl" 
rule="RESOURCEMANAGER/resourcemanager/url/outbound"/>
-                               </detect>
-                               <detect path="$.trackingUI" 
value="ApplicationMaster">
-                                       <apply path="$.trackingUrl" 
rule="RESOURCEMANAGER/resourcemanager/trackingUrlAM/outbound"/>
-                               </detect>
-                               <apply path="$.amContainerLogs" 
rule="RESOURCEMANAGER/resourcemanager/url/outbound"/>
-               <apply path="$.amHostHttpAddress" 
rule="RESOURCEMANAGER/resourcemanager/hostport/outbound"/>
-               </buffer>
-        </content>
-        <content type="*/xml">
-               <buffer path="/apps/app">
-                       <detect path="trackingUI" value="History">
-                                       <apply path="trackingUrl" 
rule="RESOURCEMANAGER/resourcemanager/url/outbound"/>
-                               </detect>
-                               <detect path="trackingUI" 
value="ApplicationMaster">
-                                       <apply path="trackingUrl" 
rule="RESOURCEMANAGER/resourcemanager/trackingUrlAM/outbound"/>
-                               </detect>
-                               <apply path="amContainerLogs" 
rule="RESOURCEMANAGER/resourcemanager/url/outbound"/>
-               <apply path="amHostHttpAddress" 
rule="RESOURCEMANAGER/resourcemanager/hostport/outbound"/>
-               </buffer>
-        </content>
-    </filter>
-
-    <filter name="RESOURCEMANAGER/resourcemanager/app/outbound">
-        <content type="*/json">
-               <buffer path="$.app">
-                       <detect path="$.trackingUI" value="History">
-                               <apply path="$.trackingUrl" 
rule="RESOURCEMANAGER/resourcemanager/url/outbound"/>
-                       </detect>
-                       <detect path="$.trackingUI" value="ApplicationMaster">
-                               <apply path="$.trackingUrl" 
rule="RESOURCEMANAGER/resourcemanager/trackingUrlAM/outbound"/>
-                       </detect>
-                   <apply path="$.amContainerLogs" 
rule="RESOURCEMANAGER/resourcemanager/url/outbound"/>
-                   <apply path="$.amHostHttpAddress" 
rule="RESOURCEMANAGER/resourcemanager/hostport/outbound"/>
-            </buffer>
-        </content>
-        <content type="*/xml">
-               <buffer path="/app">
-                       <detect path="trackingUI" value="History">
-                               <apply path="trackingUrl" 
rule="RESOURCEMANAGER/resourcemanager/url/outbound"/>
-                       </detect>
-                       <detect path="trackingUI" value="ApplicationMaster">
-                               <apply path="trackingUrl" 
rule="RESOURCEMANAGER/resourcemanager/trackingUrlAM/outbound"/>
-                       </detect>
-                   <apply path="amContainerLogs" 
rule="RESOURCEMANAGER/resourcemanager/url/outbound"/>
-                   <apply path="amHostHttpAddress" 
rule="RESOURCEMANAGER/resourcemanager/hostport/outbound"/>
-            </buffer>
-        </content>
-    </filter>
-
-    <filter name="RESOURCEMANAGER/resourcemanager/appattempts/outbound">
-        <content type="*/json">
-            <apply path="$.appAttempts.appAttempt[*].nodeHttpAddress" 
rule="RESOURCEMANAGER/resourcemanager/hostport/outbound"/>
-            <apply path="$.appAttempts.appAttempt[*].logsLink" 
rule="RESOURCEMANAGER/resourcemanager/logsLink/outbound"/>
-            <apply path="$.appAttempts.appAttempt[*].nodeId" 
rule="RESOURCEMANAGER/resourcemanager/nodeId/outbound"/>
-        </content>
-        <content type="*/xml">
-            <apply path="/appAttempts/appAttempt/nodeHttpAddress" 
rule="RESOURCEMANAGER/resourcemanager/hostport/outbound"/>
-            <apply path="/appAttempts/appAttempt/logsLink" 
rule="RESOURCEMANAGER/resourcemanager/logsLink/outbound"/>
-            <apply path="/appAttempts/appAttempt/nodeId" 
rule="RESOURCEMANAGER/resourcemanager/nodeId/outbound"/>
-        </content>
-    </filter>
-
-    <filter name="RESOURCEMANAGER/resourcemanager/nodes/outbound">
-        <content type="*/json">
-            <apply path="$.nodes.node[*].nodeHTTPAddress" 
rule="RESOURCEMANAGER/resourcemanager/hostport/outbound"/>
-            <apply path="$.nodes.node[*].nodeHostName" 
rule="RESOURCEMANAGER/resourcemanager/host/outbound"/>
-            <apply path="$.nodes.node[*].id" 
rule="RESOURCEMANAGER/resourcemanager/nodeId/outbound"/>
-        </content>
-        <content type="*/xml">
-            <apply path="/nodes/node/nodeHTTPAddress" 
rule="RESOURCEMANAGER/resourcemanager/hostport/outbound"/>
-            <apply path="/nodes/node/nodeHostName" 
rule="RESOURCEMANAGER/resourcemanager/host/outbound"/>
-            <apply path="/nodes/node/id" 
rule="RESOURCEMANAGER/resourcemanager/nodeId/outbound"/>
-        </content>
-    </filter>
-
-    <filter name="RESOURCEMANAGER/resourcemanager/node/outbound">
-        <content type="*/json">
-            <apply path="$.node.nodeHTTPAddress" 
rule="RESOURCEMANAGER/resourcemanager/hostport/outbound"/>
-            <apply path="$.node.nodeHostName" 
rule="RESOURCEMANAGER/resourcemanager/host/outbound"/>
-            <apply path="$.node.id" 
rule="RESOURCEMANAGER/resourcemanager/nodeId/outbound"/>
-        </content>
-        <content type="*/xml">
-            <apply path="/node/nodeHTTPAddress" 
rule="RESOURCEMANAGER/resourcemanager/hostport/outbound"/>
-            <apply path="/node/nodeHostName" 
rule="RESOURCEMANAGER/resourcemanager/host/outbound"/>
-            <apply path="/node/id" 
rule="RESOURCEMANAGER/resourcemanager/nodeId/outbound"/>
-        </content>
-    </filter>
-
-    <filter name="RESOURCEMANAGER/resourcemanager/proxy/jobattempts/outbound">
-        <content type="*/json">
-            <apply path="$.jobAttempts.jobAttempt[*].nodeHttpAddress" 
rule="RESOURCEMANAGER/resourcemanager/hostport/outbound"/>
-            <apply path="$.jobAttempts.jobAttempt[*].nodeId" 
rule="RESOURCEMANAGER/resourcemanager/nodeId/outbound"/>
-            <apply path="$.jobAttempts.jobAttempt[*].logsLink" 
rule="RESOURCEMANAGER/resourcemanager/url/outbound"/>
-        </content>
-        <content type="*/xml">
-            <apply path="/jobAttempts/jobAttempt/nodeHttpAddress" 
rule="RESOURCEMANAGER/resourcemanager/hostport/outbound"/>
-            <apply path="/jobAttempts/jobAttempt/nodeId" 
rule="RESOURCEMANAGER/resourcemanager/nodeId/outbound"/>
-            <apply path="/jobAttempts/jobAttempt/logsLink" 
rule="RESOURCEMANAGER/resourcemanager/url/outbound"/>
-        </content>
-    </filter>
-
-    <filter name="RESOURCEMANAGER/resourcemanager/proxy/taskattempts/outbound">
-        <content type="*/json">
-            <apply path="$.taskAttempts.taskAttempt[*].nodeHttpAddress" 
rule="RESOURCEMANAGER/resourcemanager/hostport/outbound"/>
-        </content>
-        <content type="*/xml">
-            <apply path="/taskAttempts/taskAttempt/nodeHttpAddress" 
rule="RESOURCEMANAGER/resourcemanager/hostport/outbound"/>
-        </content>
-    </filter>
-
-    <filter name="RESOURCEMANAGER/resourcemanager/proxy/taskattempt/outbound">
-        <content type="*/json">
-            <apply path="$.taskAttempt.nodeHttpAddress" 
rule="RESOURCEMANAGER/resourcemanager/hostport/outbound"/>
-        </content>
-        <content type="*/xml">
-            <apply path="/taskAttempt/nodeHttpAddress" 
rule="RESOURCEMANAGER/resourcemanager/hostport/outbound"/>
-        </content>
-    </filter>
-
-</rules>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-service-yarn-rm/src/test/java/org/apache/hadoop/gateway/yarn/rm/ResourceManagerDeploymentContributorTest.java
----------------------------------------------------------------------
diff --git 
a/gateway-service-yarn-rm/src/test/java/org/apache/hadoop/gateway/yarn/rm/ResourceManagerDeploymentContributorTest.java
 
b/gateway-service-yarn-rm/src/test/java/org/apache/hadoop/gateway/yarn/rm/ResourceManagerDeploymentContributorTest.java
deleted file mode 100644
index 485e1f2..0000000
--- 
a/gateway-service-yarn-rm/src/test/java/org/apache/hadoop/gateway/yarn/rm/ResourceManagerDeploymentContributorTest.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.yarn.rm;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.fail;
-
-import java.util.Iterator;
-import java.util.ServiceLoader;
-
-import org.apache.hadoop.gateway.deploy.ServiceDeploymentContributor;
-import org.junit.Test;
-
-public class ResourceManagerDeploymentContributorTest {
-
-  @SuppressWarnings("rawtypes")
-  @Test
-  public void testServiceLoader() throws Exception {
-    ServiceLoader loader = ServiceLoader.load( 
ServiceDeploymentContributor.class );
-    Iterator iterator = loader.iterator();
-    assertThat( "Service iterator empty.", iterator.hasNext() );
-    while( iterator.hasNext() ) {
-      Object object = iterator.next();
-      if( object instanceof ResourceManagerDeploymentContributor ) {
-        return;
-      }
-    }
-    fail( "Failed to find " + 
ResourceManagerDeploymentContributor.class.getName() + " via service loader." );
-  }
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-spi/pom.xml
----------------------------------------------------------------------
diff --git a/gateway-spi/pom.xml b/gateway-spi/pom.xml
index 506f4a0..11ddda7 100644
--- a/gateway-spi/pom.xml
+++ b/gateway-spi/pom.xml
@@ -48,6 +48,10 @@
         </dependency>
         <dependency>
             <groupId>${gateway-group}</groupId>
+            <artifactId>gateway-util-configinjector</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${gateway-group}</groupId>
             <artifactId>gateway-util-urltemplate</artifactId>
         </dependency>
 
@@ -91,7 +95,11 @@
             <groupId>com.jayway.jsonpath</groupId>
             <artifactId>json-path</artifactId>
         </dependency>
-        
+        <dependency>
+            <groupId>commons-collections</groupId>
+            <artifactId>commons-collections</artifactId>
+        </dependency>
+
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/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
new file mode 100644
index 0000000..882597c
--- /dev/null
+++ 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/config/FilterConfigurationAdapter.java
@@ -0,0 +1,38 @@
+/**
+ * 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.config;
+
+import javax.servlet.FilterConfig;
+
+public class FilterConfigurationAdapter implements ConfigurationAdapter {
+
+  private FilterConfig config;
+
+  public FilterConfigurationAdapter(FilterConfig config) {
+    this.config = config;
+  }
+
+  @Override
+  public Object getConfigurationValue(String name) throws 
ConfigurationException {
+    Object value = config.getInitParameter(name);
+    if (value == null) {
+      value = config.getServletContext().getAttribute(name);
+    }
+    return value;
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-spi/src/main/java/org/apache/hadoop/gateway/config/FilterConfigurationAdapterDescriptor.java
----------------------------------------------------------------------
diff --git 
a/gateway-spi/src/main/java/org/apache/hadoop/gateway/config/FilterConfigurationAdapterDescriptor.java
 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/config/FilterConfigurationAdapterDescriptor.java
new file mode 100644
index 0000000..4d106e1
--- /dev/null
+++ 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/config/FilterConfigurationAdapterDescriptor.java
@@ -0,0 +1,29 @@
+/**
+ * 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.config;
+
+import 
org.apache.hadoop.gateway.config.spi.AbstractConfigurationAdapterDescriptor;
+
+import javax.servlet.FilterConfig;
+
+public class FilterConfigurationAdapterDescriptor extends 
AbstractConfigurationAdapterDescriptor {
+
+  public FilterConfigurationAdapterDescriptor() {
+    add(FilterConfig.class, FilterConfigurationAdapter.class);
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-spi/src/main/java/org/apache/hadoop/gateway/config/GatewayConfig.java
----------------------------------------------------------------------
diff --git 
a/gateway-spi/src/main/java/org/apache/hadoop/gateway/config/GatewayConfig.java 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/config/GatewayConfig.java
index a8ddc83..0c3351d 100644
--- 
a/gateway-spi/src/main/java/org/apache/hadoop/gateway/config/GatewayConfig.java
+++ 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/config/GatewayConfig.java
@@ -52,6 +52,12 @@ public interface GatewayConfig {
    */
   String getGatewayDataDir();
 
+  /**
+   * The location of the gateway stack definitions
+   * @return The location of the gateway stacks top level directory.
+   */
+  String getGatewayStacksDir();
+
   String getHadoopConfDir();
 
   String getGatewayHost();

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/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 ba21928..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
@@ -18,6 +18,7 @@
 package org.apache.hadoop.gateway.deploy;
 
 import org.apache.hadoop.gateway.topology.Service;
+import org.apache.hadoop.gateway.topology.Version;
 
 public interface ServiceDeploymentContributor {
 
@@ -27,6 +28,13 @@ 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.
   void initializeContribution( DeploymentContext context );
 

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-spi/src/main/java/org/apache/hadoop/gateway/deploy/ServiceDeploymentContributorBase.java
----------------------------------------------------------------------
diff --git 
a/gateway-spi/src/main/java/org/apache/hadoop/gateway/deploy/ServiceDeploymentContributorBase.java
 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/deploy/ServiceDeploymentContributorBase.java
index 4d33fa8..f82bad5 100644
--- 
a/gateway-spi/src/main/java/org/apache/hadoop/gateway/deploy/ServiceDeploymentContributorBase.java
+++ 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/deploy/ServiceDeploymentContributorBase.java
@@ -21,6 +21,7 @@ import 
org.apache.hadoop.gateway.descriptor.FilterParamDescriptor;
 import org.apache.hadoop.gateway.descriptor.ResourceDescriptor;
 import org.apache.hadoop.gateway.topology.Provider;
 import org.apache.hadoop.gateway.topology.Service;
+import org.apache.hadoop.gateway.topology.Version;
 
 import java.net.URISyntaxException;
 import java.util.Collection;
@@ -28,6 +29,11 @@ import java.util.List;
 
 public abstract class ServiceDeploymentContributorBase extends 
DeploymentContributorBase implements ServiceDeploymentContributor {
 
+  @Override
+  public Version getVersion() {
+    return new Version();
+  }
+
   public void initializeContribution( DeploymentContext context ) {
     // Noop.
   }

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/AbstractGatewayDispatch.java
----------------------------------------------------------------------
diff --git 
a/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/AbstractGatewayDispatch.java
 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/AbstractGatewayDispatch.java
index 1bf5fc0..177ef8d 100644
--- 
a/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/AbstractGatewayDispatch.java
+++ 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/AbstractGatewayDispatch.java
@@ -20,6 +20,7 @@ package org.apache.hadoop.gateway.dispatch;
 import org.apache.hadoop.gateway.filter.AbstractGatewayFilter;
 import org.apache.hadoop.gateway.filter.GatewayResponse;
 import org.apache.hadoop.io.IOUtils;
+import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpUriRequest;
 
 import javax.servlet.FilterChain;
@@ -38,48 +39,12 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-public abstract class AbstractGatewayDispatch extends AbstractGatewayFilter 
implements Dispatch {
+public abstract class AbstractGatewayDispatch implements Dispatch {
 
-  private static Map<String,Adapter> METHOD_ADAPTERS = createMethodAdapters();
   private static int STREAM_COPY_BUFFER_SIZE = 4096;
   private static final List<String> EXCLUDE_HEADERS = Arrays.asList( "Host", 
"Authorization", "Content-Length", "Transfer-Encoding" );
 
-  private static Map<String,Adapter> createMethodAdapters() {
-    Map<String,Adapter> map = new HashMap<String,Adapter>();
-    map.put( "GET", new GetAdapter() );
-    map.put( "POST", new PostAdapter() );
-    map.put( "PUT", new PutAdapter() );
-    map.put( "DELETE", new DeleteAdapter() );
-    map.put( "OPTIONS", new OptionsAdapter() );
-    return Collections.unmodifiableMap( map );
-  }
-
-  @Override
-  protected void doFilter( HttpServletRequest request, HttpServletResponse 
response, FilterChain chain )
-      throws IOException, ServletException {
-    String method = request.getMethod().toUpperCase();
-    Adapter adapter = METHOD_ADAPTERS.get( method );
-    if( adapter != null ) {
-      try {
-        adapter.doMethod( this, request, response );
-      } catch( URISyntaxException e ) {
-        throw new ServletException( e );
-      }
-    } else {
-      response.sendError( HttpServletResponse.SC_METHOD_NOT_ALLOWED );
-    }
-  }
-
-  protected static URI getDispatchUrl( HttpServletRequest request ) {
-    StringBuffer str = request.getRequestURL();
-    String query = request.getQueryString();
-    if( query != null ) {
-      str.append( '?' );
-      str.append( query );
-    }
-    URI url = URI.create( str.toString() );
-    return url;
-  }
+  protected  HttpClient client;
 
   protected void writeResponse( HttpServletRequest request, 
HttpServletResponse response, InputStream stream )
       throws IOException {
@@ -98,6 +63,16 @@ public abstract class AbstractGatewayDispatch extends 
AbstractGatewayFilter impl
 //    }
   }
 
+  @Override
+  public HttpClient getHttpClient() {
+    return client;
+  }
+
+  @Override
+  public void setHttpClient(HttpClient client) {
+    this.client = client;
+  }
+
   public void doGet( URI url, HttpServletRequest request, HttpServletResponse 
response )
       throws IOException, URISyntaxException {
     response.sendError( HttpServletResponse.SC_METHOD_NOT_ALLOWED );
@@ -122,46 +97,6 @@ public abstract class AbstractGatewayDispatch extends 
AbstractGatewayFilter impl
       throws IOException, URISyntaxException {
     response.sendError( HttpServletResponse.SC_METHOD_NOT_ALLOWED );
   }
-
-  private interface Adapter {
-    public void doMethod( Dispatch dispatch, HttpServletRequest request, 
HttpServletResponse response )
-        throws IOException, ServletException, URISyntaxException;
-  }
-
-  private static class GetAdapter implements Adapter {
-    public void doMethod( Dispatch dispatch, HttpServletRequest request, 
HttpServletResponse response )
-        throws IOException, ServletException, URISyntaxException {
-      dispatch.doGet( getDispatchUrl( request ), request, response );
-    }
-  }
-
-  private static class PostAdapter implements Adapter {
-    public void doMethod( Dispatch dispatch, HttpServletRequest request, 
HttpServletResponse response )
-        throws IOException, ServletException, URISyntaxException {
-      dispatch.doPost( getDispatchUrl( request ), request, response );
-    }
-  }
-
-  private static class PutAdapter implements Adapter {
-    public void doMethod( Dispatch dispatch, HttpServletRequest request, 
HttpServletResponse response )
-        throws IOException, ServletException, URISyntaxException {
-      dispatch.doPut( getDispatchUrl( request ), request, response );
-    }
-  }
-
-  private static class DeleteAdapter implements Adapter {
-    public void doMethod( Dispatch dispatch, HttpServletRequest request, 
HttpServletResponse response )
-        throws IOException, ServletException, URISyntaxException {
-      dispatch.doDelete( getDispatchUrl( request ), request, response );
-    }
-  }
-
-  private static class OptionsAdapter implements Adapter {
-    public void doMethod( Dispatch dispatch, HttpServletRequest request, 
HttpServletResponse response )
-        throws IOException, ServletException, URISyntaxException {
-      dispatch.doOptions( getDispatchUrl( request ), request, response );
-    }
-  }
   
   public static void copyRequestHeaderFields(HttpUriRequest outboundRequest,
       HttpServletRequest inboundRequest) {

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/Dispatch.java
----------------------------------------------------------------------
diff --git 
a/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/Dispatch.java 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/Dispatch.java
index 072a2c6..0ce1339 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/Dispatch.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/Dispatch.java
@@ -17,6 +17,8 @@
  */
 package org.apache.hadoop.gateway.dispatch;
 
+import org.apache.http.client.HttpClient;
+
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -26,6 +28,14 @@ import java.net.URISyntaxException;
 
 public interface Dispatch {
 
+  void init();
+
+  void destroy();
+
+  HttpClient getHttpClient();
+
+  void setHttpClient(HttpClient httpClient);
+
   void doGet( URI url, HttpServletRequest request, HttpServletResponse 
response )
       throws IOException, ServletException, URISyntaxException;
 

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/GatewayDispatchFilter.java
----------------------------------------------------------------------
diff --git 
a/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/GatewayDispatchFilter.java
 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/GatewayDispatchFilter.java
new file mode 100644
index 0000000..f359568
--- /dev/null
+++ 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/GatewayDispatchFilter.java
@@ -0,0 +1,152 @@
+/**
+ * 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.dispatch;
+
+import org.apache.hadoop.gateway.filter.AbstractGatewayFilter;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static 
org.apache.hadoop.gateway.config.ConfigurationInjectorBuilder.configuration;
+
+public class GatewayDispatchFilter extends AbstractGatewayFilter {
+
+  private static Map<String, Adapter> METHOD_ADAPTERS = createMethodAdapters();
+
+  private Dispatch dispatch;
+
+  private static Map<String, Adapter> createMethodAdapters() {
+    Map<String, Adapter> map = new HashMap<String, Adapter>();
+    map.put("GET", new GetAdapter());
+    map.put("POST", new PostAdapter());
+    map.put("PUT", new PutAdapter());
+    map.put("DELETE", new DeleteAdapter());
+    map.put("OPTIONS", new OptionsAdapter());
+    return Collections.unmodifiableMap(map);
+  }
+
+  @Override
+  public void init(FilterConfig filterConfig) throws ServletException {
+    super.init(filterConfig);
+    String dispatchImpl = filterConfig.getInitParameter("dispatch-impl");
+    dispatch = newDispatch(dispatchImpl);
+    configuration().target(dispatch).source(filterConfig).inject();
+    CloseableHttpClient client = HttpClients.createSystem();
+    //[sumit] this can perhaps be stashed in the servlet context to increase 
sharing of the client
+    dispatch.setHttpClient(client);
+    dispatch.init();
+  }
+
+  public Dispatch getDispatch() {
+    return dispatch;
+  }
+
+  public void setDispatch(Dispatch dispatch) {
+    this.dispatch = dispatch;
+  }
+
+  @Override
+  protected void doFilter(HttpServletRequest request, HttpServletResponse 
response, FilterChain chain) throws IOException, ServletException {
+    String method = request.getMethod().toUpperCase();
+    Adapter adapter = METHOD_ADAPTERS.get(method);
+    if ( adapter != null ) {
+      try {
+        adapter.doMethod(dispatch, request, response);
+      } catch ( URISyntaxException e ) {
+        throw new ServletException(e);
+      }
+    } else {
+      response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
+    }
+  }
+
+  protected static URI getDispatchUrl(HttpServletRequest request) {
+    StringBuffer str = request.getRequestURL();
+    String query = request.getQueryString();
+    if ( query != null ) {
+      str.append('?');
+      str.append(query);
+    }
+    URI url = URI.create(str.toString());
+    return url;
+  }
+
+  private interface Adapter {
+    public void doMethod(Dispatch dispatch, HttpServletRequest request, 
HttpServletResponse response)
+        throws IOException, ServletException, URISyntaxException;
+  }
+
+  private static class GetAdapter implements Adapter {
+    public void doMethod(Dispatch dispatch, HttpServletRequest request, 
HttpServletResponse response)
+        throws IOException, ServletException, URISyntaxException {
+      dispatch.doGet(getDispatchUrl(request), request, response);
+    }
+  }
+
+  private static class PostAdapter implements Adapter {
+    public void doMethod(Dispatch dispatch, HttpServletRequest request, 
HttpServletResponse response)
+        throws IOException, ServletException, URISyntaxException {
+      dispatch.doPost(getDispatchUrl(request), request, response);
+    }
+  }
+
+  private static class PutAdapter implements Adapter {
+    public void doMethod(Dispatch dispatch, HttpServletRequest request, 
HttpServletResponse response)
+        throws IOException, ServletException, URISyntaxException {
+      dispatch.doPut(getDispatchUrl(request), request, response);
+    }
+  }
+
+  private static class DeleteAdapter implements Adapter {
+    public void doMethod(Dispatch dispatch, HttpServletRequest request, 
HttpServletResponse response)
+        throws IOException, ServletException, URISyntaxException {
+      dispatch.doDelete(getDispatchUrl(request), request, response);
+    }
+  }
+
+  private static class OptionsAdapter implements Adapter {
+    public void doMethod(Dispatch dispatch, HttpServletRequest request, 
HttpServletResponse response)
+        throws IOException, ServletException, URISyntaxException {
+      dispatch.doOptions(getDispatchUrl(request), request, response);
+    }
+  }
+
+  private Dispatch newDispatch(String dispatchImpl) throws ServletException {
+    try {
+      ClassLoader loader = Thread.currentThread().getContextClassLoader();
+      if ( loader == null ) {
+        loader = this.getClass().getClassLoader();
+      }
+      Class<Dispatch> clazz = (Class) loader.loadClass(dispatchImpl);
+      return clazz.newInstance();
+    } catch ( Exception e ) {
+      throw new ServletException(e);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatch.java
----------------------------------------------------------------------
diff --git 
a/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatch.java
 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatch.java
index 4de9730..e5810d4 100644
--- 
a/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatch.java
+++ 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatch.java
@@ -35,6 +35,8 @@ import 
org.apache.hadoop.gateway.audit.api.AuditServiceFactory;
 import org.apache.hadoop.gateway.audit.api.Auditor;
 import org.apache.hadoop.gateway.audit.api.ResourceType;
 import org.apache.hadoop.gateway.audit.log4j.audit.AuditConstants;
+import org.apache.hadoop.gateway.config.Configure;
+import org.apache.hadoop.gateway.config.Default;
 import org.apache.hadoop.gateway.config.GatewayConfig;
 import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
 import org.apache.hadoop.gateway.i18n.resources.ResourcesFactory;
@@ -43,6 +45,7 @@ import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpStatus;
 import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpDelete;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpOptions;
@@ -59,43 +62,39 @@ import org.apache.http.message.BasicHeader;
  */
 public class HttpClientDispatch extends AbstractGatewayDispatch {
 
-   private static final String REPLAY_BUFFER_SIZE = "replayBufferSize";
+  // private static final String CT_APP_WWW_FORM_URL_ENCODED = 
"application/x-www-form-urlencoded";
+  // private static final String CT_APP_XML = "application/xml";
+  protected static final String Q_DELEGATION_EQ = "?delegation=";
+  protected static final String AMP_DELEGATION_EQ = "&delegation=";
+  protected static final String COOKIE = "Cookie";
+  protected static final String SET_COOKIE = "Set-Cookie";
+  protected static final String WWW_AUTHENTICATE = "WWW-Authenticate";
+  protected static final String NEGOTIATE = "Negotiate";
 
-   // private static final String CT_APP_WWW_FORM_URL_ENCODED = 
"application/x-www-form-urlencoded";
-   // private static final String CT_APP_XML = "application/xml";
-   protected static final String Q_DELEGATION_EQ = "?delegation=";
-   protected static final String AMP_DELEGATION_EQ = "&delegation=";
-   protected static final String COOKIE = "Cookie";
-   protected static final String SET_COOKIE = "Set-Cookie";
-   protected static final String WWW_AUTHENTICATE = "WWW-Authenticate";
-   protected static final String NEGOTIATE = "Negotiate";
+  protected static SpiGatewayMessages LOG = 
MessagesFactory.get(SpiGatewayMessages.class);
+  protected static SpiGatewayResources RES = 
ResourcesFactory.get(SpiGatewayResources.class);
+  protected static Auditor auditor = 
AuditServiceFactory.getAuditService().getAuditor(AuditConstants.DEFAULT_AUDITOR_NAME,
+      AuditConstants.KNOX_SERVICE_NAME, AuditConstants.KNOX_COMPONENT_NAME);
 
-   protected static SpiGatewayMessages LOG = 
MessagesFactory.get(SpiGatewayMessages.class);
-   protected static SpiGatewayResources RES = 
ResourcesFactory.get(SpiGatewayResources.class);
-   protected static Auditor auditor = 
AuditServiceFactory.getAuditService().getAuditor(AuditConstants.DEFAULT_AUDITOR_NAME,
-         AuditConstants.KNOX_SERVICE_NAME, AuditConstants.KNOX_COMPONENT_NAME);
+  protected AppCookieManager appCookieManager;
 
-   protected AppCookieManager appCookieManager;
+  private int replayBufferSize = 0;
 
-   protected static final String REPLAY_BUFFER_SIZE_PARAM = "replayBufferSize";
+  @Override
+  public void init() {
+    setAppCookieManager(new AppCookieManager());
+  }
 
-   private int replayBufferSize = 0;
+  @Override
+  public void destroy() {
 
-   @Override
-   public void init(FilterConfig filterConfig) throws ServletException {
-      this.init(filterConfig, new AppCookieManager());
-   }
+  }
 
-   protected void init(FilterConfig filterConfig, AppCookieManager 
cookieManager) throws ServletException {
-      super.init(filterConfig);
-      appCookieManager = cookieManager;
-      String replayBufferSizeString = 
filterConfig.getInitParameter(REPLAY_BUFFER_SIZE_PARAM);
-      if (replayBufferSizeString != null) {
-         setReplayBufferSize(Integer.valueOf(replayBufferSizeString));
-      }
-   }
+  public void setAppCookieManager(AppCookieManager appCookieManager) {
+    this.appCookieManager = appCookieManager;
+  }
 
-   protected void executeRequest(
+  protected void executeRequest(
          HttpUriRequest outboundRequest,
          HttpServletRequest inboundRequest,
          HttpServletResponse outboundResponse)
@@ -107,7 +106,6 @@ public class HttpClientDispatch extends 
AbstractGatewayDispatch {
    protected HttpResponse executeOutboundRequest(HttpUriRequest 
outboundRequest) throws IOException {
       LOG.dispatchRequest(outboundRequest.getMethod(), 
outboundRequest.getURI());
       HttpResponse inboundResponse = null;
-      DefaultHttpClient client = new DefaultHttpClient();
 
       try {
          String query = outboundRequest.getURI().getQuery();
@@ -190,7 +188,7 @@ public class HttpClientDispatch extends 
AbstractGatewayDispatch {
    }
 
    protected HttpResponse executeKerberosDispatch(HttpUriRequest 
outboundRequest,
-                                                  DefaultHttpClient client) 
throws IOException, ClientProtocolException {
+                                                  HttpClient client) throws 
IOException, ClientProtocolException {
       HttpResponse inboundResponse;
       outboundRequest.removeHeaders(COOKIE);
       String appCookie = appCookieManager.getCachedAppCookie();
@@ -302,7 +300,8 @@ public class HttpClientDispatch extends 
AbstractGatewayDispatch {
       return replayBufferSize;
    }
 
-   protected void setReplayBufferSize(int size) {
+   @Configure
+   protected void setReplayBufferSize(@Default("8") int size) {
       replayBufferSize = size;
    }
 

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/Service.java
----------------------------------------------------------------------
diff --git 
a/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/Service.java 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/Service.java
index 9763174..41270a9 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/Service.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/Service.java
@@ -27,6 +27,7 @@ public class Service {
 
   private String role;
   private String name;
+  private Version version;
   private Map<String, String> params = new LinkedHashMap<String, String>();
   private List<String> urls;
 
@@ -46,6 +47,14 @@ public class Service {
     this.name = name;
   }
 
+  public Version getVersion() {
+    return version;
+  }
+
+  public void setVersion(Version version) {
+    this.version = version;
+  }
+
   public List<String> getUrls() {
     if ( urls == null ) {
       urls = new ArrayList<String>();

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/Topology.java
----------------------------------------------------------------------
diff --git 
a/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/Topology.java 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/Topology.java
index c8d611d..2f5d671 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/Topology.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/Topology.java
@@ -17,12 +17,11 @@
  */
 package org.apache.hadoop.gateway.topology;
 
+import org.apache.commons.collections.map.HashedMap;
+import org.apache.commons.collections.map.MultiKeyMap;
+
 import java.net.URI;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 public class Topology {
 
@@ -32,7 +31,12 @@ public class Topology {
   public List<Provider> providerList = new ArrayList<Provider>();
   private Map<String,Map<String,Provider>> providerMap = new 
HashMap<String,Map<String,Provider>>();
   public List<Service> services = new ArrayList<Service>();
-  private Map<String, Map<String, Service>> serviceMap = new HashMap<String, 
Map<String, Service>>();
+
+  private MultiKeyMap serviceMap;
+
+  public Topology() {
+    serviceMap = MultiKeyMap.decorate(new HashedMap());
+  }
 
   public URI getUri() {
     return uri;
@@ -62,27 +66,13 @@ public class Topology {
     return services;
   }
 
-  public Service getService( String role, String name ) {
-    Service service = null;
-    Map<String, Service> nameMap = serviceMap.get( role );
-    if( nameMap != null) {
-      service = nameMap.get( name );
-      if ( service == null && !nameMap.values().isEmpty() ) {
-        service = (Service) nameMap.values().toArray()[0];
-      }
-    }
-    return service;
+  public Service getService(String role, String name, Version version) {
+    return (Service)serviceMap.get(role, name, version);
   }
 
   public void addService( Service service ) {
     services.add( service );
-    String role = service.getRole();
-    Map<String, Service> nameMap = serviceMap.get( role );
-    if( nameMap == null ) {
-      nameMap = new HashMap<String, Service>();
-      serviceMap.put( role, nameMap );
-    }
-    nameMap.put( service.getName(), service );
+    serviceMap.put(service.getRole(), service.getName(), service.getVersion(), 
service);
   }
 
   public Collection<Provider> getProviders() {

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/Version.java
----------------------------------------------------------------------
diff --git 
a/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/Version.java 
b/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/Version.java
new file mode 100644
index 0000000..08aca08
--- /dev/null
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/Version.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.hadoop.gateway.topology;
+
+public class Version implements Comparable<Version> {
+
+  private int major;
+
+  private int minor;
+
+  private int patch;
+
+  public Version() {
+  }
+
+  public Version(String version) {
+    setVersion(version);
+  }
+
+  public Version(int major, int minor, int patch) {
+    this.major = major;
+    this.minor = minor;
+    this.patch = patch;
+  }
+
+  public int getMajor() {
+    return major;
+  }
+
+  public void setMajor(int major) {
+    this.major = major;
+  }
+
+  public int getMinor() {
+    return minor;
+  }
+
+  public void setMinor(int minor) {
+    this.minor = minor;
+  }
+
+  public int getPatch() {
+    return patch;
+  }
+
+  public void setPatch(int patch) {
+    this.patch = patch;
+  }
+
+  public void setVersion(String version) {
+    if (version != null) {
+      parseVersion(version);
+    }
+  }
+
+  private void parseVersion(String version) {
+    String parts[] = version.split("\\.");
+    int length = parts.length;
+    if (length >= 1) {
+      major = Integer.parseInt(parts[0]);
+    }
+    if (length >= 2) {
+      minor = Integer.parseInt(parts[1]);
+    }
+    if (length >= 3) {
+      patch = Integer.parseInt(parts[2]);
+    }
+  }
+
+  @Override
+  public int compareTo(Version version) {
+    if (major > version.getMajor()) {
+      return 1;
+    }
+    if (major < version.getMajor()) {
+      return -1;
+    }
+    if (minor > version.getMinor()) {
+      return 1;
+    }
+    if (minor < version.getMinor()) {
+      return -1;
+    }
+    if (patch > version.getPatch()) {
+      return 1;
+    }
+    if (patch < version.getPatch()) {
+      return -1;
+    }
+    return 0;
+  }
+
+  @Override
+  public String toString() {
+    StringBuffer buffer = new StringBuffer();
+    buffer.append(major);
+    buffer.append(".");
+    buffer.append(minor);
+    buffer.append(".");
+    buffer.append(patch);
+    return buffer.toString();
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof Version)) {
+      return false;
+    }
+    Version that = (Version) o;
+    if (major == that.getMajor() && minor == that.getMinor() && patch == 
that.getPatch()) {
+      return true;
+    }
+    return false;
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-spi/src/main/resources/META-INF/services/org.apache.hadoop.gateway.config.spi.ConfigurationAdapterDescriptor
----------------------------------------------------------------------
diff --git 
a/gateway-spi/src/main/resources/META-INF/services/org.apache.hadoop.gateway.config.spi.ConfigurationAdapterDescriptor
 
b/gateway-spi/src/main/resources/META-INF/services/org.apache.hadoop.gateway.config.spi.ConfigurationAdapterDescriptor
new file mode 100755
index 0000000..4c1cad9
--- /dev/null
+++ 
b/gateway-spi/src/main/resources/META-INF/services/org.apache.hadoop.gateway.config.spi.ConfigurationAdapterDescriptor
@@ -0,0 +1,18 @@
+##########################################################################
+# 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.config.FilterConfigurationAdapterDescriptor

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-spi/src/test/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatchTest.java
----------------------------------------------------------------------
diff --git 
a/gateway-spi/src/test/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatchTest.java
 
b/gateway-spi/src/test/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatchTest.java
index b9b26b6..9446ab5 100644
--- 
a/gateway-spi/src/test/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatchTest.java
+++ 
b/gateway-spi/src/test/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatchTest.java
@@ -39,6 +39,7 @@ import javax.servlet.http.HttpServletResponse;
 import org.apache.hadoop.gateway.config.GatewayConfig;
 import org.apache.http.HttpEntity;
 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;
@@ -76,6 +77,7 @@ public class HttpClientDispatchTest {
     EasyMock.replay( outboundRequest, inboundRequest, outboundResponse );
 
     HttpClientDispatch dispatch = new HttpClientDispatch();
+    dispatch.setHttpClient(new DefaultHttpClient());
     try {
       dispatch.executeRequest( outboundRequest, inboundRequest, 
outboundResponse );
       fail( "Should have thrown IOException" );

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/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));
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayFuncTestDriver.java
----------------------------------------------------------------------
diff --git 
a/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayFuncTestDriver.java
 
b/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayFuncTestDriver.java
index 6faccac..6117c76 100644
--- 
a/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayFuncTestDriver.java
+++ 
b/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayFuncTestDriver.java
@@ -157,6 +157,18 @@ public class GatewayFuncTestDriver {
     } catch (ServiceLifecycleException e) {
       e.printStackTrace(); // I18N not required.
     }
+    File stacksDir = new File( config.getGatewayStacksDir() );
+    stacksDir.mkdirs();
+    //TODO: [sumit] This is a hack for now, need to find a better way to 
locate the source resources for 'stacks' to be tested
+    String pathToStacksSource = 
"gateway-service-definitions/src/main/resources/services";
+    File stacksSourceDir = new File( targetDir.getParent(), 
pathToStacksSource);
+    if (!stacksSourceDir.exists()) {
+      stacksSourceDir = new File( targetDir.getParentFile().getParent(), 
pathToStacksSource);
+    }
+    if (stacksSourceDir.exists()) {
+      FileUtils.copyDirectoryToDirectory(stacksSourceDir, stacksDir);
+    }
+
     gateway = GatewayServer.startGateway( config, srvcs );
     MatcherAssert.assertThat( "Failed to start gateway.", gateway, 
notNullValue() );
 
@@ -170,6 +182,7 @@ public class GatewayFuncTestDriver {
     FileUtils.deleteQuietly( new File( config.getGatewaySecurityDir() ) );
     FileUtils.deleteQuietly( new File( config.getGatewayDeploymentDir() ) );
     FileUtils.deleteQuietly( new File( config.getGatewayDataDir() ) );
+    FileUtils.deleteQuietly( new File( config.getGatewayStacksDir() ) );
 
     for( Service service : services.values() ) {
       service.server.stop();

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayTestConfig.java
----------------------------------------------------------------------
diff --git 
a/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayTestConfig.java 
b/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayTestConfig.java
index 4340500..f91b7bf 100644
--- 
a/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayTestConfig.java
+++ 
b/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayTestConfig.java
@@ -234,5 +234,9 @@ public class GatewayTestConfig implements GatewayConfig {
 //  public void setKerberosLoginConfig(String kerberosLoginConfig) {
 //   this.kerberosLoginConfig = kerberosLoginConfig;
 //  }
-  
+
+   @Override
+   public String getGatewayStacksDir() {
+      return gatewayHomeDir + "/data/services";
+   }
 }

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-test/src/test/java/org/apache/hadoop/gateway/deploy/DeploymentFactoryFuncTest.java
----------------------------------------------------------------------
diff --git 
a/gateway-test/src/test/java/org/apache/hadoop/gateway/deploy/DeploymentFactoryFuncTest.java
 
b/gateway-test/src/test/java/org/apache/hadoop/gateway/deploy/DeploymentFactoryFuncTest.java
index fc699b1..8b54f6f 100644
--- 
a/gateway-test/src/test/java/org/apache/hadoop/gateway/deploy/DeploymentFactoryFuncTest.java
+++ 
b/gateway-test/src/test/java/org/apache/hadoop/gateway/deploy/DeploymentFactoryFuncTest.java
@@ -82,6 +82,7 @@ public class DeploymentFactoryFuncTest {
 
 //    ((GatewayTestConfig) config).setDeploymentDir( "clusters" );
 
+    addStacksDir(config, targetDir);
     DefaultGatewayServices srvcs = new DefaultGatewayServices();
     Map<String,String> options = new HashMap<String,String>();
     options.put("persist-master", "false");
@@ -135,6 +136,7 @@ public class DeploymentFactoryFuncTest {
     ((GatewayTestConfig) config).setGatewayHomeDir( 
gatewayDir.getAbsolutePath() );
     File deployDir = new File( config.getGatewayDeploymentDir() );
     deployDir.mkdirs();
+    addStacksDir(config, targetDir);
 
     DefaultGatewayServices srvcs = new DefaultGatewayServices();
     Map<String,String> options = new HashMap<String,String>();
@@ -189,6 +191,7 @@ public class DeploymentFactoryFuncTest {
     ((GatewayTestConfig) config).setGatewayHomeDir( 
gatewayDir.getAbsolutePath() );
     File deployDir = new File( config.getGatewayDeploymentDir() );
     deployDir.mkdirs();
+    addStacksDir(config, targetDir);
 
     DefaultGatewayServices srvcs = new DefaultGatewayServices();
     Map<String,String> options = new HashMap<String,String>();
@@ -228,8 +231,8 @@ public class DeploymentFactoryFuncTest {
     topology.addProvider( authorizer );
 
     WebArchive war = DeploymentFactory.createDeployment( config, topology );
-    //File dir = new File( System.getProperty( "user.dir" ) );
-    //File file = war.as( ExplodedExporter.class ).exportExploded( dir, 
"test-cluster.war" );
+//    File dir = new File( System.getProperty( "user.dir" ) );
+//    File file = war.as( ExplodedExporter.class ).exportExploded( dir, 
"test-cluster.war" );
 
     Document web = parse( war.get( "WEB-INF/web.xml" ).getAsset().openStream() 
);
     assertThat( web, hasXPath( "/web-app/servlet/servlet-name", equalTo( 
"test-cluster" ) ) );
@@ -264,8 +267,8 @@ public class DeploymentFactoryFuncTest {
     assertThat( gateway, hasXPath( "/gateway/resource[1]/filter[6]/class", 
equalTo( "org.apache.hadoop.gateway.filter.AclsAuthorizationFilter" ) ) );
 
     assertThat( gateway, hasXPath( "/gateway/resource[1]/filter[7]/role", 
equalTo( "dispatch" ) ) );
-    assertThat( gateway, hasXPath( "/gateway/resource[1]/filter[7]/name", 
equalTo( "hdfs" ) ) );
-    assertThat( gateway, hasXPath( "/gateway/resource[1]/filter[7]/class", 
equalTo( "org.apache.hadoop.gateway.hdfs.dispatch.HdfsDispatch" ) ) );
+    assertThat( gateway, hasXPath( "/gateway/resource[1]/filter[7]/name", 
equalTo( "webhdfs" ) ) );
+    assertThat( gateway, hasXPath( "/gateway/resource[1]/filter[7]/class", 
equalTo( "org.apache.hadoop.gateway.dispatch.GatewayDispatchFilter" ) ) );
 
     assertThat( gateway, hasXPath( "/gateway/resource[2]/pattern", equalTo( 
"/webhdfs/v1/**?**" ) ) );
     //assertThat( gateway, hasXPath( "/gateway/resource[2]/target", equalTo( 
"http://localhost:50070/webhdfs/v1/{path=**}?{**}"; ) ) );
@@ -290,8 +293,8 @@ public class DeploymentFactoryFuncTest {
     assertThat( gateway, hasXPath( "/gateway/resource[1]/filter[6]/class", 
equalTo( "org.apache.hadoop.gateway.filter.AclsAuthorizationFilter" ) ) );
 
     assertThat( gateway, hasXPath( "/gateway/resource[2]/filter[7]/role", 
equalTo( "dispatch" ) ) );
-    assertThat( gateway, hasXPath( "/gateway/resource[2]/filter[7]/name", 
equalTo( "hdfs" ) ) );
-    assertThat( gateway, hasXPath( "/gateway/resource[2]/filter[7]/class", 
equalTo( "org.apache.hadoop.gateway.hdfs.dispatch.HdfsDispatch" ) ) );
+    assertThat( gateway, hasXPath( "/gateway/resource[2]/filter[7]/name", 
equalTo( "webhdfs" ) ) );
+    assertThat( gateway, hasXPath( "/gateway/resource[2]/filter[7]/class", 
equalTo( "org.apache.hadoop.gateway.dispatch.GatewayDispatchFilter" ) ) );
   }
 
 
@@ -379,6 +382,7 @@ public class DeploymentFactoryFuncTest {
     ((GatewayTestConfig) 
config).setGatewayHomeDir(gatewayDir.getAbsolutePath());
     File deployDir = new File(config.getGatewayDeploymentDir());
     deployDir.mkdirs();
+    addStacksDir(config, targetDir);
 
     DefaultGatewayServices srvcs = new DefaultGatewayServices();
     Map<String, String> options = new HashMap<String, String>();
@@ -453,6 +457,7 @@ public class DeploymentFactoryFuncTest {
     ((GatewayTestConfig) 
config).setGatewayHomeDir(gatewayDir.getAbsolutePath());
     File deployDir = new File(config.getGatewayDeploymentDir());
     deployDir.mkdirs();
+    addStacksDir(config, targetDir);
 
     DefaultGatewayServices srvcs = new DefaultGatewayServices();
     Map<String, String> options = new HashMap<String, String>();
@@ -499,7 +504,7 @@ public class DeploymentFactoryFuncTest {
 
     WebArchive war = DeploymentFactory.createDeployment( config, topology );
     Document doc = parse( war.get( "WEB-INF/gateway.xml" 
).getAsset().openStream() );
-    //dump( doc );
+    dump( doc );
 
     Node resourceNode, filterNode, paramNode;
     String value;
@@ -538,6 +543,33 @@ public class DeploymentFactoryFuncTest {
     return builder.parse( source );
   }
 
+  private void addStacksDir(GatewayConfig config, File targetDir) {
+    File stacksDir = new File( config.getGatewayStacksDir() );
+    stacksDir.mkdirs();
+    //TODO: [sumit] This is a hack for now, need to find a better way to 
locate the source resources for 'stacks' to be tested
+    String pathToStacksSource = 
"gateway-service-definitions/src/main/resources/services";
+    File stacksSourceDir = new File( targetDir.getParent(), 
pathToStacksSource);
+    if (!stacksSourceDir.exists()) {
+      stacksSourceDir = new File( targetDir.getParentFile().getParent(), 
pathToStacksSource);
+    }
+    if (stacksSourceDir.exists()) {
+      try {
+        FileUtils.copyDirectoryToDirectory(stacksSourceDir, stacksDir);
+      } catch ( IOException e) {
+        fail(e.getMessage());
+      }
+    }
+
+  }
+//  private void dump( Document document ) throws TransformerException {
+//    Transformer transformer = 
TransformerFactory.newInstance().newTransformer();
+//    transformer.setOutputProperty( OutputKeys.INDENT, "yes" );
+//    StreamResult result = new StreamResult( new StringWriter() );
+//    DOMSource source = new DOMSource( document );
+//    transformer.transform( source, result );
+//    String xmlString = result.getWriter().toString();
+//    System.out.println( xmlString );
+//  }
   private void dump( Document document ) throws TransformerException {
     Transformer transformer = 
TransformerFactory.newInstance().newTransformer();
     transformer.setOutputProperty( OutputKeys.INDENT, "yes" );

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-test/src/test/java/org/apache/hadoop/gateway/webhcat/WebHCatDeploymentContributorTest.java
----------------------------------------------------------------------
diff --git 
a/gateway-test/src/test/java/org/apache/hadoop/gateway/webhcat/WebHCatDeploymentContributorTest.java
 
b/gateway-test/src/test/java/org/apache/hadoop/gateway/webhcat/WebHCatDeploymentContributorTest.java
deleted file mode 100644
index 8b3303d..0000000
--- 
a/gateway-test/src/test/java/org/apache/hadoop/gateway/webhcat/WebHCatDeploymentContributorTest.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.webhcat;
-
-import org.apache.hadoop.gateway.deploy.ServiceDeploymentContributor;
-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 WebHCatDeploymentContributorTest {
-
-  @Test
-  public void testServiceLoader() throws Exception {
-    ServiceLoader loader = ServiceLoader.load( 
ServiceDeploymentContributor.class );
-    Iterator iterator = loader.iterator();
-    assertThat( "Service iterator empty.", iterator.hasNext() );
-    while( iterator.hasNext() ) {
-      Object object = iterator.next();
-      if( object instanceof WebHCatDeploymentContributor ) {
-        return;
-      }
-    }
-    fail( "Failed to find " + WebHCatDeploymentContributor.class.getName() + " 
via service loader." );
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-util-configinjector/pom.xml
----------------------------------------------------------------------
diff --git a/gateway-util-configinjector/pom.xml 
b/gateway-util-configinjector/pom.xml
new file mode 100755
index 0000000..b247e99
--- /dev/null
+++ b/gateway-util-configinjector/pom.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.knox</groupId>
+        <artifactId>gateway</artifactId>
+        <version>0.6.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>gateway-util-configinjector</artifactId>
+
+    <name>gateway-util-configinjector</name>
+    <description>A lightweight config injection utility</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+            <scope>compile</scope>
+            <version>1.9.2</version>
+        </dependency>
+
+        <dependency>
+            <groupId>${gateway-group}</groupId>
+            <artifactId>gateway-test-utils</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest-library</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/Alias.java
----------------------------------------------------------------------
diff --git 
a/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/Alias.java
 
b/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/Alias.java
new file mode 100755
index 0000000..b002e7a
--- /dev/null
+++ 
b/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/Alias.java
@@ -0,0 +1,31 @@
+/**
+ * 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.config;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target( { ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER} )
+@Retention( RetentionPolicy.RUNTIME )
+@Documented
+public @interface Alias {
+  public String value();
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/ConfigurationAdapter.java
----------------------------------------------------------------------
diff --git 
a/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/ConfigurationAdapter.java
 
b/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/ConfigurationAdapter.java
new file mode 100755
index 0000000..401258f
--- /dev/null
+++ 
b/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/ConfigurationAdapter.java
@@ -0,0 +1,24 @@
+/**
+ * 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.config;
+
+public interface ConfigurationAdapter {
+
+  Object getConfigurationValue(String name) throws ConfigurationException;
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/ConfigurationBinding.java
----------------------------------------------------------------------
diff --git 
a/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/ConfigurationBinding.java
 
b/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/ConfigurationBinding.java
new file mode 100755
index 0000000..a2b2b67
--- /dev/null
+++ 
b/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/ConfigurationBinding.java
@@ -0,0 +1,24 @@
+/**
+ * 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.config;
+
+public interface ConfigurationBinding {
+
+  String getConfigurationName(String name);
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/ConfigurationException.java
----------------------------------------------------------------------
diff --git 
a/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/ConfigurationException.java
 
b/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/ConfigurationException.java
new file mode 100755
index 0000000..c979cc6
--- /dev/null
+++ 
b/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/ConfigurationException.java
@@ -0,0 +1,30 @@
+/**
+ * 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.config;
+
+public class ConfigurationException extends RuntimeException {
+
+  public ConfigurationException( String message, Throwable cause ) {
+    super( message, cause );
+  }
+
+  public ConfigurationException( String message ) {
+    super( message );
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/ConfigurationInjectorBuilder.java
----------------------------------------------------------------------
diff --git 
a/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/ConfigurationInjectorBuilder.java
 
b/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/ConfigurationInjectorBuilder.java
new file mode 100755
index 0000000..e0fadbd
--- /dev/null
+++ 
b/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/ConfigurationInjectorBuilder.java
@@ -0,0 +1,107 @@
+/**
+ * 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.config;
+
+import org.apache.hadoop.gateway.config.impl.ConfigurationAdapterFactory;
+import org.apache.hadoop.gateway.config.impl.DefaultConfigurationBinding;
+import org.apache.hadoop.gateway.config.impl.MappedConfigurationBinding;
+import org.apache.hadoop.gateway.config.spi.ConfigurationInjector;
+
+import java.util.Iterator;
+import java.util.ServiceLoader;
+
+public class ConfigurationInjectorBuilder {
+
+  private static ConfigurationBinding DEFAULT_BINDING = new 
DefaultConfigurationBinding();
+  private static ConfigurationInjector INSTANCE = null;
+
+  private static synchronized ConfigurationInjector getInjector() {
+    if( INSTANCE == null ) {
+      INSTANCE = createInjector();
+    }
+    return INSTANCE;
+  }
+
+  private static synchronized ConfigurationInjector createInjector() {
+    ConfigurationInjector injector = null;
+    ServiceLoader<ConfigurationInjector> loader = ServiceLoader.load( 
ConfigurationInjector.class );
+    if( loader != null ) {
+      Iterator<ConfigurationInjector> iterator = loader.iterator();
+      if( iterator != null ) {
+        while( iterator.hasNext() ) {
+          injector = iterator.next();
+          break;
+        }
+      }
+    }
+    if( injector == null ) {
+      throw new ConfigurationException( String.format(
+          "Failed to load an implementation of %s", 
ConfigurationInjector.class.getName() ) );
+    }
+    return injector;
+  }
+
+  private Object target = null;
+  private ConfigurationAdapter source = null;
+  private ConfigurationBinding binding = null;
+
+  public static ConfigurationInjectorBuilder configuration() {
+    return new ConfigurationInjectorBuilder();
+  }
+
+  public ConfigurationInjectorBuilder target( Object target ) {
+    this.target = target;
+    return this;
+  }
+
+  public ConfigurationInjectorBuilder source( Object source ) {
+    this.source = ConfigurationAdapterFactory.get(source);
+    return this;
+  }
+
+  public ConfigurationInjectorBuilder source( ConfigurationAdapter adapter ) {
+    this.source = adapter;
+    return this;
+  }
+
+  public ConfigurationInjectorBuilder binding( ConfigurationBinding binding ) {
+    this.binding = binding;
+    return this;
+  }
+
+  public ConfigurationInjectorBuilder bind( String targetName, String 
sourceName ) {
+    ((MappedConfigurationBinding)binding()).bind( targetName, sourceName );
+    return this;
+  }
+
+  public ConfigurationBinding binding() {
+    if( binding == null ) {
+      binding = new MappedConfigurationBinding();
+    }
+    return binding;
+  }
+
+  public void inject() throws ConfigurationException {
+    ConfigurationInjector injector = getInjector();
+    if( binding == null ) {
+      binding = DEFAULT_BINDING;
+    }
+    injector.configure( target, source, binding );
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/Configure.java
----------------------------------------------------------------------
diff --git 
a/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/Configure.java
 
b/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/Configure.java
new file mode 100755
index 0000000..895648f
--- /dev/null
+++ 
b/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/Configure.java
@@ -0,0 +1,30 @@
+/**
+ * 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.config;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target( { ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER} )
+@Retention( RetentionPolicy.RUNTIME )
+@Documented
+public @interface Configure {
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/Default.java
----------------------------------------------------------------------
diff --git 
a/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/Default.java
 
b/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/Default.java
new file mode 100755
index 0000000..1ef9042
--- /dev/null
+++ 
b/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/Default.java
@@ -0,0 +1,31 @@
+/**
+ * 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.config;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target( { ElementType.PARAMETER } )
+@Retention( RetentionPolicy.RUNTIME )
+@Documented
+public @interface Default {
+  public String value();
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/Optional.java
----------------------------------------------------------------------
diff --git 
a/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/Optional.java
 
b/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/Optional.java
new file mode 100755
index 0000000..1299e75
--- /dev/null
+++ 
b/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/Optional.java
@@ -0,0 +1,30 @@
+/**
+ * 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.config;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target( { ElementType.FIELD } )
+@Retention( RetentionPolicy.RUNTIME )
+@Documented
+public @interface Optional {
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/0d9fa0da/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/impl/BeanConfigurationAdapter.java
----------------------------------------------------------------------
diff --git 
a/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/impl/BeanConfigurationAdapter.java
 
b/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/impl/BeanConfigurationAdapter.java
new file mode 100755
index 0000000..67459a4
--- /dev/null
+++ 
b/gateway-util-configinjector/src/main/java/org/apache/hadoop/gateway/config/impl/BeanConfigurationAdapter.java
@@ -0,0 +1,40 @@
+/**
+ * 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.config.impl;
+
+import org.apache.commons.beanutils.PropertyUtils;
+import org.apache.hadoop.gateway.config.ConfigurationAdapter;
+import org.apache.hadoop.gateway.config.ConfigurationException;
+
+public class BeanConfigurationAdapter implements ConfigurationAdapter {
+
+  private Object bean;
+
+  public BeanConfigurationAdapter( Object bean ) {
+    this.bean = bean;
+  }
+
+  @Override
+  public Object getConfigurationValue( String name ) throws 
ConfigurationException {
+    try {
+      return PropertyUtils.getSimpleProperty( bean, name );
+    } catch( Exception e ) {
+      throw new ConfigurationException( String.format( "" ), e );
+    }
+  }
+}

Reply via email to