You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by km...@apache.org on 2013/09/20 05:58:50 UTC

[1/3] KNOX-127: Use hostmap in some service registry rewrite functions.

Updated Branches:
  refs/heads/master afe298efe -> e338fe64f


http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/Expander.java
----------------------------------------------------------------------
diff --git a/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/Expander.java b/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/Expander.java
index 2ae5886..4d02ff2 100644
--- a/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/Expander.java
+++ b/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/Expander.java
@@ -31,67 +31,67 @@ public class Expander {
 
   private static Params EMPTY_PARAMS = new EmptyParams();
 
-  public static URI expand( Template template, Params params ) throws URISyntaxException {
-    return new Expander().expandToUri( template, params );
+  public static URI expand( Template template, Params params, Evaluator evaluator ) throws URISyntaxException {
+    return new Expander().expandToUri( template, params, evaluator );
   }
 
-  public URI expandToUri( Template template, Params params ) throws URISyntaxException {
-    return new URI( expandToString( template, params ) );
+  public URI expandToUri( Template template, Params params, Evaluator evaluator ) throws URISyntaxException {
+    return new URI( expandToString( template, params, evaluator ) );
   }
 
-  public Template expandToTemplate( Template template, Params params ) throws URISyntaxException {
+  public Template expandToTemplate( Template template, Params params, Evaluator evaluator ) throws URISyntaxException {
     //TODO: This could be much more efficient if it didn't create and then parse a string.
-    return Parser.parse( expandToString( template, params ) );
+    return Parser.parse( expandToString( template, params, evaluator ) );
   }
 
-  public String expandToString( Template template, Params params ) {
+  public String expandToString( Template template, Params params, Evaluator evaluator ) {
     StringBuilder builder = new StringBuilder();
     if( params == null ) {
       params = EMPTY_PARAMS;
     }
     Set<String> names = new HashSet<String>( params.getNames() );
-    expandScheme( template, names, params, builder );
-    expandAuthority( template, names, params, builder );
-    expandPath( template, names, params, builder );
-    expandQuery( template, names, params, builder );
-    expandFragment( template, names, params, builder );
+    expandScheme( template, names, params, evaluator, builder );
+    expandAuthority( template, names, params, evaluator, builder );
+    expandPath( template, names, params, evaluator, builder );
+    expandQuery( template, names, params, evaluator, builder );
+    expandFragment( template, names, params, evaluator, builder );
     return builder.toString();
   }
 
-  private static void expandScheme( Template template, Set<String> names, Params params, StringBuilder builder ) {
+  private static void expandScheme( Template template, Set<String> names, Params params, Evaluator evaluator, StringBuilder builder ) {
     Segment segment = template.getScheme();
     if( segment != null ) {
-      expandSingleValue( template.getScheme(), names, params, builder );
+      expandSingleValue( template.getScheme(), names, params, evaluator, builder );
       builder.append( ":" );
     }
   }
 
-  private static void expandAuthority( Template template, Set<String> names, Params params, StringBuilder builder ) {
+  private static void expandAuthority( Template template, Set<String> names, Params params, Evaluator evaluator, StringBuilder builder ) {
     if( template.hasAuthority() ) {
       builder.append( "//" );
       Segment username = template.getUsername();
       Segment password = template.getPassword();
       Segment host = template.getHost();
       Segment port = template.getPort();
-      expandSingleValue( username, names, params, builder );
+      expandSingleValue( username, names, params, evaluator, builder );
       if( password != null ) {
         builder.append( ":" );
-        expandSingleValue( password, names, params, builder );
+        expandSingleValue( password, names, params, evaluator, builder );
       }
       if( username != null || password != null ) {
         builder.append( "@" );
       }
       if( host != null ) {
-        expandSingleValue( host, names, params, builder );
+        expandSingleValue( host, names, params, evaluator, builder );
       }
       if( port != null ) {
         builder.append( ":" );
-        expandSingleValue( port, names, params, builder );
+        expandSingleValue( port, names, params, evaluator, builder );
       }
     }
   }
 
-  private static void expandPath( Template template, Set<String> names, Params params, StringBuilder builder ) {
+  private static void expandPath( Template template, Set<String> names, Params params, Evaluator evaluator, StringBuilder builder ) {
     if( template.isAbsolute() ) {
       builder.append( "/" );
     }
@@ -102,7 +102,8 @@ public class Expander {
       }
       Path segment = path.get( i );
       String name = segment.getParamName();
-      names.remove( name );
+      Function function = new Function( name );
+      names.remove( function.getParameterName() );
       Segment.Value value = segment.getFirstValue();
       switch( value.getType() ) {
         case( Segment.STATIC ):
@@ -113,7 +114,7 @@ public class Expander {
         case( Segment.STAR ):
         case( Segment.GLOB ):
         case( Segment.REGEX ):
-          List<String> values = params.resolve( name );
+          List<String> values = function.evaluate( params, evaluator );
           expandPathValues( segment, values, builder );
           break;
       }
@@ -142,9 +143,9 @@ public class Expander {
     }
   }
 
-  private static void expandQuery( Template template, Set<String> names, Params params, StringBuilder builder ) {
+  private static void expandQuery( Template template, Set<String> names, Params params, Evaluator evaluator, StringBuilder builder ) {
     AtomicInteger index = new AtomicInteger( 0 );
-    expandExplicitQuery( template, names, params, builder, index );
+    expandExplicitQuery( template, names, params, evaluator, builder, index );
     expandExtraQuery( template, names, params, builder, index );
     //Kevin: I took this out because it causes '?' to be added to expanded templates when there are not query params.
 //    if( template.hasQuery() && index.get() == 0 ) {
@@ -152,7 +153,7 @@ public class Expander {
 //    }
   }
 
-  private static void expandExplicitQuery( Template template, Set<String> names, Params params, StringBuilder builder, AtomicInteger index ) {
+  private static void expandExplicitQuery( Template template, Set<String> names, Params params, Evaluator evaluator, StringBuilder builder, AtomicInteger index ) {
     Collection<Query> query = template.getQuery().values();
     if( !query.isEmpty() ) {
       Iterator<Query> iterator = query.iterator();
@@ -165,9 +166,9 @@ public class Expander {
         }
         Query segment = iterator.next();
         String queryName = segment.getQueryName();
-        String funcName = segment.getParamName();
-        String paramName = extractParamNameFromFunction( funcName );
-        names.remove( paramName );
+        String paramName = segment.getParamName();
+        Function function = new Function( paramName );
+        names.remove( function.getParameterName() );
         for( Segment.Value value: segment.getValues() ) {
           switch( value.getType() ) {
             case( Segment.STATIC ):
@@ -182,7 +183,7 @@ public class Expander {
             case( Segment.GLOB ):
             case( Segment.STAR ):
             case( Segment.REGEX ):
-              List<String> values = params.resolve( funcName );
+              List<String> values = function.evaluate( params, evaluator );
               expandQueryValues( segment, queryName, values, builder );
               break;
             default:
@@ -240,52 +241,42 @@ public class Expander {
     }
   }
 
-  private static void expandFragment( Template template, Set<String> names, Params params, StringBuilder builder ) {
+  private static void expandFragment( Template template, Set<String> names, Params params, Evaluator evaluator, StringBuilder builder ) {
     if( template.hasFragment() ) {
       builder.append( "#" );
     }
-    expandSingleValue( template.getFragment(), names, params, builder );
+    expandSingleValue( template.getFragment(), names, params, evaluator, builder );
   }
 
-  private static void expandSingleValue( Segment segment, Set<String> names, Params params, StringBuilder builder ) {
+  private static void expandSingleValue( Segment segment, Set<String> names, Params params, Evaluator evaluator, StringBuilder builder ) {
     if( segment != null ) {
-      String name = segment.getParamName();
-      names.remove( name );
+      String paramName = segment.getParamName();
+      Function function = new Function( paramName );
+      names.remove( function.getParameterName() );
       Segment.Value value = segment.getFirstValue();
+      String str;
       switch( value.getType() ) {
-        case( Segment.STATIC ):
-          String pattern = value.getPattern();
-          builder.append( pattern );
-          break;
-        case( Segment.DEFAULT ):
-        case( Segment.STAR ):
-        case( Segment.GLOB ):
-        case( Segment.REGEX ):
-          List<String> values = params.resolve( name );
+        case Segment.DEFAULT:
+        case Segment.STAR:
+        case Segment.GLOB:
+        case Segment.REGEX:
+          List<String> values = function.evaluate( params, evaluator );
           if( values != null && !values.isEmpty() ) {
-            builder.append( values.get( 0 ) );
+            str = values.get( 0 );
+          } else if( function.getFunctionName() != null ) {
+            str = paramName;
           } else {
-            builder.append( segment.getFirstValue().getPattern() );
+            str = value.getPattern();
           }
           break;
+        default:
+          str = value.getPattern();
+          break;
       }
+      builder.append( str );
     }
   }
 
-  private static String extractParamNameFromFunction( String function ) {
-    String param = function;
-    if( param != null && param.startsWith( "$" ) ) {
-      int stop = param.lastIndexOf( ')' );
-      if( stop > 1 ) {
-        int start = param.indexOf( '(' );
-        if( start > -1 ) {
-          param = param.substring( start+1, stop );
-        }
-      }
-    }
-    return param;
-  }
-
   private static class EmptyParams implements Params {
     @Override
     public Set<String> getNames() {
@@ -296,6 +287,7 @@ public class Expander {
     public List<String> resolve( String name ) {
       return Collections.EMPTY_LIST;
     }
+
   }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/Function.java
----------------------------------------------------------------------
diff --git a/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/Function.java b/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/Function.java
new file mode 100644
index 0000000..cbe38eb
--- /dev/null
+++ b/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/Function.java
@@ -0,0 +1,114 @@
+/**
+ * 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.urltemplate;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.StringTokenizer;
+
+class Function {
+
+  private enum State { UNKNOWN, FUNCTION, VARIABLE, LITERAL }
+
+  private String funcName = null;
+  private String paramName = null;
+  private List<String> paramValue = null;
+
+  static List<String> evaluate( String statement, Resolver resolver, Evaluator evaluator ) {
+    Function function = new Function( statement );
+    List<String> results = function.evaluate( resolver, evaluator );
+    return results;
+  }
+
+  Function( String statement ) {
+    if( statement != null ) {
+      StringTokenizer parser = new StringTokenizer( statement, "$()[]", true );
+      State state = State.UNKNOWN;
+      String token;
+      while( parser.hasMoreTokens() ) {
+        token = parser.nextToken().trim();
+        if( !token.isEmpty() ) {
+          switch( state ) {
+            case UNKNOWN:
+              if( "$".equals( token ) ) {
+                state = State.FUNCTION;
+              } else if( "(".equals( token ) ) {
+                state = State.VARIABLE;
+              } else if( "[".equals( token ) ) {
+                state = State.LITERAL;
+              } else {
+                paramName = token;
+                return;
+              }
+              break;
+            case FUNCTION:
+              if( "$".equals( token ) || ")".equals( token ) || "]".equals( token ) ) {
+                // Ignore it.
+              } else if( "(".equals( token ) ) {
+                state = State.VARIABLE;
+              } else if( "[".equals( token ) ) {
+                state = State.LITERAL;
+              } else {
+                funcName = token;
+                state = State.UNKNOWN;
+              }
+              break;
+            case VARIABLE:
+              if( "$".equals( token ) || "(".equals( token ) || ")".equals( token ) || "[".equals( token ) || "]".equals( token ) ) {
+                // Ignore it.
+              } else {
+                paramName = token;
+                return;
+              }
+            case LITERAL:
+              if( "$".equals( token ) || "(".equals( token ) || ")".equals( token ) || "[".equals( token ) || "]".equals( token ) ) {
+                // Ignore it.
+              } else {
+                paramValue = Arrays.asList( token );
+              }
+              return;
+          }
+        }
+      }
+    }
+  }
+
+  String getFunctionName() {
+    return funcName;
+  }
+
+  String getParameterName() {
+    return paramName;
+  }
+
+  List<String> getParameterValue() {
+    return paramValue;
+  }
+
+  List<String> evaluate( Resolver resolver, Evaluator evaluator ) {
+    List<String> values = paramValue;
+    if( paramName != null && resolver != null ) {
+      values = resolver.resolve( paramName );
+    }
+    if( funcName != null && evaluator != null ) {
+      values = evaluator.evaluate( funcName, values );
+    }
+    return values;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/MockParams.java
----------------------------------------------------------------------
diff --git a/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/MockParams.java b/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/MockParams.java
index 98f9e8b..ecdeb3c 100644
--- a/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/MockParams.java
+++ b/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/MockParams.java
@@ -50,6 +50,7 @@ public class MockParams implements Params {
     values.add( 0, value );
   }
 
+  @Override
   public List<String> resolve( String name ) {
     return map.get( name );
   }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/Rewriter.java
----------------------------------------------------------------------
diff --git a/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/Rewriter.java b/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/Rewriter.java
index 98d751d..ebe7e15 100644
--- a/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/Rewriter.java
+++ b/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/Rewriter.java
@@ -37,12 +37,12 @@ public class Rewriter {
 
   private Matcher<Template> rules;
 
-  public static URI rewrite( URI inputUri, Template inputTemplate, Template outputTemplate, Resolver resolver )
+  public static URI rewrite( URI inputUri, Template inputTemplate, Template outputTemplate, Resolver resolver, Evaluator evaluator )
       throws URISyntaxException {
     Rewriter rewriter = new Rewriter();
     rewriter.addRule( inputTemplate, outputTemplate );
     Template inputUriTemplate = Parser.parse( inputUri.toString() );
-    return rewriter.rewrite( inputUriTemplate, resolver );
+    return rewriter.rewrite( inputUriTemplate, resolver, evaluator );
   }
 
   public Rewriter() {
@@ -53,7 +53,7 @@ public class Rewriter {
     rules.add( inputTemplate, outputTemplate );
   }
 
-  public URI rewrite( Template input, Resolver resolver )
+  public URI rewrite( Template input, Resolver resolver, Evaluator evaluator )
       throws URISyntaxException {
     URI outputUri = null;
     Matcher<Template>.Match match = rules.match( input );
@@ -64,7 +64,7 @@ public class Rewriter {
       } else {
         params = new RewriteParams( match.getParams(), resolver );
       }
-      outputUri = Expander.expand( match.getValue(), params );
+      outputUri = Expander.expand( match.getValue(), params, evaluator );
     }
     return outputUri;
   }
@@ -96,6 +96,7 @@ public class Rewriter {
       }
       return values;
     }
+
   }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/ExpanderTest.java
----------------------------------------------------------------------
diff --git a/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/ExpanderTest.java b/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/ExpanderTest.java
index ae65e84..28de5c4 100644
--- a/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/ExpanderTest.java
+++ b/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/ExpanderTest.java
@@ -47,7 +47,7 @@ public class ExpanderTest {
     text = "foo://username:password@example.com:8042/over/there/index.dtb?type=animal&name=narwhal#nose";
     template = Parser.parse( text );
     params = new MockParams();
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( text ) ) ;
 
     text = "{scheme}://{username}:{password}@{host}:{port}/{path=**}?query={queryParam}#{fragment}";
@@ -64,7 +64,7 @@ public class ExpanderTest {
     params.addValue( "path", "file" );
     params.addValue( "queryParam", "new-value" );
     params.addValue( "fragment", "fragment" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "http://horton:hadoop@hortonworks.com:8888/top/mid/bot/file?query=new-value#fragment" ) ) ;
   }
 
@@ -76,91 +76,91 @@ public class ExpanderTest {
 
     template = Parser.parse( "" );
     params = new MockParams();
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "" ) ) ;
 
     template = Parser.parse( "/" );
     params = new MockParams();
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "/" ) ) ;
 
     template = Parser.parse( "{path-name}" );
     params = new MockParams();
     params.addValue( "path-name", "path-value" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "path-value" ) ) ;
 
     template = Parser.parse( "/{path-name}" );
     params = new MockParams();
     params.addValue( "path-name", "path-value" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "/path-value" ) ) ;
 
     template = Parser.parse( "{path-name}/" );
     params = new MockParams();
     params.addValue( "path-name", "path-value" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "path-value/" ) ) ;
 
     template = Parser.parse( "/{path-name}/" );
     params = new MockParams();
     params.addValue( "path-name", "path-value" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "/path-value/" ) ) ;
 
     template = Parser.parse( "path-name" );
     params = new MockParams();
     params.addValue( "path-name", "other-path-value" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "path-name" ) ) ;
 
     template = Parser.parse( "/path-name" );
     params = new MockParams();
     params.addValue( "path-name", "other-path-value" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "/path-name" ) ) ;
 
     template = Parser.parse( "path-name/" );
     params = new MockParams();
     params.addValue( "path-name", "other-path-value" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "path-name/" ) ) ;
 
     template = Parser.parse( "/path-name/" );
     params = new MockParams();
     params.addValue( "path-name", "other-path-value" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "/path-name/" ) ) ;
 
     template = Parser.parse( "?" );
     params = new MockParams();
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "" ) ) ;
 
     template = Parser.parse( "?query-name={queryParam-name}" );
     params = new MockParams();
     params.addValue( "queryParam-name", "queryParam-value" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "?query-name=queryParam-value" ) ) ;
 
     template = Parser.parse( "?query-name-1={queryParam-name-1}&query-name-2={queryParam-name-2}" );
     params = new MockParams();
     params.addValue( "queryParam-name-1", "queryParam-value-1" );
     params.addValue( "queryParam-name-2", "queryParam-value-2" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "?query-name-1=queryParam-value-1&query-name-2=queryParam-value-2" ) ) ;
 
     template = Parser.parse( "?query-name=queryParam-value" );
     params = new MockParams();
     params.addValue( "queryParam-name", "other-queryParam-value" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "?query-name=queryParam-value" ) ) ;
 
     template = Parser.parse( "?query-name-1=queryParam-value-1&query-name-2=queryParam-value-2" );
     params = new MockParams();
     params.addValue( "queryParam-name-1", "other-queryParam-value-1" );
     params.addValue( "queryParam-name-2", "other-queryParam-value-2" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "?query-name-1=queryParam-value-1&query-name-2=queryParam-value-2" ) ) ;
   }
 
@@ -185,22 +185,22 @@ public class ExpanderTest {
 
     template = Parser.parse( "//host" );
     params = new MockParams();
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "//host" ) ) ;
 
     template = Parser.parse( "//:port" );
     params = new MockParams();
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "//:port" ) ) ;
 
     template = Parser.parse( "//username@" );
     params = new MockParams();
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "//username@" ) ) ;
 
     template = Parser.parse( "//:password@" );
     params = new MockParams();
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "//:password@" ) ) ;
   }
 
@@ -212,28 +212,28 @@ public class ExpanderTest {
 
     template = Parser.parse( "/a/b/c" );
     params = new MockParams();
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "/a/b/c" ) ) ;
 
     template = Parser.parse( "/top/{middle}/bottom" );
     params = new MockParams();
     params.addValue( "middle", "A" );
     params.addValue( "middle", "B" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "/top/A/B/bottom" ) ) ;
 
     template = Parser.parse( "/top/{middle=*}/bottom" );
     params = new MockParams();
     params.addValue( "middle", "A" );
     params.addValue( "middle", "B" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "/top/A/bottom" ) ) ;
 
     template = Parser.parse( "/top/{middle=**}/bottom" );
     params = new MockParams();
     params.addValue( "middle", "A" );
     params.addValue( "middle", "B" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "/top/A/B/bottom" ) ) ;
   }
 
@@ -245,28 +245,28 @@ public class ExpanderTest {
 
     template = Parser.parse( "?query" );
     params = new MockParams();
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "?query" ) ) ;
 
     template = Parser.parse( "?query={queryParam}" );
     params = new MockParams();
     params.addValue( "queryParam", "A" );
     params.addValue( "queryParam", "B" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "?query=A&query=B" ) ) ;
 
     template = Parser.parse( "?query={queryParam=*}" );
     params = new MockParams();
     params.addValue( "queryParam", "A" );
     params.addValue( "queryParam", "B" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "?query=A" ) ) ;
 
     template = Parser.parse( "?query={queryParam=**}" );
     params = new MockParams();
     params.addValue( "queryParam", "A" );
     params.addValue( "queryParam", "B" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "?query=A&query=B" ) ) ;
 
   }
@@ -287,21 +287,21 @@ public class ExpanderTest {
     params.addValue( "extra", "extraA" );
 
     template = Parser.parse( "{scheme}://host/{path=*]?{query=*}" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "schemeA://host/pathA?query=queryA" ) );
 
     template = Parser.parse( "{scheme}://host/{path=**}?{query=**}" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat( expanded.toString(), equalTo( "schemeA://host/pathA/pathB?query=queryA&query=queryB" ) );
 
     template = Parser.parse( "{scheme}://host/{path=**}?{host}&{query=**}&{**}" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat(
         expanded.toString(),
         equalTo( "schemeA://host/pathA/pathB?host=hostA&query=queryA&query=queryB&extra=extraA" ) );
 
     template = Parser.parse( "{scheme}://host/{path=**}?server={host}&{query=**}&{**}" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat(
         expanded.toString(),
         equalTo( "schemeA://host/pathA/pathB?server=hostA&query=queryA&query=queryB&extra=extraA" ) );
@@ -310,7 +310,7 @@ public class ExpanderTest {
     // is copied.  I'm not really sure what the correct behavior should be.  My initial thinking
     // is that if something within {} isn't resolve to a param it should be dropped from the output.
     template = Parser.parse( "{scheme}://host/{path=**}?{server=host}&{query=**}&{**}" );
-    expanded = Expander.expand( template, params );
+    expanded = Expander.expand( template, params, null );
     assertThat(
         expanded.toString(),
         equalTo( "schemeA://host/pathA/pathB?server=host&query=queryA&query=queryB&host=hostA&extra=extraA" ) );

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/FunctionTest.java
----------------------------------------------------------------------
diff --git a/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/FunctionTest.java b/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/FunctionTest.java
new file mode 100644
index 0000000..a5304d1
--- /dev/null
+++ b/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/FunctionTest.java
@@ -0,0 +1,167 @@
+/**
+ * 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.urltemplate;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
+import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
+
+public class FunctionTest {
+
+  @Test
+  public void testParse() throws Exception {
+    Function function;
+
+    function = new Function( null );
+    assertThat( function.getFunctionName(), nullValue() );
+    assertThat( function.getParameterName(), nullValue() );
+    assertThat( function.getParameterValue(), nullValue() );
+
+    function = new Function( "" );
+    assertThat( function.getFunctionName(), nullValue() );
+    assertThat( function.getParameterName(), nullValue() );
+    assertThat( function.getParameterValue(), nullValue() );
+
+    function = new Function( " " );
+    assertThat( function.getFunctionName(), nullValue() );
+    assertThat( function.getParameterName(), nullValue() );
+    assertThat( function.getParameterValue(), nullValue() );
+
+    function = new Function( "variable" );
+    assertThat( function.getFunctionName(), nullValue() );
+    assertThat( function.getParameterName(), is( "variable" ) );
+    assertThat( function.getParameterValue(), nullValue() );
+
+    function = new Function( " variable " );
+    assertThat( function.getFunctionName(), nullValue() );
+    assertThat( function.getParameterName(), is( "variable" ) );
+    assertThat( function.getParameterValue(), nullValue() );
+
+    function = new Function( "(variable)" );
+    assertThat( function.getFunctionName(), nullValue() );
+    assertThat( function.getParameterName(), is( "variable" ) );
+    assertThat( function.getParameterValue(), nullValue() );
+
+    function = new Function( " ( variable ) " );
+    assertThat( function.getFunctionName(), nullValue() );
+    assertThat( function.getParameterName(), is( "variable" ) );
+    assertThat( function.getParameterValue(), nullValue() );
+
+    function = new Function( "[literal]" );
+    assertThat( function.getFunctionName(), nullValue() );
+    assertThat( function.getParameterName(), nullValue() );
+    assertThat( function.getParameterValue(), contains( "literal" ) );
+
+    function = new Function( " [ literal ] " );
+    assertThat( function.getFunctionName(), nullValue() );
+    assertThat( function.getParameterName(), nullValue() );
+    assertThat( function.getParameterValue(), contains( "literal" ) );
+
+    function = new Function( "()" );
+    assertThat( function.getFunctionName(), nullValue() );
+    assertThat( function.getParameterName(), nullValue() );
+    assertThat( function.getParameterValue(), nullValue() );
+
+    function = new Function( "[]" );
+    assertThat( function.getFunctionName(), nullValue() );
+    assertThat( function.getParameterName(), nullValue() );
+    assertThat( function.getParameterValue(), nullValue() );
+
+    function = new Function( "$" );
+    assertThat( function.getFunctionName(), nullValue() );
+    assertThat( function.getParameterName(), nullValue() );
+    assertThat( function.getParameterValue(), nullValue() );
+
+    function = new Function( "$()" );
+    assertThat( function.getFunctionName(), nullValue() );
+    assertThat( function.getParameterName(), nullValue() );
+    assertThat( function.getParameterValue(), nullValue() );
+
+    function = new Function( "$[]" );
+    assertThat( function.getFunctionName(), nullValue() );
+    assertThat( function.getParameterName(), nullValue() );
+    assertThat( function.getParameterValue(), nullValue() );
+
+    function = new Function( "$function" );
+    assertThat( function.getFunctionName(), is( "function") );
+    assertThat( function.getParameterName(), nullValue() );
+    assertThat( function.getParameterValue(), nullValue() );
+
+    function = new Function( "$function(variable)" );
+    assertThat( function.getFunctionName(), is( "function" ) );
+    assertThat( function.getParameterName(), is( "variable" ) );
+    assertThat( function.getParameterValue(), nullValue() );
+
+    function = new Function( "$function[literal]" );
+    assertThat( function.getFunctionName(), is( "function") );
+    assertThat( function.getParameterName(), nullValue() );
+    assertThat( function.getParameterValue(), contains( "literal" ) );
+  }
+
+  @Test
+  public void testEvaluate() throws Exception {
+    TestResolver resolver = new TestResolver();
+    TestEvaluator evaluator = new TestEvaluator();
+    List<String> values;
+
+    values = Function.evaluate( "$test-func(test-variable)", resolver, evaluator );
+    assertThat( values, contains( "<test-func:resolve(test-variable)>" ) );
+
+    values = Function.evaluate( "$test-func[test-literal]", resolver, evaluator );
+    assertThat( values, contains( "<test-func:test-literal>" ) );
+
+    values = Function.evaluate( "test-variable", resolver, evaluator );
+    assertThat( values, contains( "resolve(test-variable)" ) );
+
+    values = Function.evaluate( "(test-variable)", resolver, evaluator );
+    assertThat( values, contains( "resolve(test-variable)" ) );
+
+    values = Function.evaluate( "[test-literal]", resolver, evaluator );
+    assertThat( values, contains( "test-literal" ) );
+  }
+
+  class TestResolver implements Resolver {
+
+    @Override
+    public List<String> resolve( String name ) {
+      return Arrays.asList( "resolve(" + name + ")" );
+    }
+
+  }
+
+  class TestEvaluator implements Evaluator {
+
+    @Override
+    public List<String> evaluate( String function, List<String> parameters ) {
+      List<String> result = new ArrayList<String>( parameters.size() );
+      for( String parameter : parameters ) {
+        result.add( "<" + function + ":" + parameter + ">" );
+      }
+      return result;
+    }
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/MatcherTest.java
----------------------------------------------------------------------
diff --git a/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/MatcherTest.java b/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/MatcherTest.java
index 7817271..0382326 100644
--- a/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/MatcherTest.java
+++ b/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/MatcherTest.java
@@ -53,6 +53,105 @@ public class MatcherTest {
   }
 
   @Test
+  public void testRootPathMatching() throws Exception {
+    Matcher<String> matcher;
+    Template patternTemplate, inputTemplate;
+    Matcher<String>.Match match;
+
+    ///////
+    patternTemplate = Parser.parse( "*://*:*" );
+    matcher = new Matcher<String>();
+    matcher.add( patternTemplate, "test-match" );
+
+    inputTemplate = Parser.parse( "test-scheme://test-host:42" );
+    match = matcher.match( inputTemplate );
+    assertThat( match, notNullValue() );
+    inputTemplate = Parser.parse( "test-scheme://test-host:42/" );
+    match = matcher.match( inputTemplate );
+    assertThat( match, notNullValue() );
+    inputTemplate = Parser.parse( "test-scheme://test-host:42/test-path" );
+    match = matcher.match( inputTemplate );
+    assertThat( match, nullValue() );
+
+    ///////
+    patternTemplate = Parser.parse( "*://*:*/" );
+    matcher = new Matcher<String>();
+    matcher.add( patternTemplate, "test-match" );
+
+    inputTemplate = Parser.parse( "test-scheme://test-host:42" );
+    match = matcher.match( inputTemplate );
+    assertThat( match, notNullValue() );
+    inputTemplate = Parser.parse( "test-scheme://test-host:42/" );
+    match = matcher.match( inputTemplate );
+    assertThat( match, notNullValue() );
+    inputTemplate = Parser.parse( "test-scheme://test-host:42/test-path" );
+    match = matcher.match( inputTemplate );
+    assertThat( match, nullValue() );
+
+    ///////
+    patternTemplate = Parser.parse( "*://*:*/*" );
+    matcher = new Matcher<String>();
+    matcher.add( patternTemplate, "test-match" );
+
+    inputTemplate = Parser.parse( "test-scheme://test-host:42" );
+    match = matcher.match( inputTemplate );
+    assertThat( match, nullValue() );
+    inputTemplate = Parser.parse( "test-scheme://test-host:42/" );
+    match = matcher.match( inputTemplate );
+    assertThat( match, nullValue() );
+    inputTemplate = Parser.parse( "test-scheme://test-host:42/test-path" );
+    match = matcher.match( inputTemplate );
+    assertThat( match, notNullValue() );
+
+    ///////
+    patternTemplate = Parser.parse( "*://*:*/**" );
+    matcher = new Matcher<String>();
+    matcher.add( patternTemplate, "test-match" );
+
+//KM: I'm not sure what the correct behavior is here.
+//    inputTemplate = Parser.parse( "test-scheme://test-host:42" );
+//    match = matcher.match( inputTemplate );
+//    assertThat( match, ? );
+//    inputTemplate = Parser.parse( "test-scheme://test-host:42/" );
+//    match = matcher.match( inputTemplate );
+//    assertThat( match, ? );
+    inputTemplate = Parser.parse( "test-scheme://test-host:42/test-path" );
+    match = matcher.match( inputTemplate );
+    assertThat( match, notNullValue() );
+
+    ///////
+    patternTemplate = Parser.parse( "*://*:*/{path=*}" );
+    matcher = new Matcher<String>();
+    matcher.add( patternTemplate, "test-match" );
+
+    inputTemplate = Parser.parse( "test-scheme://test-host:42" );
+    match = matcher.match( inputTemplate );
+    assertThat( match, nullValue() );
+    inputTemplate = Parser.parse( "test-scheme://test-host:42/" );
+    match = matcher.match( inputTemplate );
+    assertThat( match, nullValue() );
+    inputTemplate = Parser.parse( "test-scheme://test-host:42/test-path" );
+    match = matcher.match( inputTemplate );
+    assertThat( match, notNullValue() );
+
+    ///////
+    patternTemplate = Parser.parse( "*://*:*/{path=**}" );
+    matcher = new Matcher<String>();
+    matcher.add( patternTemplate, "test-match" );
+
+//KM: I'm not sure what the correct behavior is here.
+//    inputTemplate = Parser.parse( "test-scheme://test-host:42" );
+//    match = matcher.match( inputTemplate );
+//    assertThat( match, ? );
+//    inputTemplate = Parser.parse( "test-scheme://test-host:42/" );
+//    match = matcher.match( inputTemplate );
+//    assertThat( match, ? );
+    inputTemplate = Parser.parse( "test-scheme://test-host:42/test-path" );
+    match = matcher.match( inputTemplate );
+    assertThat( match, notNullValue() );
+  }
+
+  @Test
   public void testTopLevelPathGlobMatch() throws Exception {
     Matcher<String> matcher;
     Template patternTemplate, inputTemplate;

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/ParserTest.java
----------------------------------------------------------------------
diff --git a/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/ParserTest.java b/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/ParserTest.java
index 82fb7d0..221b67c 100644
--- a/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/ParserTest.java
+++ b/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/ParserTest.java
@@ -901,25 +901,25 @@ public class ParserTest {
 
     assertThat( template, notNullValue() );
     assertThat( template.getQuery().get( "X" ), notNullValue() );
-    string = expander.expandToString( template, null );
+    string = expander.expandToString( template, null, null );
     assertThat( string, is( "*://*:*/**?X" ) );
 
     template = Parser.parse( "*://*:*/**?X=" );
     assertThat( template, notNullValue() );
     assertThat( template.getQuery().get( "X" ), notNullValue() );
-    string = expander.expandToString( template, null );
+    string = expander.expandToString( template, null, null );
     assertThat( string, is( "*://*:*/**?X" ) );
 
     template = Parser.parse( "http://localhost:62142/gateway/cluster/datanode/api/v1/tmp/GatewayWebHdfsFuncTest/testBasicHdfsUseCase/dir/file?aG9zdD1sb2NhbGhvc3QmcG9ydD02MjEzOSZvcD1DUkVBVEUmdXNlci5uYW1lPWhkZnM" );
     assertThat( template, notNullValue() );
     assertThat( template.getQuery().get( "aG9zdD1sb2NhbGhvc3QmcG9ydD02MjEzOSZvcD1DUkVBVEUmdXNlci5uYW1lPWhkZnM" ), notNullValue() );
-    string = expander.expandToString( template, null );
+    string = expander.expandToString( template, null, null );
     assertThat( string, is( "http://localhost:62142/gateway/cluster/datanode/api/v1/tmp/GatewayWebHdfsFuncTest/testBasicHdfsUseCase/dir/file?aG9zdD1sb2NhbGhvc3QmcG9ydD02MjEzOSZvcD1DUkVBVEUmdXNlci5uYW1lPWhkZnM" ) );
 
     template = Parser.parse( "http://localhost:62142/gateway/cluster/datanode/api/v1/tmp/GatewayWebHdfsFuncTest/testBasicHdfsUseCase/dir/file?aG9zdD1sb2NhbGhvc3QmcG9ydD02MjEzOSZvcD1DUkVBVEUmdXNlci5uYW1lPWhkZnM=" );
     assertThat( template, notNullValue() );
     assertThat( template.getQuery().get( "aG9zdD1sb2NhbGhvc3QmcG9ydD02MjEzOSZvcD1DUkVBVEUmdXNlci5uYW1lPWhkZnM" ), notNullValue() );
-    string = expander.expandToString( template, null );
+    string = expander.expandToString( template, null, null );
     assertThat( string, is( "http://localhost:62142/gateway/cluster/datanode/api/v1/tmp/GatewayWebHdfsFuncTest/testBasicHdfsUseCase/dir/file?aG9zdD1sb2NhbGhvc3QmcG9ydD02MjEzOSZvcD1DUkVBVEUmdXNlci5uYW1lPWhkZnM" ) );
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/RewriterTest.java
----------------------------------------------------------------------
diff --git a/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/RewriterTest.java b/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/RewriterTest.java
index 6117099..1e9b441 100644
--- a/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/RewriterTest.java
+++ b/gateway-util-urltemplate/src/test/java/org/apache/hadoop/gateway/util/urltemplate/RewriterTest.java
@@ -58,7 +58,7 @@ public class RewriterTest {
     outputTemplate = Parser.parse( "{scheme}://{host}:{port}" );
     // Copies the values extracted from the input URI via the inputTemplate and inserts them into the outputTemplate.
     // The resolver isn't used in this case.
-    outputUri = Rewriter.rewrite( inputUri, inputTemplate, outputTemplate, resolver );
+    outputUri = Rewriter.rewrite( inputUri, inputTemplate, outputTemplate, resolver, null );
     assertThat( outputUri.toString(), equalTo( "http://some-host:80" ) );
 
     // Need a syntax for the URL rewriter to tell it to take the value extracted from the inputUri
@@ -71,7 +71,7 @@ public class RewriterTest {
     inputUri = new URI( "http://some-known-host:80" );
     inputTemplate = Parser.parse( "{scheme}://{host}:{port}" );
     outputTemplate = Parser.parse( "{scheme}://{$host}:{port}" );
-    outputUri = Rewriter.rewrite( inputUri, inputTemplate, outputTemplate, resolver );
+    outputUri = Rewriter.rewrite( inputUri, inputTemplate, outputTemplate, resolver, null );
     assertThat( outputUri.toString(), equalTo( "http://some-other-host:80" ) );
 
     // What should happen if the param value cannot be resolved to something else?
@@ -80,7 +80,7 @@ public class RewriterTest {
     inputUri = new URI( "http://some-unknown-host:80" );
     inputTemplate = Parser.parse( "{scheme}://{host}:{port}" );
     outputTemplate = Parser.parse( "{scheme}://{$host}:{port}" );
-    outputUri = Rewriter.rewrite( inputUri, inputTemplate, outputTemplate, resolver );
+    outputUri = Rewriter.rewrite( inputUri, inputTemplate, outputTemplate, resolver, null );
     assertThat( outputUri.toString(), equalTo( "http://:80" ) );
 
     // Should there be another syntax that uses the original value if it cannot resolve the extracted value?
@@ -89,11 +89,30 @@ public class RewriterTest {
     inputUri = new URI( "http://some-unknown-host:80" );
     inputTemplate = Parser.parse( "{scheme}://{host}:{port}" );
     outputTemplate = Parser.parse( "{scheme}://{?host}:{port}" );
-    outputUri = Rewriter.rewrite( inputUri, inputTemplate, outputTemplate, resolver );
+    outputUri = Rewriter.rewrite( inputUri, inputTemplate, outputTemplate, resolver, null );
     assertThat( outputUri.toString(), equalTo( "http://some-unknown-host:80" ) );
   }
 
   @Test
+  public void testServiceRegistryHostmapUserCase() throws Exception {
+    Resolver resolver = EasyMock.createNiceMock( Resolver.class );
+    EasyMock.expect( resolver.resolve( "internal-host" ) ).andReturn( Arrays.asList( "internal-host" ) ).anyTimes();
+
+    Evaluator evaluator = EasyMock.createNiceMock( Evaluator.class );
+    EasyMock.expect( evaluator.evaluate( "hostmap", Arrays.asList( "internal-host" ) ) ).andReturn( Arrays.asList( "external-host" ) ).anyTimes();
+
+    EasyMock.replay( resolver, evaluator );
+
+    URI inputUri = new URI( "scheme://internal-host:777/path" );
+    Template inputMatch = Parser.parse( "{scheme}://{host}:{port}/{path=**}?{**}" );
+    Template outputTemplate = Parser.parse( "{scheme}://{$hostmap(host)}:{port}/{path=**}?&{**}" );
+
+    URI outputUri = Rewriter.rewrite( inputUri, inputMatch, outputTemplate, resolver, evaluator );
+
+    assertThat( outputUri.toString(), is( "scheme://external-host:777/path" ) );
+  }
+
+  @Test
   public void testBasicRewrite() throws Exception {
     URI inputUri, outputUri;
     Template inputTemplate, outputTemplate;
@@ -102,19 +121,19 @@ public class RewriterTest {
     inputUri = new URI( "path-1/path-2" );
     inputTemplate = Parser.parse( "{path-1-name}/{path-2-name}" );
     outputTemplate = Parser.parse( "{path-2-name}/{path-1-name}" );
-    outputUri = Rewriter.rewrite( inputUri, inputTemplate, outputTemplate, resolver );
+    outputUri = Rewriter.rewrite( inputUri, inputTemplate, outputTemplate, resolver, null );
     assertThat( outputUri.toString(), equalTo( "path-2/path-1" ) );
 
     inputUri = new URI( "path-1/path-2/path-3/path-4" );
     inputTemplate = Parser.parse( "path-1/{path=**}/path-4" ); // Need the ** to allow the expansion to include all path values.
     outputTemplate = Parser.parse( "new-path-1/{path=**}/new-path-4" );
-    outputUri = Rewriter.rewrite( inputUri, inputTemplate, outputTemplate, resolver );
+    outputUri = Rewriter.rewrite( inputUri, inputTemplate, outputTemplate, resolver, null );
     assertThat( outputUri.toString(), equalTo( "new-path-1/path-2/path-3/new-path-4" ) );
 
     inputUri = new URI( "some-path?query-name=some-queryParam-value" );
     inputTemplate = Parser.parse( "{path-name}?query-name={queryParam-value}" );
     outputTemplate = Parser.parse( "{queryParam-value}/{path-name}" );
-    outputUri = Rewriter.rewrite( inputUri, inputTemplate, outputTemplate, resolver );
+    outputUri = Rewriter.rewrite( inputUri, inputTemplate, outputTemplate, resolver, null );
     assertThat( outputUri.toString(), equalTo( "some-queryParam-value/some-path" ) );
   }
 
@@ -128,13 +147,13 @@ public class RewriterTest {
     inputTemplate = Parser.parse( "path?{**}" );
     outputTemplate = Parser.parse( "path?{**}" );
 
-    outputUri = Rewriter.rewrite( inputUri, inputTemplate, outputTemplate, params );
+    outputUri = Rewriter.rewrite( inputUri, inputTemplate, outputTemplate, params, null );
     assertThat( outputUri.toString(), equalTo( "path?query=value" ) );
 
     inputUri = new URI( "path?query=value" );
     inputTemplate = Parser.parse( "path?{*}" );
     outputTemplate = Parser.parse( "path?{*}" );
-    outputUri = Rewriter.rewrite( inputUri, inputTemplate, outputTemplate, params );
+    outputUri = Rewriter.rewrite( inputUri, inputTemplate, outputTemplate, params, null );
     assertThat( outputUri.toString(), equalTo( "path?query=value" ) );
   }
 
@@ -156,63 +175,63 @@ public class RewriterTest {
 //    sourcePattern = Parser.parse( "**" );
     sourcePattern = Parser.parse( "*://*:*/**" );
     targetPattern = Parser.parse( "should-not-change" );
-    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ) );
+    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ), null );
     expectOutput = new URI( "should-not-change" );
     assertThat( actualOutput, equalTo( expectOutput ) );
 
     actualInput = new URI( "http://some-host:0/some-path" );
     sourcePattern = Parser.parse( "*://*:*/{0=**}" );
     targetPattern = Parser.parse( "{0}" );
-    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ) );
+    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ), null );
     expectOutput = new URI( "some-path" );
     assertThat( actualOutput, equalTo( expectOutput ) );
 
     actualInput = new URI( "http://some-host:0/pathA/pathB/pathC" );
     sourcePattern = Parser.parse( "*://*:*/pathA/{1=*}/{2=*}" );
     targetPattern = Parser.parse( "http://some-other-host/{2}/{1}" );
-    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ) );
+    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ), null );
     expectOutput = new URI( "http://some-other-host/pathC/pathB" );
     assertThat( actualOutput, equalTo( expectOutput ) );
 
     actualInput = new URI( "http://some-host:0/some-path" );
     sourcePattern = Parser.parse( "*://*:*/**" );
     targetPattern = Parser.parse( "{filter-queryParam-name}" );
-    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ) );
+    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ), null );
     expectOutput = new URI( "filter-queryParam-value" );
     assertThat( actualOutput, equalTo( expectOutput ) );
 
     actualInput = new URI( "http://some-host:0/some-path" );
     sourcePattern = Parser.parse( "*://*:*/**" );
     targetPattern = Parser.parse( "{expect-queryParam-name}" );
-    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ) );
+    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ), null );
     expectOutput = new URI( "expect-queryParam-value" );
     assertThat( actualOutput, equalTo( expectOutput ) );
 
     actualInput = new URI( "http://some-host:0/some-path" );
     sourcePattern = Parser.parse( "*://*:*/**" );
     targetPattern = Parser.parse( "http://some-other-host/{filter-queryParam-name}/{expect-queryParam-name}" );
-    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ) );
+    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ), null );
     expectOutput = new URI( "http://some-other-host/filter-queryParam-value/expect-queryParam-value" );
     assertThat( actualOutput, equalTo( expectOutput ) );
 
     actualInput = new URI( "http://some-host:0/pathA/pathB/pathC" );
     sourcePattern = Parser.parse( "*://*:*/pathA/{1=*}/{2=*}" );
     targetPattern = Parser.parse( "http://some-other-host/{2}/{1}/{filter-queryParam-name}/{expect-queryParam-name}" );
-    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ) );
+    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ), null );
     expectOutput = new URI( "http://some-other-host/pathC/pathB/filter-queryParam-value/expect-queryParam-value" );
     assertThat( actualOutput, equalTo( expectOutput ) );
 
     actualInput = new URI( "/namenode/api/v1/test" );
     sourcePattern = Parser.parse( "/namenode/api/v1/{0=**}" );
     targetPattern = Parser.parse( "http://{filter-queryParam-name}/webhdfs/v1/{0}" );
-    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ) );
+    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ), null );
     expectOutput = new URI( "http://filter-queryParam-value/webhdfs/v1/test" );
     assertThat( actualOutput, equalTo( expectOutput ) );
 
     actualInput = new URI( "/namenode/api/v1/test" );
     sourcePattern = Parser.parse( "/namenode/api/v1/{0=**}" );
     targetPattern = Parser.parse( "http://{filter-queryParam-name}/webhdfs/v1/{0}" );
-    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ) );
+    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ), null );
     expectOutput = new URI( "http://filter-queryParam-value/webhdfs/v1/test" );
     assertThat( actualOutput, equalTo( expectOutput ) );
 
@@ -220,14 +239,14 @@ public class RewriterTest {
     expectOutput = new URI( "http://filter-queryParam-value/gatewaycluster/namenode/api/v1/test/file?op=CREATE&user.name=hdfs&overwrite=false" );
     sourcePattern = Parser.parse( "*://*:*/webhdfs/v1/{path=**}?op={op=*}&user.name={username=*}&overwrite={overwrite=*}" );
     targetPattern = Parser.parse( "http://{filter-queryParam-name}/gatewaycluster/namenode/api/v1/{path=**}?op={op}&user.name={username}&overwrite={overwrite}" );
-    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ) );
+    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ), null );
     assertThat( actualOutput, equalTo( expectOutput ) );
 
     actualInput = new URI( "/datanode/api/v1/test?user.name=hdfs&op=CREATE&overwrite=false&host=vm.home&port=50075" );
     expectOutput = new URI( "http://vm.home:50075/webhdfs/v1/test?op=CREATE&user.name=hdfs&overwrite=false" );
     sourcePattern = Parser.parse( "/datanode/api/v1/{path=**}?{host}&{port}&{**}" );
     targetPattern = Parser.parse( "http://{host}:{port}/webhdfs/v1/{path=**}?{**}" );
-    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ) );
+    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ), null );
     // Note: Had to change the order of the expected query params to match.
     // This is probably dependent upon iterator ordering and therefore might be a test issue.
     // Unfortunately URI.equals() doesn't ignore query queryParam order.
@@ -267,7 +286,7 @@ public class RewriterTest {
 
     actualInput = new URI( "http://vm.local:50075/webhdfs/v1/tmp/GatewayWebHdfsFuncTest/dirA700/fileA700?op=CREATE&user.name=hdfs&overwrite=false&permission=700" );
     expectOutput = new URI( "http://gw:8888/gateway/cluster/datanode/api/v1/tmp/GatewayWebHdfsFuncTest/dirA700/fileA700?host=vm.local&port=50075&op=CREATE&user.name=hdfs&overwrite=false&permission=700" );
-    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ) );
+    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ), null );
     assertThat( actualOutput, equalTo( expectOutput ) );
   }
 
@@ -288,7 +307,7 @@ public class RewriterTest {
 
     actualInput = new URI( "/datanode/api/v1/tmp/GatewayWebHdfsFuncTest/dirA700/fileA700?host=vm.local&port=50075&op=CREATE&user.name=hdfs&overwrite=false&permission=700" );
     expectOutput = new URI( "http://vm.local:50075/webhdfs/v1/tmp/GatewayWebHdfsFuncTest/dirA700/fileA700?op=CREATE&user.name=hdfs&overwrite=false&permission=700" );
-    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ) );
+    actualOutput = Rewriter.rewrite( actualInput, sourcePattern, targetPattern, new TestResolver( config, request ), null );
     assertThat( actualOutput, equalTo( expectOutput ) );
   }
 
@@ -303,7 +322,7 @@ public class RewriterTest {
     actualInput = new URI( "http://host:42/pathA/pathB" );
     expectOutput = new URI( "http://host:777/test-output/pathA/pathB" );
 
-    actualOutput = Rewriter.rewrite( actualInput, inputTemplate, outputTemplate, null );
+    actualOutput = Rewriter.rewrite( actualInput, inputTemplate, outputTemplate, null, null );
 
     assertThat( actualOutput, is( expectOutput ) );
   }
@@ -347,6 +366,7 @@ public class RewriterTest {
 
       return values;
     }
+
   }
 
 }


[2/3] KNOX-127: Use hostmap in some service registry rewrite functions.

Posted by km...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedHostFunctionProcessorTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedHostFunctionProcessorTest.java b/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedHostFunctionProcessorTest.java
new file mode 100644
index 0000000..e38442a
--- /dev/null
+++ b/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedHostFunctionProcessorTest.java
@@ -0,0 +1,148 @@
+/**
+ * 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.svcregfunc.impl;
+
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteEnvironment;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriter;
+import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteContext;
+import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
+import org.apache.hadoop.gateway.services.GatewayServices;
+import org.apache.hadoop.gateway.services.hostmap.HostMapper;
+import org.apache.hadoop.gateway.services.hostmap.HostMapperService;
+import org.apache.hadoop.gateway.services.registry.ServiceRegistry;
+import org.apache.hadoop.gateway.svcregfunc.api.ServiceMappedHostFunctionDescriptor;
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.ServiceLoader;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
+import static org.junit.Assert.fail;
+
+public class ServiceMappedHostFunctionProcessorTest {
+
+  HostMapperService hms;
+  HostMapper hm;
+  ServiceRegistry reg;
+  GatewayServices svc;
+  UrlRewriteEnvironment env;
+  UrlRewriteContext ctx;
+  ServiceMappedHostFunctionDescriptor desc;
+
+  @Before
+  public void setUp() {
+    hm = EasyMock.createNiceMock( HostMapper.class );
+    EasyMock.expect( hm.resolveInboundHostName( "test-host" ) ).andReturn( "test-internal-host" ).anyTimes();
+
+    hms = EasyMock.createNiceMock( HostMapperService.class );
+    EasyMock.expect( hms.getHostMapper( "test-cluster" ) ).andReturn( hm ).anyTimes();
+
+    reg = EasyMock.createNiceMock( ServiceRegistry.class );
+    EasyMock.expect( reg.lookupServiceURL( "test-cluster", "test-service" ) ).andReturn( "test-scheme://test-host:777/test-path" ).anyTimes();
+
+    svc = EasyMock.createNiceMock( GatewayServices.class );
+    EasyMock.expect( svc.getService( GatewayServices.SERVICE_REGISTRY_SERVICE ) ).andReturn( reg ).anyTimes();
+    EasyMock.expect( svc.getService( GatewayServices.HOST_MAPPING_SERVICE ) ).andReturn( hms ).anyTimes();
+
+    env = EasyMock.createNiceMock( UrlRewriteEnvironment.class );
+    EasyMock.expect( env.getAttribute( GatewayServices.GATEWAY_SERVICES_ATTRIBUTE ) ).andReturn( svc ).anyTimes();
+    EasyMock.expect( env.getAttribute( GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE ) ).andReturn( "test-cluster" ).anyTimes();
+
+    ctx = EasyMock.createNiceMock( UrlRewriteContext.class );
+    EasyMock.expect( ctx.getDirection() ).andReturn( UrlRewriter.Direction.IN ).anyTimes();
+
+    desc = EasyMock.createNiceMock( ServiceMappedHostFunctionDescriptor.class );
+
+    EasyMock.replay( hm, hms, reg, svc, env, desc, ctx );
+  }
+
+  @Test
+  public void testServiceLoader() throws Exception {
+    ServiceLoader loader = ServiceLoader.load( UrlRewriteFunctionProcessor.class );
+    Iterator iterator = loader.iterator();
+    assertThat( "Service iterator empty.", iterator.hasNext() );
+    while( iterator.hasNext() ) {
+      Object object = iterator.next();
+      if( object instanceof ServiceMappedHostFunctionProcessor ) {
+        return;
+      }
+    }
+    fail( "Failed to find " + ServiceMappedHostFunctionProcessor.class.getName() + " via service loader." );
+  }
+
+  @Test
+  public void testName() throws Exception {
+    ServiceMappedHostFunctionProcessor func = new ServiceMappedHostFunctionProcessor();
+    assertThat( func.name(), is( "serviceMappedHost" ) );
+  }
+
+  @Test
+  public void testInitialize() throws Exception {
+    ServiceMappedHostFunctionProcessor func = new ServiceMappedHostFunctionProcessor();
+    try {
+      func.initialize( null, desc );
+      fail( "Should have thrown an IllegalArgumentException" );
+    } catch( IllegalArgumentException e ) {
+      assertThat( e.getMessage(), containsString( "environment" ) );
+    }
+
+    func = new ServiceMappedHostFunctionProcessor();
+    try {
+      func.initialize( env, null );
+    } catch( Exception e ) {
+      e.printStackTrace();
+      fail( "Should not have thrown an exception" );
+    }
+
+    func.initialize( env, desc );
+
+    assertThat( func.cluster(), is( "test-cluster" ) );
+    assertThat( func.registry(), sameInstance( reg ) );
+  }
+
+  @Test
+  public void testDestroy() throws Exception {
+    ServiceMappedHostFunctionProcessor func = new ServiceMappedHostFunctionProcessor();
+    func.initialize( env, desc );
+    func.destroy();
+
+    assertThat( func.cluster(), nullValue() );
+    assertThat( func.registry(), nullValue() );
+  }
+
+  @Test
+  public void testResolve() throws Exception {
+    ServiceMappedHostFunctionProcessor func = new ServiceMappedHostFunctionProcessor();
+    func.initialize( env, desc );
+
+    assertThat( func.resolve( ctx, Arrays.asList( "test-service" ) ), contains( "test-internal-host" ) );
+    assertThat( func.resolve( ctx, Arrays.asList( "invalid-test-service" ) ), contains( "invalid-test-service" ) );
+    assertThat( func.resolve( ctx, null ), nullValue() );
+
+    func.destroy();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedUrlFunctionProcessorTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedUrlFunctionProcessorTest.java b/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedUrlFunctionProcessorTest.java
new file mode 100644
index 0000000..5d01f5d
--- /dev/null
+++ b/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedUrlFunctionProcessorTest.java
@@ -0,0 +1,148 @@
+/**
+ * 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.svcregfunc.impl;
+
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteEnvironment;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriter;
+import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteContext;
+import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
+import org.apache.hadoop.gateway.services.GatewayServices;
+import org.apache.hadoop.gateway.services.hostmap.HostMapper;
+import org.apache.hadoop.gateway.services.hostmap.HostMapperService;
+import org.apache.hadoop.gateway.services.registry.ServiceRegistry;
+import org.apache.hadoop.gateway.svcregfunc.api.ServiceMappedUrlFunctionDescriptor;
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.ServiceLoader;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
+import static org.junit.Assert.fail;
+
+public class ServiceMappedUrlFunctionProcessorTest {
+
+  HostMapperService hms;
+  HostMapper hm;
+  ServiceRegistry reg;
+  GatewayServices svc;
+  UrlRewriteEnvironment env;
+  UrlRewriteContext ctx;
+  ServiceMappedUrlFunctionDescriptor desc;
+
+  @Before
+  public void setUp() {
+    hm = EasyMock.createNiceMock( HostMapper.class );
+    EasyMock.expect( hm.resolveInboundHostName( "test-host" ) ).andReturn( "test-internal-host" ).anyTimes();
+
+    hms = EasyMock.createNiceMock( HostMapperService.class );
+    EasyMock.expect( hms.getHostMapper( "test-cluster" ) ).andReturn( hm ).anyTimes();
+
+    reg = EasyMock.createNiceMock( ServiceRegistry.class );
+    EasyMock.expect( reg.lookupServiceURL( "test-cluster", "test-service" ) ).andReturn( "test-scheme://test-host:777/test-path" ).anyTimes();
+
+    svc = EasyMock.createNiceMock( GatewayServices.class );
+    EasyMock.expect( svc.getService( GatewayServices.SERVICE_REGISTRY_SERVICE ) ).andReturn( reg ).anyTimes();
+    EasyMock.expect( svc.getService( GatewayServices.HOST_MAPPING_SERVICE ) ).andReturn( hms ).anyTimes();
+
+    env = EasyMock.createNiceMock( UrlRewriteEnvironment.class );
+    EasyMock.expect( env.getAttribute( GatewayServices.GATEWAY_SERVICES_ATTRIBUTE ) ).andReturn( svc ).anyTimes();
+    EasyMock.expect( env.getAttribute( GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE ) ).andReturn( "test-cluster" ).anyTimes();
+
+    ctx = EasyMock.createNiceMock( UrlRewriteContext.class );
+    EasyMock.expect( ctx.getDirection() ).andReturn( UrlRewriter.Direction.IN ).anyTimes();
+
+    desc = EasyMock.createNiceMock( ServiceMappedUrlFunctionDescriptor.class );
+
+    EasyMock.replay( hm, hms, reg, svc, env, desc, ctx );
+  }
+
+  @Test
+  public void testServiceLoader() throws Exception {
+    ServiceLoader loader = ServiceLoader.load( UrlRewriteFunctionProcessor.class );
+    Iterator iterator = loader.iterator();
+    assertThat( "Service iterator empty.", iterator.hasNext() );
+    while( iterator.hasNext() ) {
+      Object object = iterator.next();
+      if( object instanceof ServiceMappedUrlFunctionProcessor ) {
+        return;
+      }
+    }
+    fail( "Failed to find " + ServiceMappedUrlFunctionProcessor.class.getName() + " via service loader." );
+  }
+
+  @Test
+  public void testName() throws Exception {
+    ServiceMappedUrlFunctionProcessor func = new ServiceMappedUrlFunctionProcessor();
+    assertThat( func.name(), is( "serviceMappedUrl" ) );
+  }
+
+  @Test
+  public void testInitialize() throws Exception {
+    ServiceMappedUrlFunctionProcessor func = new ServiceMappedUrlFunctionProcessor();
+    try {
+      func.initialize( null, desc );
+      fail( "Should have thrown an IllegalArgumentException" );
+    } catch( IllegalArgumentException e ) {
+      assertThat( e.getMessage(), containsString( "environment" ) );
+    }
+
+    func = new ServiceMappedUrlFunctionProcessor();
+    try {
+      func.initialize( env, null );
+    } catch( Exception e ) {
+      e.printStackTrace(); //NOTE: OK to use e.printStackTrace for a test failure.
+      fail( "Should not have thrown an exception" );
+    }
+
+    func.initialize( env, desc );
+
+    assertThat( func.cluster(), is( "test-cluster" ) );
+    assertThat( func.registry(), sameInstance( reg ) );
+  }
+
+  @Test
+  public void testDestroy() throws Exception {
+    ServiceMappedUrlFunctionProcessor func = new ServiceMappedUrlFunctionProcessor();
+    func.initialize( env, desc );
+    func.destroy();
+
+    assertThat( func.cluster(), nullValue() );
+    assertThat( func.registry(), nullValue() );
+  }
+
+  @Test
+  public void testResolve() throws Exception {
+    ServiceMappedUrlFunctionProcessor func = new ServiceMappedUrlFunctionProcessor();
+    func.initialize( env, desc );
+
+    assertThat( func.resolve( ctx, Arrays.asList( "test-service" ) ), contains( "test-scheme://test-internal-host:777/test-path" ) );
+    assertThat( func.resolve( ctx, Arrays.asList( "invalid-test-service" ) ), contains( "invalid-test-service" ) );
+    assertThat( func.resolve( ctx, null ), nullValue() );
+
+    func.destroy();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServicePathFunctionProcessorTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServicePathFunctionProcessorTest.java b/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServicePathFunctionProcessorTest.java
index ce554ad..fc344ae 100644
--- a/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServicePathFunctionProcessorTest.java
+++ b/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServicePathFunctionProcessorTest.java
@@ -22,13 +22,12 @@ import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteContext;
 import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
 import org.apache.hadoop.gateway.services.GatewayServices;
 import org.apache.hadoop.gateway.services.registry.ServiceRegistry;
-import org.apache.hadoop.gateway.svcregfunc.api.ServiceAddressFunctionDescriptor;
 import org.apache.hadoop.gateway.svcregfunc.api.ServicePathFunctionDescriptor;
-import org.apache.hadoop.gateway.svcregfunc.api.ServiceSchemeFunctionDescriptor;
 import org.easymock.EasyMock;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.ServiceLoader;
 
@@ -37,6 +36,7 @@ import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.CoreMatchers.sameInstance;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
 import static org.junit.Assert.fail;
 
 public class ServicePathFunctionProcessorTest {
@@ -126,7 +126,7 @@ public class ServicePathFunctionProcessorTest {
     func.initialize( env, desc );
 
 //    assertThat( func.resolve( ctx, "test-service" ), is( "/test-path" ) );
-    assertThat( func.resolve( ctx, "invalid-test-service" ), is( "invalid-test-service" ) );
+    assertThat( func.resolve( ctx, Arrays.asList( "invalid-test-service" ) ), contains( "invalid-test-service" ) );
 //    assertThat( func.resolve( ctx, null ), nullValue() );
 
     func.destroy();

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServicePortFunctionProcessorTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServicePortFunctionProcessorTest.java b/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServicePortFunctionProcessorTest.java
index 29c993d..60ee9d7 100644
--- a/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServicePortFunctionProcessorTest.java
+++ b/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServicePortFunctionProcessorTest.java
@@ -22,13 +22,12 @@ import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteContext;
 import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
 import org.apache.hadoop.gateway.services.GatewayServices;
 import org.apache.hadoop.gateway.services.registry.ServiceRegistry;
-import org.apache.hadoop.gateway.svcregfunc.api.ServiceAddressFunctionDescriptor;
 import org.apache.hadoop.gateway.svcregfunc.api.ServicePortFunctionDescriptor;
-import org.apache.hadoop.gateway.svcregfunc.api.ServiceSchemeFunctionDescriptor;
 import org.easymock.EasyMock;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.ServiceLoader;
 
@@ -37,6 +36,7 @@ import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.CoreMatchers.sameInstance;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
 import static org.junit.Assert.fail;
 
 public class ServicePortFunctionProcessorTest {
@@ -125,8 +125,8 @@ public class ServicePortFunctionProcessorTest {
     ServicePortFunctionProcessor func = new ServicePortFunctionProcessor();
     func.initialize( env, desc );
 
-    assertThat( func.resolve( ctx, "test-service" ), is( "777" ) );
-    assertThat( func.resolve( ctx, "invalid-test-service" ), is( "invalid-test-service" ) );
+    assertThat( func.resolve( ctx, Arrays.asList( "test-service" ) ), contains( "777" ) );
+    assertThat( func.resolve( ctx, Arrays.asList( "invalid-test-service" ) ), contains( "invalid-test-service" ) );
     assertThat( func.resolve( ctx, null ), nullValue() );
 
     func.destroy();

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceSchemeFunctionProcessorTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceSchemeFunctionProcessorTest.java b/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceSchemeFunctionProcessorTest.java
index 021455a..f99e478 100644
--- a/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceSchemeFunctionProcessorTest.java
+++ b/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceSchemeFunctionProcessorTest.java
@@ -22,12 +22,12 @@ import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteContext;
 import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
 import org.apache.hadoop.gateway.services.GatewayServices;
 import org.apache.hadoop.gateway.services.registry.ServiceRegistry;
-import org.apache.hadoop.gateway.svcregfunc.api.ServiceAddressFunctionDescriptor;
 import org.apache.hadoop.gateway.svcregfunc.api.ServiceSchemeFunctionDescriptor;
 import org.easymock.EasyMock;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.ServiceLoader;
 
@@ -36,6 +36,7 @@ import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.CoreMatchers.sameInstance;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
 import static org.junit.Assert.fail;
 
 public class ServiceSchemeFunctionProcessorTest {
@@ -124,8 +125,8 @@ public class ServiceSchemeFunctionProcessorTest {
     ServiceSchemeFunctionProcessor func = new ServiceSchemeFunctionProcessor();
     func.initialize( env, desc );
 
-    assertThat( func.resolve( ctx, "test-service" ), is( "test-scheme" ) );
-    assertThat( func.resolve( ctx, "invalid-test-service" ), is( "invalid-test-service" ) );
+    assertThat( func.resolve( ctx, Arrays.asList( "test-service" ) ), contains( "test-scheme" ) );
+    assertThat( func.resolve( ctx, Arrays.asList( "invalid-test-service" ) ), contains( "invalid-test-service" ) );
     assertThat( func.resolve( ctx, null ), nullValue() );
 
     func.destroy();

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceUrlFunctionProcessorTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceUrlFunctionProcessorTest.java b/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceUrlFunctionProcessorTest.java
index b7e1dfe..b04c2c1 100644
--- a/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceUrlFunctionProcessorTest.java
+++ b/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceUrlFunctionProcessorTest.java
@@ -18,29 +18,34 @@
 package org.apache.hadoop.gateway.svcregfunc.impl;
 
 import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteEnvironment;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriter;
 import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteContext;
 import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
 import org.apache.hadoop.gateway.services.GatewayServices;
+import org.apache.hadoop.gateway.services.hostmap.HostMapper;
+import org.apache.hadoop.gateway.services.hostmap.HostMapperService;
 import org.apache.hadoop.gateway.services.registry.ServiceRegistry;
-import org.apache.hadoop.gateway.svcregfunc.api.ServiceAddressFunctionDescriptor;
-import org.apache.hadoop.gateway.svcregfunc.api.ServiceSchemeFunctionDescriptor;
 import org.apache.hadoop.gateway.svcregfunc.api.ServiceUrlFunctionDescriptor;
 import org.easymock.EasyMock;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.ServiceLoader;
 
 import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.CoreMatchers.sameInstance;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
 import static org.junit.Assert.fail;
 
 public class ServiceUrlFunctionProcessorTest {
 
+  HostMapperService hms;
+  HostMapper hm;
   ServiceRegistry reg;
   GatewayServices svc;
   UrlRewriteEnvironment env;
@@ -49,21 +54,29 @@ public class ServiceUrlFunctionProcessorTest {
 
   @Before
   public void setUp() {
+    hm = EasyMock.createNiceMock( HostMapper.class );
+    EasyMock.expect( hm.resolveInboundHostName( "test-host" ) ).andReturn( "test-internal-host" ).anyTimes();
+
+    hms = EasyMock.createNiceMock( HostMapperService.class );
+    EasyMock.expect( hms.getHostMapper( "test-cluster" ) ).andReturn( hm ).anyTimes();
+
     reg = EasyMock.createNiceMock( ServiceRegistry.class );
     EasyMock.expect( reg.lookupServiceURL( "test-cluster", "test-service" ) ).andReturn( "test-scheme://test-host:777/test-path" ).anyTimes();
 
     svc = EasyMock.createNiceMock( GatewayServices.class );
     EasyMock.expect( svc.getService( GatewayServices.SERVICE_REGISTRY_SERVICE ) ).andReturn( reg ).anyTimes();
+    EasyMock.expect( svc.getService( GatewayServices.HOST_MAPPING_SERVICE ) ).andReturn( hms ).anyTimes();
 
     env = EasyMock.createNiceMock( UrlRewriteEnvironment.class );
     EasyMock.expect( env.getAttribute( GatewayServices.GATEWAY_SERVICES_ATTRIBUTE ) ).andReturn( svc ).anyTimes();
     EasyMock.expect( env.getAttribute( GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE ) ).andReturn( "test-cluster" ).anyTimes();
 
     ctx = EasyMock.createNiceMock( UrlRewriteContext.class );
+    EasyMock.expect( ctx.getDirection() ).andReturn( UrlRewriter.Direction.IN ).anyTimes();
 
     desc = EasyMock.createNiceMock( ServiceUrlFunctionDescriptor.class );
 
-    EasyMock.replay( reg, svc, env, desc, ctx );
+    EasyMock.replay( hm, hms, reg, svc, env, desc, ctx );
   }
 
   @Test
@@ -125,8 +138,8 @@ public class ServiceUrlFunctionProcessorTest {
     ServiceUrlFunctionProcessor func = new ServiceUrlFunctionProcessor();
     func.initialize( env, desc );
 
-    assertThat( func.resolve( ctx, "test-service" ), is( "test-scheme://test-host:777/test-path" ) );
-    assertThat( func.resolve( ctx, "invalid-test-service" ), is( "invalid-test-service" ) );
+    assertThat( func.resolve( ctx, Arrays.asList( "test-service" ) ), contains( "test-scheme://test-host:777/test-path" ) );
+    assertThat( func.resolve( ctx, Arrays.asList( "invalid-test-service" ) ), contains( "invalid-test-service" ) );
     assertThat( func.resolve( ctx, null ), nullValue() );
 
     func.destroy();

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteProcessor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteProcessor.java b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteProcessor.java
index a6efaf0..0b7c62c 100644
--- a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteProcessor.java
+++ b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteProcessor.java
@@ -20,7 +20,6 @@ package org.apache.hadoop.gateway.filter.rewrite.api;
 import org.apache.hadoop.gateway.filter.rewrite.i18n.UrlRewriteMessages;
 import org.apache.hadoop.gateway.filter.rewrite.impl.UrlRewriteContextImpl;
 import org.apache.hadoop.gateway.filter.rewrite.impl.UrlRewriteFunctionProcessorFactory;
-import org.apache.hadoop.gateway.filter.rewrite.impl.UrlRewriteFunctionResolver;
 import org.apache.hadoop.gateway.filter.rewrite.impl.UrlRewriteStepProcessorHolder;
 import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteContext;
 import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
@@ -30,10 +29,8 @@ import org.apache.hadoop.gateway.util.urltemplate.Matcher;
 import org.apache.hadoop.gateway.util.urltemplate.Resolver;
 import org.apache.hadoop.gateway.util.urltemplate.Template;
 
-import java.util.ArrayList;
 import java.util.EnumSet;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 import static org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriter.Direction.IN;
@@ -124,8 +121,7 @@ public class UrlRewriteProcessor implements UrlRewriter {
   }
 
   @Override
-  public Template rewrite(
-      Resolver resolver, Template inputUri, Direction direction, String ruleName ) {
+  public Template rewrite( Resolver resolver, Template inputUri, Direction direction, String ruleName ) {
     Template outputUri = inputUri;
     UrlRewriteStepProcessorHolder stepHolder = null;
     if( ruleName == null || "*".equals( ruleName ) ) {
@@ -145,8 +141,7 @@ public class UrlRewriteProcessor implements UrlRewriter {
       stepHolder = rules.get( ruleName );
     }
     if( stepHolder != null ) {
-      UrlRewriteFunctionResolver function = new UrlRewriteFunctionResolver( functions, resolver );
-      UrlRewriteContext context = new UrlRewriteContextImpl( environment, function, direction, inputUri );
+      UrlRewriteContext context = new UrlRewriteContextImpl( environment, resolver, functions, direction, inputUri );
       try {
         UrlRewriteStepStatus stepStatus = stepHolder.process( context );
         if( UrlRewriteStepStatus.SUCCESS == stepStatus ) {

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/ext/UrlRewriteActionRewriteProcessorExt.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/ext/UrlRewriteActionRewriteProcessorExt.java b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/ext/UrlRewriteActionRewriteProcessorExt.java
index e1ca859..d0785a6 100644
--- a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/ext/UrlRewriteActionRewriteProcessorExt.java
+++ b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/ext/UrlRewriteActionRewriteProcessorExt.java
@@ -44,7 +44,7 @@ public class UrlRewriteActionRewriteProcessorExt
 
   @Override
   public UrlRewriteStepStatus process( UrlRewriteContext context ) throws Exception {
-    Template rewritten = expander.expandToTemplate( template, context.getParameters() );
+    Template rewritten = expander.expandToTemplate( template, context.getParameters(), context.getEvaluator() );
     context.setCurrentUrl( rewritten );
     return UrlRewriteStepStatus.SUCCESS;
   }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteContextImpl.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteContextImpl.java b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteContextImpl.java
index 75963eb..57e54c0 100644
--- a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteContextImpl.java
+++ b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteContextImpl.java
@@ -21,12 +21,13 @@ import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteEnvironment;
 import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriter;
 import org.apache.hadoop.gateway.filter.rewrite.i18n.UrlRewriteMessages;
 import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteContext;
-import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteResolver;
+import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
 import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
+import org.apache.hadoop.gateway.util.urltemplate.Evaluator;
 import org.apache.hadoop.gateway.util.urltemplate.Params;
+import org.apache.hadoop.gateway.util.urltemplate.Resolver;
 import org.apache.hadoop.gateway.util.urltemplate.Template;
 
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -37,7 +38,9 @@ public class UrlRewriteContextImpl implements UrlRewriteContext {
   private static final UrlRewriteMessages LOG = MessagesFactory.get( UrlRewriteMessages.class );
 
   private UrlRewriteEnvironment environment;
-  private UrlRewriteResolver resolver;
+  private Resolver resolver;
+  private Evaluator evaluator;
+  private Map<String,UrlRewriteFunctionProcessor> functions;
   private ContextParameters params;
   private UrlRewriter.Direction direction;
   private Template originalUrl;
@@ -45,12 +48,15 @@ public class UrlRewriteContextImpl implements UrlRewriteContext {
 
   public UrlRewriteContextImpl(
       UrlRewriteEnvironment environment,
-      UrlRewriteResolver resolver,
+      Resolver resolver,
+      Map<String,UrlRewriteFunctionProcessor> functions,
       UrlRewriter.Direction direction,
       Template url ) {
     this.environment = environment;
     this.resolver = resolver;
+    this.functions = functions;
     this.params = new ContextParameters();
+    this.evaluator = new ContextEvaluator();
     this.direction = direction;
     this.originalUrl = url;
     this.currentUrl = url;
@@ -86,6 +92,11 @@ public class UrlRewriteContextImpl implements UrlRewriteContext {
     return params;
   }
 
+  @Override
+  public Evaluator getEvaluator() {
+    return evaluator;
+  }
+
   private class ContextParameters implements Params {
 
     Map<String,List<String>> map = new HashMap<String,List<String>>();
@@ -97,14 +108,12 @@ public class UrlRewriteContextImpl implements UrlRewriteContext {
 
     @Override
     public List<String> resolve( String name ) {
-      List<String> values = map.get( name ); // Try to fine the name in the context map.
+      List<String> values = map.get( name ); // Try to find the name in the context map.
       if( values == null ) {
         try {
-          String value = resolver.resolve( UrlRewriteContextImpl.this, name );
-          if( value != null ) {
-            values = Arrays.asList( value ); // Try to fine the name in the resolver chain.
-          } else {
-            values = environment.resolve( name ); // Try to fine the name in the environment.
+          values = resolver.resolve( name );
+          if( values == null ) {
+            values = environment.resolve( name ); // Try to find the name in the environment.
           }
         } catch( Exception e ) {
           LOG.failedToFindValuesByParameter( name, e );
@@ -122,4 +131,22 @@ public class UrlRewriteContextImpl implements UrlRewriteContext {
 
   }
 
+  private class ContextEvaluator implements Evaluator {
+
+    @Override
+    public List<String> evaluate( String function, List<String> parameters ) {
+      List<String> results = null;
+      UrlRewriteFunctionProcessor processor = functions.get( function );
+      if( processor != null ) {
+        try {
+          results = processor.resolve( UrlRewriteContextImpl.this, parameters );
+        } catch( Exception e ) {
+          LOG.failedToInvokeRewriteFunction( function, e );
+          results = null;
+        }
+      }
+      return results;
+    }
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteFunctionResolver.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteFunctionResolver.java b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteFunctionResolver.java
deleted file mode 100644
index be65591..0000000
--- a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteFunctionResolver.java
+++ /dev/null
@@ -1,115 +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.filter.rewrite.impl;
-
-import org.apache.hadoop.gateway.filter.rewrite.i18n.UrlRewriteMessages;
-import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteContext;
-import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
-import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteResolver;
-import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
-import org.apache.hadoop.gateway.util.urltemplate.Resolver;
-
-import java.util.List;
-import java.util.Map;
-import java.util.StringTokenizer;
-
-public class UrlRewriteFunctionResolver implements UrlRewriteResolver {
-
-  private static final UrlRewriteMessages LOG = MessagesFactory.get( UrlRewriteMessages.class );
-
-  private Map<String,UrlRewriteFunctionProcessor> functions;
-  private Resolver delegate;
-  private enum TokenType { FUNCTION, DIRECT_PARAMETER, INDIRECT_PARAMETER}
-
-  public UrlRewriteFunctionResolver( Map<String,UrlRewriteFunctionProcessor> functions, Resolver delegate ) {
-    this.functions = functions;
-    this.delegate = delegate;
-  }
-
-  @Override
-  public String resolve( UrlRewriteContext context, String parameter ) throws Exception {
-//    System.out.println( "RESOLVE: " + parameter );
-    String value = null;
-    String function = null;
-    if( parameter != null && parameter.startsWith( "$" ) ) {
-      StringTokenizer parser = new StringTokenizer( parameter, "$()[]", true );
-      parser.nextToken(); // Consume the $
-      TokenType tokenType = TokenType.FUNCTION;
-      while( parser.hasMoreTokens() ) {
-        String token = parser.nextToken();
-        //Note: Currently () implies a variable parameter and [] a constant parameter.
-        if( "(".equals( token ) ) {
-          tokenType = TokenType.INDIRECT_PARAMETER;
-        } else if( "[".equals( token ) ) {
-          tokenType = TokenType.DIRECT_PARAMETER;
-        } else if ( ")".equals( token ) ) {
-          break;
-        } else if( "]".equals( token ) ) {
-          break;
-        } else if( tokenType.equals( TokenType.FUNCTION ) ) {
-          function = token;
-        } else {
-          parameter = token;
-        }
-      }
-      if( tokenType.equals( TokenType.INDIRECT_PARAMETER ) ) {
-        value = getFirstValue( context.getParameters().resolve( parameter ) );
-        if( value != null ) {
-          parameter = value;
-        } else {
-          parameter = invokeDelegate( parameter );
-        }
-      }
-      value = invokeFunction( context, function, parameter );
-    } else {
-      value = getFirstValue( delegate.resolve( parameter ) );
-    }
-    return value;
-  }
-
-  private String invokeFunction( UrlRewriteContext context, String function, String parameter ) {
-    String value = parameter;
-    if( function != null ) {
-      UrlRewriteResolver resolver = functions.get( function );
-      if( resolver != null ) {
-        try {
-          value = resolver.resolve( context, parameter );
-        } catch( Exception e ) {
-          LOG.failedToInvokeRewriteFunction( function, e );
-          // Ignore it and use the original parameter values.
-        }
-      }
-    }
-    return value;
-  }
-
-  private String invokeDelegate( String parameter ) {
-    List<String> values = delegate.resolve( parameter );
-    String value = getFirstValue( values );
-    return value;
-  }
-
-  private static String getFirstValue( List<String> values ) {
-    String value = null;
-    if( values != null && !values.isEmpty() ) {
-      value = values.get( 0 );
-    }
-    return value;
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/spi/UrlRewriteContext.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/spi/UrlRewriteContext.java b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/spi/UrlRewriteContext.java
index 193d1b3..5fe99a4 100644
--- a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/spi/UrlRewriteContext.java
+++ b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/spi/UrlRewriteContext.java
@@ -18,6 +18,7 @@
 package org.apache.hadoop.gateway.filter.rewrite.spi;
 
 import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriter;
+import org.apache.hadoop.gateway.util.urltemplate.Evaluator;
 import org.apache.hadoop.gateway.util.urltemplate.Params;
 import org.apache.hadoop.gateway.util.urltemplate.Template;
 
@@ -35,4 +36,6 @@ public interface UrlRewriteContext {
 
   Params getParameters();
 
+  Evaluator getEvaluator();
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/spi/UrlRewriteResolver.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/spi/UrlRewriteResolver.java b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/spi/UrlRewriteResolver.java
index 8b51dc3..ec07b5b 100644
--- a/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/spi/UrlRewriteResolver.java
+++ b/gateway-provider-rewrite/src/main/java/org/apache/hadoop/gateway/filter/rewrite/spi/UrlRewriteResolver.java
@@ -17,8 +17,10 @@
  */
 package org.apache.hadoop.gateway.filter.rewrite.spi;
 
+import java.util.List;
+
 public interface UrlRewriteResolver {
 
-  String resolve( UrlRewriteContext context, String parameter ) throws Exception;
+  List<String> resolve( UrlRewriteContext context, List<String> parameter ) throws Exception;
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteContextImplTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteContextImplTest.java b/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteContextImplTest.java
index b743f69..88587ea 100644
--- a/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteContextImplTest.java
+++ b/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/UrlRewriteContextImplTest.java
@@ -19,16 +19,18 @@ package org.apache.hadoop.gateway.filter.rewrite.impl;
 
 import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteEnvironment;
 import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriter;
-import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteContext;
-import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteResolver;
+import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
 import org.apache.hadoop.gateway.util.urltemplate.Params;
 import org.apache.hadoop.gateway.util.urltemplate.Parser;
+import org.apache.hadoop.gateway.util.urltemplate.Resolver;
 import org.apache.hadoop.gateway.util.urltemplate.Template;
 import org.easymock.EasyMock;
 import org.junit.Test;
 
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.notNullValue;
@@ -42,15 +44,17 @@ public class UrlRewriteContextImplTest {
     UrlRewriteEnvironment environment = EasyMock.createNiceMock( UrlRewriteEnvironment.class );
     EasyMock.expect( environment.resolve( "test-env-param-name" ) ).andReturn( Arrays.asList( "test-env-param-value" ) ).anyTimes();
 
-    UrlRewriteResolver resolver = EasyMock.createNiceMock( UrlRewriteResolver.class );
-    EasyMock.expect( resolver.resolve( EasyMock.anyObject(UrlRewriteContext.class), EasyMock.eq( "test-ctx-param-name" ) ) ).andReturn( "test-ctx-param-value" );
+    Resolver resolver = EasyMock.createNiceMock( Resolver.class );
+    EasyMock.expect( resolver.resolve( "test-ctx-param-name" ) ).andReturn( Arrays.asList( "test-ctx-param-value" ) );
 
     EasyMock.replay( environment, resolver );
 
+    Map<String,UrlRewriteFunctionProcessor> functions = new HashMap<String,UrlRewriteFunctionProcessor>();
+
     UrlRewriter.Direction direction = UrlRewriter.Direction.OUT;
     Template template = Parser.parse( "scheme://host:port/dir/file" );
 
-    UrlRewriteContextImpl context = new UrlRewriteContextImpl( environment, resolver, direction, template );
+    UrlRewriteContextImpl context = new UrlRewriteContextImpl( environment, resolver, functions, direction, template );
 
     Params params = context.getParameters();
     List<String> values = params.resolve( "test-env-param-name" );

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-release/home/deployments/sample.xml
----------------------------------------------------------------------
diff --git a/gateway-release/home/deployments/sample.xml b/gateway-release/home/deployments/sample.xml
index bb0c1e7..4474288 100644
--- a/gateway-release/home/deployments/sample.xml
+++ b/gateway-release/home/deployments/sample.xml
@@ -58,11 +58,11 @@
 
     <service>
         <role>NAMENODE</role>
-        <url>hdfs://sandbox.hortonworks.com:8020</url>
+        <url>hdfs://localhost:8020</url>
     </service>
     <service>
         <role>JOBTRACKER</role>
-        <url>rpc://sandbox.hortonworks.com:8050</url>
+        <url>rpc://localhost:8050</url>
     </service>
     <service>
         <role>WEBHDFS</role>

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/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 76e01ef..ca468e1 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
@@ -153,15 +153,6 @@ public interface GatewayMessages {
   @Message( level = MessageLevel.DEBUG, text = "Apache Knox Gateway {0} ({1})" )
   void gatewayVersionMessage( String version, String hash );
 
-  @Message( level = MessageLevel.DEBUG, text = "Loading from persistent master: {0}" )
-  void loadingFromPersistentMaster( String tag );
-
-  @Message( level = MessageLevel.DEBUG, text = "ALIAS: {0}" )
-  void printClusterAlias( String alias );
-
-  @Message( level = MessageLevel.DEBUG, text = "MASTER SERVICE == NULL: {0}" )
-  void printMasterServiceIsNull( boolean masterServiceIsNull );
-
   @Message( level = MessageLevel.ERROR, text = "Failed to inject service {0}: {1}" )
   void failedToInjectService( String serviceName, @StackTrace( level = MessageLevel.DEBUG ) Exception e );
 

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/UrlConnectionDispatch.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/UrlConnectionDispatch.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/UrlConnectionDispatch.java
index b315048..8e2145b 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/UrlConnectionDispatch.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/UrlConnectionDispatch.java
@@ -60,7 +60,7 @@ public class UrlConnectionDispatch extends AbstractGatewayDispatch {
 
     Resolver resolver = new DispatchParamResolver( getConfig(), request );
     URI sourceUri = new URI( sourcePathInfo );
-    URI targetUri = Rewriter.rewrite( sourceUri, sourceTemplate, targetTemplate, resolver );
+    URI targetUri = Rewriter.rewrite( sourceUri, sourceTemplate, targetTemplate, resolver, null );
 
 //    //TODO: This should be more at filter init.
 //    Pattern sourceRegex = UrlRewriter.compileUrlRegex( sourcePattern );

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-server/src/main/java/org/apache/hadoop/gateway/services/DefaultGatewayServices.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/DefaultGatewayServices.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/DefaultGatewayServices.java
index b5687c1..b9055f2 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/DefaultGatewayServices.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/DefaultGatewayServices.java
@@ -23,7 +23,7 @@ import org.apache.hadoop.gateway.deploy.DeploymentContext;
 import org.apache.hadoop.gateway.descriptor.FilterParamDescriptor;
 import org.apache.hadoop.gateway.descriptor.ResourceDescriptor;
 import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
-import org.apache.hadoop.gateway.services.hostmap.impl.DefaultHostMappingService;
+import org.apache.hadoop.gateway.services.hostmap.impl.DefaultHostMapperService;
 import org.apache.hadoop.gateway.services.registry.impl.DefaultServiceRegistryService;
 import org.apache.hadoop.gateway.services.security.KeystoreServiceException;
 import org.apache.hadoop.gateway.services.security.SSLService;
@@ -89,7 +89,7 @@ public class DefaultGatewayServices implements GatewayServices {
     sr.init( config, options );
     services.put( SERVICE_REGISTRY_SERVICE, sr );
 
-    DefaultHostMappingService hm = new DefaultHostMappingService();
+    DefaultHostMapperService hm = new DefaultHostMapperService();
     hm.init( config, options );
     services.put( HOST_MAPPING_SERVICE, hm );
   }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-server/src/main/java/org/apache/hadoop/gateway/services/HssoGatewayServices.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/HssoGatewayServices.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/HssoGatewayServices.java
index 589be1b..6992429 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/HssoGatewayServices.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/HssoGatewayServices.java
@@ -17,21 +17,13 @@
  */
 package org.apache.hadoop.gateway.services;
 
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
 import org.apache.hadoop.gateway.GatewayMessages;
 import org.apache.hadoop.gateway.config.GatewayConfig;
 import org.apache.hadoop.gateway.deploy.DeploymentContext;
 import org.apache.hadoop.gateway.descriptor.FilterParamDescriptor;
 import org.apache.hadoop.gateway.descriptor.ResourceDescriptor;
 import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
-import org.apache.hadoop.gateway.services.GatewayServices;
-import org.apache.hadoop.gateway.services.Service;
-import org.apache.hadoop.gateway.services.ServiceLifecycleException;
-import org.apache.hadoop.gateway.services.hostmap.impl.DefaultHostMappingService;
+import org.apache.hadoop.gateway.services.hostmap.impl.DefaultHostMapperService;
 import org.apache.hadoop.gateway.services.registry.impl.DefaultServiceRegistryService;
 import org.apache.hadoop.gateway.services.security.KeystoreServiceException;
 import org.apache.hadoop.gateway.services.security.SSLService;
@@ -43,6 +35,11 @@ import org.apache.hadoop.gateway.services.security.impl.JettySSLService;
 import org.apache.hadoop.gateway.services.token.impl.DefaultTokenAuthorityService;
 import org.apache.hadoop.gateway.topology.Provider;
 
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 public class HssoGatewayServices implements GatewayServices {
 
   private static GatewayMessages log = MessagesFactory.get( GatewayMessages.class );
@@ -92,7 +89,7 @@ public class HssoGatewayServices implements GatewayServices {
     ssl.init(config, options);
     services.put(SSL_SERVICE, ssl);
     
-    DefaultHostMappingService hm = new DefaultHostMappingService();
+    DefaultHostMapperService hm = new DefaultHostMapperService();
     hm.init( config, options );
     services.put( HOST_MAPPING_SERVICE, hm );
   }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-server/src/main/java/org/apache/hadoop/gateway/services/hostmap/impl/DefaultHostMapperService.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/hostmap/impl/DefaultHostMapperService.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/hostmap/impl/DefaultHostMapperService.java
new file mode 100644
index 0000000..ba6fd67
--- /dev/null
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/hostmap/impl/DefaultHostMapperService.java
@@ -0,0 +1,81 @@
+/**
+ * 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.services.hostmap.impl;
+
+import org.apache.hadoop.gateway.config.GatewayConfig;
+import org.apache.hadoop.gateway.services.ServiceLifecycleException;
+import org.apache.hadoop.gateway.services.hostmap.HostMapper;
+import org.apache.hadoop.gateway.services.hostmap.HostMapperService;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ *
+ *
+ */
+public class DefaultHostMapperService implements HostMapperService {
+
+  private ConcurrentHashMap<String, HostMapper> map = new ConcurrentHashMap<String, HostMapper>();
+
+  /* (non-Javadoc)
+   * @see org.apache.hadoop.gateway.services.Service#init(org.apache.hadoop.gateway.config.GatewayConfig, java.util.Map)
+   */
+  @Override
+  public void init( GatewayConfig config, Map<String, String> options ) throws ServiceLifecycleException {
+  }
+
+  /* (non-Javadoc)
+   * @see org.apache.hadoop.gateway.services.Service#start()
+   */
+  @Override
+  public void start() throws ServiceLifecycleException {
+  }
+
+  /* (non-Javadoc)
+   * @see org.apache.hadoop.gateway.services.Service#stop()
+   */
+  @Override
+  public void stop() throws ServiceLifecycleException {
+  }
+
+  /* (non-Javadoc)
+   * @see org.apache.hadoop.gateway.services.hostmap.HostMappingService#getHostMapper(java.lang.String)
+   */
+  @Override
+  public HostMapper getHostMapper( String clusterName ) {
+    return map.get( clusterName );
+  }
+
+  /* (non-Javadoc)
+   * @see org.apache.hadoop.gateway.services.hostmap.HostMappingService#registerHostMapperForCluster(java.lang.String, org.apache.hadoop.gateway.services.hostmap.HostMapper)
+   */
+  @Override
+  public void registerHostMapperForCluster( String clusterName, HostMapper hostMapper ) {
+    map.put( clusterName, hostMapper );
+  }
+
+  /* (non-Javadoc)
+   * @see org.apache.hadoop.gateway.services.hostmap.HostMappingService#removeHostMapperForCluster(java.lang.String)
+   */
+  @Override
+  public void removeHostMapperForCluster( String clusterName ) {
+    map.remove( clusterName );
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-server/src/main/java/org/apache/hadoop/gateway/services/hostmap/impl/DefaultHostMappingService.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/hostmap/impl/DefaultHostMappingService.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/hostmap/impl/DefaultHostMappingService.java
deleted file mode 100644
index 5d094dd..0000000
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/hostmap/impl/DefaultHostMappingService.java
+++ /dev/null
@@ -1,83 +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.services.hostmap.impl;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.hadoop.gateway.config.GatewayConfig;
-import org.apache.hadoop.gateway.services.ServiceLifecycleException;
-import org.apache.hadoop.gateway.services.hostmap.FileBasedHostMapper;
-import org.apache.hadoop.gateway.services.hostmap.HostMappingService;
-import org.apache.hadoop.gateway.services.hostmap.HostMapper;
-
-/**
- * 
- *
- */
-public class DefaultHostMappingService implements HostMappingService {
-  ConcurrentHashMap<String, FileBasedHostMapper> map = new ConcurrentHashMap<String, FileBasedHostMapper>();
-  
-  /* (non-Javadoc)
-   * @see org.apache.hadoop.gateway.services.Service#init(org.apache.hadoop.gateway.config.GatewayConfig, java.util.Map)
-   */
-  @Override
-  public void init(GatewayConfig config, Map<String, String> options)
-      throws ServiceLifecycleException {
-  }
-
-  /* (non-Javadoc)
-   * @see org.apache.hadoop.gateway.services.Service#start()
-   */
-  @Override
-  public void start() throws ServiceLifecycleException {
-  }
-
-  /* (non-Javadoc)
-   * @see org.apache.hadoop.gateway.services.Service#stop()
-   */
-  @Override
-  public void stop() throws ServiceLifecycleException {
-  }
-
-  /* (non-Javadoc)
-   * @see org.apache.hadoop.gateway.services.hostmap.HostMappingService#getHostMapper(java.lang.String)
-   */
-  @Override
-  public HostMapper getHostMapper(String clusterName) {
-    return null;
-  }
-
-  /* (non-Javadoc)
-   * @see org.apache.hadoop.gateway.services.hostmap.HostMappingService#registerHostMapperForCluster(java.lang.String, org.apache.hadoop.gateway.services.hostmap.HostMapper)
-   */
-  @Override
-  public void registerHostMapperForCluster(String clusterName,
-      FileBasedHostMapper hostMapper) {
-    map.put(clusterName, hostMapper);
-  }
-
-  /* (non-Javadoc)
-   * @see org.apache.hadoop.gateway.services.hostmap.HostMappingService#removeHostMapperForCluster(java.lang.String)
-   */
-  @Override
-  public void removeHostMapperForCluster(String clusterName) {
-    map.remove(clusterName);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-service-hdfs/src/main/resources/org/apache/hadoop/gateway/hdfs/WebHdfsDeploymentContributor/rewrite.xml
----------------------------------------------------------------------
diff --git a/gateway-service-hdfs/src/main/resources/org/apache/hadoop/gateway/hdfs/WebHdfsDeploymentContributor/rewrite.xml b/gateway-service-hdfs/src/main/resources/org/apache/hadoop/gateway/hdfs/WebHdfsDeploymentContributor/rewrite.xml
index db6069b..d0bd2e2 100644
--- a/gateway-service-hdfs/src/main/resources/org/apache/hadoop/gateway/hdfs/WebHdfsDeploymentContributor/rewrite.xml
+++ b/gateway-service-hdfs/src/main/resources/org/apache/hadoop/gateway/hdfs/WebHdfsDeploymentContributor/rewrite.xml
@@ -32,7 +32,7 @@
     </rule>
 
     <rule dir="IN" name="WEBHDFS/webhdfs/inbound/hdfs" pattern="hdfs:/{path=**}?{**}">
-        <rewrite template="{$serviceUrl[NAMENODE]}/{path=**}?{**}"/>
+        <rewrite template="{$serviceMappedUrl[NAMENODE]}/{path=**}?{**}"/>
     </rule>
 
     <rule dir="IN" name="WEBHDFS/webhdfs/inbound/webhdfs" pattern="webhdfs:/{path=**}?{**}">

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-spi/src/main/java/org/apache/hadoop/gateway/i18n/GatewaySpiMessages.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/i18n/GatewaySpiMessages.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/i18n/GatewaySpiMessages.java
index 6234ef2..669afd7 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/i18n/GatewaySpiMessages.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/i18n/GatewaySpiMessages.java
@@ -64,4 +64,13 @@ public interface GatewaySpiMessages {
   @Message( level = MessageLevel.ERROR, text = "Failed to get key {0}: {1}" )
   void failedToGetKey(String alias, @StackTrace( level = MessageLevel.DEBUG ) Exception e);
 
+  @Message( level = MessageLevel.DEBUG, text = "Loading from persistent master: {0}" )
+  void loadingFromPersistentMaster( String tag );
+
+  @Message( level = MessageLevel.DEBUG, text = "ALIAS: {0}" )
+  void printClusterAlias( String alias );
+
+  @Message( level = MessageLevel.DEBUG, text = "MASTER SERVICE == NULL: {0}" )
+  void printMasterServiceIsNull( boolean masterServiceIsNull );
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/hostmap/FileBasedHostMapper.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/hostmap/FileBasedHostMapper.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/hostmap/FileBasedHostMapper.java
index 5af0744..cdfbddf 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/hostmap/FileBasedHostMapper.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/hostmap/FileBasedHostMapper.java
@@ -26,53 +26,56 @@ import java.util.HashMap;
 import java.util.Map;
 
 public class FileBasedHostMapper implements HostMapper {
+
   private Map<String, String> inbound = new HashMap<String, String>();
   private Map<String, String> outbound = new HashMap<String, String>();
-  
-  public FileBasedHostMapper(String clusterName, URL url) {
+
+  public FileBasedHostMapper( URL url ) throws IOException {
     if( url != null ) {
-      InputStream stream;
-      try {
-        stream = url.openStream();
-        BufferedReader reader = new BufferedReader( new InputStreamReader( stream ) );
-        String line = reader.readLine();
-        while( line != null ) {
-          String[] lineSplit = line.split( "=" );
-          if( lineSplit.length >= 2 ) {
-            String[] externalSplit = lineSplit[ 0 ].split( "," );
-            String[] internalSplit = lineSplit[ 1 ].split( "," );
-            if( externalSplit.length >= 1 && internalSplit.length >= 1 ) {
-              for( String external : externalSplit ) {
-                inbound.put( external, internalSplit[ 0 ] );
-              }
-              for( String internal : internalSplit ) {
-                outbound.put( internal, externalSplit[ 0 ] );
-              }
+      InputStream stream = url.openStream();
+      BufferedReader reader = new BufferedReader( new InputStreamReader( stream ) );
+      String line = reader.readLine();
+      while( line != null ) {
+        String[] lineSplit = line.split( "=" );
+        if( lineSplit.length >= 2 ) {
+          String[] externalSplit = lineSplit[ 0 ].split( "," );
+          String[] internalSplit = lineSplit[ 1 ].split( "," );
+          if( externalSplit.length >= 1 && internalSplit.length >= 1 ) {
+            for( String external : externalSplit ) {
+              inbound.put( external.trim(), internalSplit[ 0 ].trim() );
+            }
+            for( String internal : internalSplit ) {
+              outbound.put( internal.trim(), externalSplit[ 0 ].trim() );
             }
           }
-          line = reader.readLine();
         }
-        reader.close();
-      } catch (IOException e) {
-        // TODO Auto-generated catch block
-        e.printStackTrace();
+        line = reader.readLine();
       }
+      reader.close();
     }
   }
-  
+
   /* (non-Javadoc)
    * @see org.apache.hadoop.gateway.services.hostmap.HostMapper#resolveInboundHostName(java.lang.String)
    */
   @Override
-  public String resolveInboundHostName(String inboundHost) {
-    return inbound.get(inboundHost);
+  public String resolveInboundHostName( String hostName ) {
+    String resolvedHostName = inbound.get( hostName );
+    if( resolvedHostName == null ) {
+      resolvedHostName = hostName;
+    }
+    return resolvedHostName;
   }
 
   /* (non-Javadoc)
    * @see org.apache.hadoop.gateway.services.hostmap.HostMapper#resolveOutboundHostName(java.lang.String)
    */
   @Override
-  public String resolveOutboundHostName(String outboundHost) {
-    return outbound.get(outboundHost);
+  public String resolveOutboundHostName( String hostName ) {
+    String resolvedHostName = outbound.get( hostName );
+    if( resolvedHostName == null ) {
+      resolvedHostName = hostName;
+    }
+    return resolvedHostName;
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/hostmap/HostMapper.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/hostmap/HostMapper.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/hostmap/HostMapper.java
index 14ab0ac..e067371 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/hostmap/HostMapper.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/hostmap/HostMapper.java
@@ -22,8 +22,16 @@ package org.apache.hadoop.gateway.services.hostmap;
  */
 public interface HostMapper {
 
-  public abstract String resolveInboundHostName(String inboundHost);
+  /**
+   * @param inboundHost
+   * @return
+   */
+  public abstract String resolveInboundHostName( String inboundHost );
 
-  public abstract String resolveOutboundHostName(String outboundHost);
+  /**
+   * @param outboundHost
+   * @return
+   */
+  public abstract String resolveOutboundHostName( String outboundHost );
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/hostmap/HostMapperService.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/hostmap/HostMapperService.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/hostmap/HostMapperService.java
new file mode 100644
index 0000000..1e784d8
--- /dev/null
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/hostmap/HostMapperService.java
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.gateway.services.hostmap;
+
+import org.apache.hadoop.gateway.services.Service;
+
+public interface HostMapperService extends Service {
+
+  /**
+   * @param clusterName
+   * @return
+   */
+  HostMapper getHostMapper( String clusterName );
+
+  /**
+   * @param clusterName
+   * @param hostMapper
+   */
+  void registerHostMapperForCluster( String clusterName, HostMapper hostMapper );
+
+  /**
+   * @param clusterName
+   */
+  void removeHostMapperForCluster( String clusterName );
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/hostmap/HostMappingService.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/hostmap/HostMappingService.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/hostmap/HostMappingService.java
deleted file mode 100644
index a950724..0000000
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/hostmap/HostMappingService.java
+++ /dev/null
@@ -1,35 +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.services.hostmap;
-
-import org.apache.hadoop.gateway.services.Service;
-
-public interface HostMappingService extends Service {
-  HostMapper getHostMapper(String clusterName);
-
-  /**
-   * @param clusterName
-   * @param hostMapper
-   */
-  void registerHostMapperForCluster(String clusterName, FileBasedHostMapper hostMapper);
-
-  /**
-   * @param clusterName
-   */
-  void removeHostMapperForCluster(String clusterName);
-}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/CMFMasterService.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/CMFMasterService.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/CMFMasterService.java
index 4d6b8dd..28d027b 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/CMFMasterService.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/CMFMasterService.java
@@ -17,13 +17,6 @@
  */
 package org.apache.hadoop.gateway.services.security.impl;
 
-import java.io.Console;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.net.ntp.TimeStamp;
@@ -32,6 +25,13 @@ import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
 import org.apache.hadoop.gateway.services.ServiceLifecycleException;
 import org.apache.hadoop.gateway.services.security.EncryptionResult;
 
+import java.io.Console;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
 public class CMFMasterService {
   private static GatewaySpiMessages LOG = MessagesFactory.get( GatewaySpiMessages.class );
 
@@ -151,8 +151,7 @@ public class CMFMasterService {
       try {
         List<String> lines = FileUtils.readLines(masterFile, "UTF8");
         String tag = lines.get(0);
-        // TODO: log - if appropriate - at least at finest level
-        System.out.println("Loading from persistent master: " + tag); //TODO: I18N
+        LOG.loadingFromPersistentMaster( tag );
         String line = new String(Base64.decodeBase64(lines.get(1)));
         String[] parts = line.split("::");
         this.master = new String(aes.decrypt(Base64.decodeBase64(parts[0]), Base64.decodeBase64(parts[1]), Base64.decodeBase64(parts[2])), "UTF8").toCharArray();

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-spi/src/test/java/org/apache/hadoop/gateway/services/hostmap/FileBasedHostMapperTest.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/test/java/org/apache/hadoop/gateway/services/hostmap/FileBasedHostMapperTest.java b/gateway-spi/src/test/java/org/apache/hadoop/gateway/services/hostmap/FileBasedHostMapperTest.java
new file mode 100644
index 0000000..0ad867d
--- /dev/null
+++ b/gateway-spi/src/test/java/org/apache/hadoop/gateway/services/hostmap/FileBasedHostMapperTest.java
@@ -0,0 +1,64 @@
+/**
+ * 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.services.hostmap;
+
+import org.apache.hadoop.test.TestUtils;
+import org.junit.Test;
+
+import java.net.URL;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+public class FileBasedHostMapperTest {
+
+  @Test
+  public void testEverything() throws Exception {
+    URL hostMapUrl = TestUtils.getResourceUrl( FileBasedHostMapperTest.class, "hostmap.txt" );
+    FileBasedHostMapper mapper = new FileBasedHostMapper( hostMapUrl );
+
+    assertThat( mapper.resolveInboundHostName( null ), nullValue() );
+    assertThat( mapper.resolveOutboundHostName( null ), nullValue() );
+
+    // external=internal
+    assertThat( mapper.resolveInboundHostName( "external" ), is( "internal" ) );
+    assertThat( mapper.resolveInboundHostName( "internal" ), is( "internal" ) );
+    assertThat( mapper.resolveOutboundHostName( "external" ), is( "external" ) );
+    assertThat( mapper.resolveOutboundHostName( "internal" ), is( "external" ) );
+
+    // external-space = internal-space
+    assertThat( mapper.resolveInboundHostName( "external-space" ), is( "internal-space" ) );
+    assertThat( mapper.resolveInboundHostName( "internal-space" ), is( "internal-space" ) );
+    assertThat( mapper.resolveOutboundHostName( "external-space" ), is( "external-space" ) );
+    assertThat( mapper.resolveOutboundHostName( "internal-space" ), is( "external-space" ) );
+
+//    external-list = external-list-1, external-list-2
+    assertThat( mapper.resolveInboundHostName( "external-list" ), is( "external-list-1" ) );
+
+//    internal-list-1, internal-list-2 = internal-list
+    assertThat( mapper.resolveOutboundHostName( "internal-list" ), is( "internal-list-1" ) );
+
+//    external-both-list-1, external-both-list-2 = internal-both-list-1, internal-both-list-2
+    assertThat( mapper.resolveInboundHostName( "external-both-list-1" ), is( "internal-both-list-1" ) );
+    assertThat( mapper.resolveInboundHostName( "external-both-list-2" ), is( "internal-both-list-1" ) );
+    assertThat( mapper.resolveOutboundHostName( "internal-both-list-1" ), is( "external-both-list-1" ) );
+    assertThat( mapper.resolveOutboundHostName( "internal-both-list-2" ), is( "external-both-list-1" ) );
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-spi/src/test/resources/org/apache/hadoop/gateway/services/hostmap/FileBasedHostMapperTest/hostmap.txt
----------------------------------------------------------------------
diff --git a/gateway-spi/src/test/resources/org/apache/hadoop/gateway/services/hostmap/FileBasedHostMapperTest/hostmap.txt b/gateway-spi/src/test/resources/org/apache/hadoop/gateway/services/hostmap/FileBasedHostMapperTest/hostmap.txt
new file mode 100644
index 0000000..b10a606
--- /dev/null
+++ b/gateway-spi/src/test/resources/org/apache/hadoop/gateway/services/hostmap/FileBasedHostMapperTest/hostmap.txt
@@ -0,0 +1,6 @@
+external=internal
+external-space = internal-space
+external-list = external-list-1, external-list-2
+internal-list-1, internal-list-2 = internal-list
+external-both-list-1, external-both-list-2 = internal-both-list-1, internal-both-list-2
+

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/Evaluator.java
----------------------------------------------------------------------
diff --git a/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/Evaluator.java b/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/Evaluator.java
new file mode 100644
index 0000000..cd0b25f
--- /dev/null
+++ b/gateway-util-urltemplate/src/main/java/org/apache/hadoop/gateway/util/urltemplate/Evaluator.java
@@ -0,0 +1,26 @@
+/**
+ * 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.urltemplate;
+
+import java.util.List;
+
+public interface Evaluator {
+
+  List<String> evaluate( String function, List<String> parameters );
+
+}


[3/3] git commit: KNOX-127: Use hostmap in some service registry rewrite functions.

Posted by km...@apache.org.
KNOX-127: Use hostmap in some service registry rewrite functions.


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

Branch: refs/heads/master
Commit: e338fe64f94dfa5365b699faa6f8621ce3f59bf2
Parents: afe298e
Author: Kevin Minder <ke...@hortonworks.com>
Authored: Thu Sep 19 23:58:05 2013 -0400
Committer: Kevin Minder <ke...@hortonworks.com>
Committed: Thu Sep 19 23:58:05 2013 -0400

----------------------------------------------------------------------
 .../function/UsernameFunctionProcessor.java     |  18 +-
 .../function/UsernameFunctionProcessorTest.java |   9 +-
 .../impl/HostmapDeploymentContributor.java      |  13 +-
 .../hostmap/impl/HostmapFunctionProcessor.java  |  73 ++++----
 .../impl/HostmapFunctionProcessorTest.java      |  36 +++-
 .../api/ServiceAddressFunctionDescriptor.java   |  11 +-
 .../api/ServiceHostFunctionDescriptor.java      |  11 +-
 .../ServiceMappedAddressFunctionDescriptor.java |  31 ++++
 .../ServiceMappedHostFunctionDescriptor.java    |  31 ++++
 .../api/ServiceMappedUrlFunctionDescriptor.java |  31 ++++
 .../api/ServicePathFunctionDescriptor.java      |  11 +-
 .../api/ServicePortFunctionDescriptor.java      |  11 +-
 .../api/ServiceSchemeFunctionDescriptor.java    |  11 +-
 .../impl/ServiceAddressFunctionProcessor.java   |  40 ++++-
 .../impl/ServiceHostFunctionProcessor.java      |  28 +++-
 .../ServiceMappedAddressFunctionProcessor.java  | 110 ++++++++++++
 .../ServiceMappedHostFunctionProcessor.java     |  87 ++++++++++
 .../impl/ServiceMappedUrlFunctionProcessor.java |  90 ++++++++++
 .../impl/ServicePathFunctionProcessor.java      |  28 ++--
 .../impl/ServicePortFunctionProcessor.java      |  28 +++-
 .../ServiceRegistryFunctionProcessorBase.java   |  19 +--
 .../impl/ServiceSchemeFunctionProcessor.java    |  28 +++-
 .../impl/ServiceUrlFunctionProcessor.java       |  31 +++-
 ...ter.rewrite.api.UrlRewriteFunctionDescriptor |   5 +-
 ...lter.rewrite.spi.UrlRewriteFunctionProcessor |   5 +-
 .../ServiceAddressFunctionProcessorTest.java    |   7 +-
 .../impl/ServiceHostFunctionProcessorTest.java  |   8 +-
 ...rviceMappedAddressFunctionProcessorTest.java | 148 ++++++++++++++++
 .../ServiceMappedHostFunctionProcessorTest.java | 148 ++++++++++++++++
 .../ServiceMappedUrlFunctionProcessorTest.java  | 148 ++++++++++++++++
 .../impl/ServicePathFunctionProcessorTest.java  |   6 +-
 .../impl/ServicePortFunctionProcessorTest.java  |   8 +-
 .../ServiceSchemeFunctionProcessorTest.java     |   7 +-
 .../impl/ServiceUrlFunctionProcessorTest.java   |  25 ++-
 .../filter/rewrite/api/UrlRewriteProcessor.java |   9 +-
 .../UrlRewriteActionRewriteProcessorExt.java    |   2 +-
 .../rewrite/impl/UrlRewriteContextImpl.java     |  47 ++++--
 .../impl/UrlRewriteFunctionResolver.java        | 115 -------------
 .../filter/rewrite/spi/UrlRewriteContext.java   |   3 +
 .../filter/rewrite/spi/UrlRewriteResolver.java  |   4 +-
 .../rewrite/impl/UrlRewriteContextImplTest.java |  14 +-
 gateway-release/home/deployments/sample.xml     |   4 +-
 .../apache/hadoop/gateway/GatewayMessages.java  |   9 -
 .../gateway/dispatch/UrlConnectionDispatch.java |   2 +-
 .../services/DefaultGatewayServices.java        |   4 +-
 .../gateway/services/HssoGatewayServices.java   |  17 +-
 .../hostmap/impl/DefaultHostMapperService.java  |  81 +++++++++
 .../hostmap/impl/DefaultHostMappingService.java |  83 ---------
 .../WebHdfsDeploymentContributor/rewrite.xml    |   2 +-
 .../hadoop/gateway/i18n/GatewaySpiMessages.java |   9 +
 .../services/hostmap/FileBasedHostMapper.java   |  61 +++----
 .../gateway/services/hostmap/HostMapper.java    |  12 +-
 .../services/hostmap/HostMapperService.java     |  41 +++++
 .../services/hostmap/HostMappingService.java    |  35 ----
 .../security/impl/CMFMasterService.java         |  17 +-
 .../hostmap/FileBasedHostMapperTest.java        |  64 +++++++
 .../hostmap/FileBasedHostMapperTest/hostmap.txt |   6 +
 .../gateway/util/urltemplate/Evaluator.java     |  26 +++
 .../gateway/util/urltemplate/Expander.java      | 110 ++++++------
 .../gateway/util/urltemplate/Function.java      | 114 +++++++++++++
 .../gateway/util/urltemplate/MockParams.java    |   1 +
 .../gateway/util/urltemplate/Rewriter.java      |   9 +-
 .../gateway/util/urltemplate/ExpanderTest.java  |  68 ++++----
 .../gateway/util/urltemplate/FunctionTest.java  | 167 +++++++++++++++++++
 .../gateway/util/urltemplate/MatcherTest.java   |  99 +++++++++++
 .../gateway/util/urltemplate/ParserTest.java    |   8 +-
 .../gateway/util/urltemplate/RewriterTest.java  |  66 +++++---
 67 files changed, 1991 insertions(+), 619 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-identity-assertion-pseudo/src/main/java/org/apache/hadoop/gateway/identityasserter/function/UsernameFunctionProcessor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-identity-assertion-pseudo/src/main/java/org/apache/hadoop/gateway/identityasserter/function/UsernameFunctionProcessor.java b/gateway-provider-identity-assertion-pseudo/src/main/java/org/apache/hadoop/gateway/identityasserter/function/UsernameFunctionProcessor.java
index 8cabeab..b3c90f5 100644
--- a/gateway-provider-identity-assertion-pseudo/src/main/java/org/apache/hadoop/gateway/identityasserter/function/UsernameFunctionProcessor.java
+++ b/gateway-provider-identity-assertion-pseudo/src/main/java/org/apache/hadoop/gateway/identityasserter/function/UsernameFunctionProcessor.java
@@ -26,6 +26,8 @@ import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
 
 import javax.security.auth.Subject;
 import java.security.AccessController;
+import java.util.ArrayList;
+import java.util.List;
 
 public class UsernameFunctionProcessor
     extends AbstractIdentityAssertionBase
@@ -54,16 +56,18 @@ public class UsernameFunctionProcessor
   }
 
   @Override
-  public String resolve( UrlRewriteContext context, String parameter ) throws Exception {
-    String value = parameter;
+  public List<String> resolve( UrlRewriteContext context, List<String> parameters ) throws Exception {
+    List<String> results = null;
     Subject subject = Subject.getSubject( AccessController.getContext() );
     if( subject != null ) {
-      value = getPrincipalName( subject );
-//      if( mapper != null ) {
-//        value = mapper.mapPrincipal( value );
-//      }
+      results = new ArrayList<String>( 1 );
+      String username = getPrincipalName( subject );
+      results.add( username );
+    } else if( parameters != null && parameters.size() > 0 ) {
+      results = new ArrayList<String>( 1 );
+      results.add( parameters.get( 0 ) );
     }
-    return value;
+    return results;
   }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-identity-assertion-pseudo/src/test/java/org/apache/hadoop/gateway/identityasserter/function/UsernameFunctionProcessorTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-identity-assertion-pseudo/src/test/java/org/apache/hadoop/gateway/identityasserter/function/UsernameFunctionProcessorTest.java b/gateway-provider-identity-assertion-pseudo/src/test/java/org/apache/hadoop/gateway/identityasserter/function/UsernameFunctionProcessorTest.java
index dab9c59..dffa4b0 100644
--- a/gateway-provider-identity-assertion-pseudo/src/test/java/org/apache/hadoop/gateway/identityasserter/function/UsernameFunctionProcessorTest.java
+++ b/gateway-provider-identity-assertion-pseudo/src/test/java/org/apache/hadoop/gateway/identityasserter/function/UsernameFunctionProcessorTest.java
@@ -52,15 +52,16 @@ import java.net.URL;
 import java.nio.charset.Charset;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
+import java.util.Arrays;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.ServiceLoader;
 
-import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.nullValue;
+import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
 import static org.junit.Assert.fail;
 
 public class UsernameFunctionProcessorTest {
@@ -135,15 +136,15 @@ public class UsernameFunctionProcessorTest {
   public void testResolve() throws Exception {
     final UsernameFunctionProcessor processor = new UsernameFunctionProcessor();
     assertThat( processor.resolve( null, null ), nullValue() );
-    assertThat( processor.resolve( null, "test-input" ), is( "test-input" ) );
+    assertThat( processor.resolve( null, Arrays.asList( "test-input" ) ), contains( "test-input" ) );
     Subject subject = new Subject();
     subject.getPrincipals().add( new PrimaryPrincipal( "test-username" ) );
     subject.setReadOnly();
     Subject.doAs( subject, new PrivilegedExceptionAction<Object>() {
       @Override
       public Object run() throws Exception {
-        assertThat( processor.resolve( null, null ), is( "test-username" ) );
-        assertThat( processor.resolve( null, "test-ignored" ), is( "test-username" ) );
+        assertThat( processor.resolve( null, null ), contains( "test-username" ) );
+        assertThat( processor.resolve( null, Arrays.asList( "test-ignored" ) ), contains( "test-username" ) );
         return null;
       }
     } );

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-hostmap-static/src/main/java/org/apache/hadoop/gateway/hostmap/impl/HostmapDeploymentContributor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-hostmap-static/src/main/java/org/apache/hadoop/gateway/hostmap/impl/HostmapDeploymentContributor.java b/gateway-provider-rewrite-func-hostmap-static/src/main/java/org/apache/hadoop/gateway/hostmap/impl/HostmapDeploymentContributor.java
index f79b046..fdd0b03 100644
--- a/gateway-provider-rewrite-func-hostmap-static/src/main/java/org/apache/hadoop/gateway/hostmap/impl/HostmapDeploymentContributor.java
+++ b/gateway-provider-rewrite-func-hostmap-static/src/main/java/org/apache/hadoop/gateway/hostmap/impl/HostmapDeploymentContributor.java
@@ -24,7 +24,6 @@ import org.apache.hadoop.gateway.descriptor.FilterParamDescriptor;
 import org.apache.hadoop.gateway.descriptor.ResourceDescriptor;
 import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteRulesDescriptor;
 import org.apache.hadoop.gateway.hostmap.api.HostmapFunctionDescriptor;
-import org.apache.hadoop.gateway.services.hostmap.HostMappingService;
 import org.apache.hadoop.gateway.topology.Provider;
 import org.apache.hadoop.gateway.topology.Service;
 import org.jboss.shrinkwrap.api.asset.Asset;
@@ -41,14 +40,8 @@ public class HostmapDeploymentContributor
 
   public static final String PROVIDER_ROLE_NAME = HostmapFunctionDescriptor.FUNCTION_NAME;
   public static final String PROVIDER_IMPL_NAME = "static";
-
   private static final String REWRITE_ROLE_NAME = "rewrite";
-  private HostMappingService hostMapping;
-  
-  private void setHostMappingService(HostMappingService hostMapping) {
-    this.hostMapping = hostMapping;
-  }
-  
+
   @Override
   public String getRole() {
     return PROVIDER_ROLE_NAME;
@@ -80,12 +73,12 @@ public class HostmapDeploymentContributor
   private Asset createAsset( Provider provider ) {
     StringWriter buffer = new StringWriter();
     PrintWriter writer = new PrintWriter( buffer );
-    for( Map.Entry<String,String> entry : provider.getParams().entrySet() ) {
+    for( Map.Entry<String, String> entry : provider.getParams().entrySet() ) {
       String externalHosts = entry.getKey();
       String internalHosts = entry.getValue();
       writer.print( externalHosts );
       writer.print( "=" );
-      writer.println( internalHosts ) ;
+      writer.println( internalHosts );
     }
     writer.close();
     String string = buffer.toString();

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-hostmap-static/src/main/java/org/apache/hadoop/gateway/hostmap/impl/HostmapFunctionProcessor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-hostmap-static/src/main/java/org/apache/hadoop/gateway/hostmap/impl/HostmapFunctionProcessor.java b/gateway-provider-rewrite-func-hostmap-static/src/main/java/org/apache/hadoop/gateway/hostmap/impl/HostmapFunctionProcessor.java
index 9be1dd2..ca55c16 100644
--- a/gateway-provider-rewrite-func-hostmap-static/src/main/java/org/apache/hadoop/gateway/hostmap/impl/HostmapFunctionProcessor.java
+++ b/gateway-provider-rewrite-func-hostmap-static/src/main/java/org/apache/hadoop/gateway/hostmap/impl/HostmapFunctionProcessor.java
@@ -23,26 +23,22 @@ import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
 import org.apache.hadoop.gateway.hostmap.api.HostmapFunctionDescriptor;
 import org.apache.hadoop.gateway.services.GatewayServices;
 import org.apache.hadoop.gateway.services.hostmap.FileBasedHostMapper;
-import org.apache.hadoop.gateway.services.hostmap.HostMappingService;
-import org.apache.hadoop.gateway.services.security.CryptoService;
+import org.apache.hadoop.gateway.services.hostmap.HostMapper;
+import org.apache.hadoop.gateway.services.hostmap.HostMapperService;
 
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.net.URL;
-import java.util.HashMap;
+import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 
 public class HostmapFunctionProcessor
     implements UrlRewriteFunctionProcessor<HostmapFunctionDescriptor> {
 
   public static final String DESCRIPTOR_DEFAULT_FILE_NAME = "hostmap.txt";
   public static final String DESCRIPTOR_DEFAULT_LOCATION = "/WEB-INF/" + DESCRIPTOR_DEFAULT_FILE_NAME;
-  
-  private FileBasedHostMapper hostMapper = null;
+
+  private HostMapperService hostMapperService;
+  private HostMapper hostMapper = null;
   private String clusterName;
-  private HostMappingService hostMappingService;
 
   @Override
   public String name() {
@@ -52,48 +48,43 @@ public class HostmapFunctionProcessor
   @Override
   public void initialize( UrlRewriteEnvironment environment, HostmapFunctionDescriptor descriptor ) throws Exception {
     URL url = environment.getResource( DESCRIPTOR_DEFAULT_LOCATION );
-    List<String> names = environment.resolve( "cluster.name" );
-    if (names != null && names.size() > 0) {
-      clusterName = names.get( 0 );
-    }
-    hostMapper = new FileBasedHostMapper(clusterName, url);
-
-    GatewayServices services = environment.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
-    if (clusterName != null && services != null) {
-      hostMappingService = (HostMappingService) services.getService(GatewayServices.HOST_MAPPING_SERVICE);
-      if (hostMappingService != null) {
-        hostMappingService.registerHostMapperForCluster(clusterName, hostMapper);
+    hostMapper = new FileBasedHostMapper( url );
+    clusterName = environment.getAttribute(  GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE );
+    GatewayServices services = environment.getAttribute( GatewayServices.GATEWAY_SERVICES_ATTRIBUTE );
+    if( clusterName != null && services != null ) {
+      hostMapperService = services.getService( GatewayServices.HOST_MAPPING_SERVICE );
+      if( hostMapperService != null ) {
+        hostMapperService.registerHostMapperForCluster( clusterName, hostMapper );
       }
     }
   }
 
   @Override
   public void destroy() throws Exception {
-    // need to remove the host mapper for the cluster on undeploy
-    if (clusterName != null && hostMappingService != null) {
-      hostMappingService.removeHostMapperForCluster(clusterName);
+    if( hostMapperService != null && clusterName != null ) {
+      hostMapperService.removeHostMapperForCluster( clusterName );
     }
-    
   }
 
   @Override
-  public String resolve( UrlRewriteContext context, String parameter ) throws Exception {
-    String value;
-    switch( context.getDirection() ) {
-      case IN:
-        value = hostMapper.resolveInboundHostName(parameter);
-        break;
-      case OUT:
-        value = hostMapper.resolveOutboundHostName(parameter);
-        break;
-      default:
-        value = null;
-    }
-    if( value == null ) {
-      value = parameter;
-    }
+  public List<String> resolve( UrlRewriteContext context, List<String> parameters ) throws Exception {
+    List<String> result = null;
+    if( parameters != null ) {
+      result = new ArrayList<String>( parameters.size() );
+      for( String parameter : parameters ) {
+        switch( context.getDirection() ) {
+          case IN:
+            parameter = hostMapper.resolveInboundHostName( parameter );
+            break;
+          case OUT:
+            parameter = hostMapper.resolveOutboundHostName( parameter );
+            break;
+        }
+        result.add( parameter );
+      }
 //    System.out.println( "HOSTMAP: " + parameter + "->" + value );
-    return value;
+    }
+    return result;
   }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-hostmap-static/src/test/java/org/apache/hadoop/gateway/hostmap/impl/HostmapFunctionProcessorTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-hostmap-static/src/test/java/org/apache/hadoop/gateway/hostmap/impl/HostmapFunctionProcessorTest.java b/gateway-provider-rewrite-func-hostmap-static/src/test/java/org/apache/hadoop/gateway/hostmap/impl/HostmapFunctionProcessorTest.java
index 011a4bd..be738e9 100644
--- a/gateway-provider-rewrite-func-hostmap-static/src/test/java/org/apache/hadoop/gateway/hostmap/impl/HostmapFunctionProcessorTest.java
+++ b/gateway-provider-rewrite-func-hostmap-static/src/test/java/org/apache/hadoop/gateway/hostmap/impl/HostmapFunctionProcessorTest.java
@@ -27,7 +27,7 @@ import org.apache.hadoop.gateway.filter.rewrite.ext.UrlRewriteActionRewriteDescr
 import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
 import org.apache.hadoop.gateway.services.GatewayServices;
 import org.apache.hadoop.gateway.services.hostmap.HostMapper;
-import org.apache.hadoop.gateway.services.hostmap.HostMappingService;
+import org.apache.hadoop.gateway.services.hostmap.HostMapperService;
 import org.apache.hadoop.gateway.util.urltemplate.Parser;
 import org.apache.hadoop.gateway.util.urltemplate.Resolver;
 import org.apache.hadoop.gateway.util.urltemplate.Template;
@@ -68,7 +68,7 @@ public class HostmapFunctionProcessorTest {
     HostMapper hm = EasyMock.createNiceMock(HostMapper.class);
     EasyMock.expect( hm.resolveInboundHostName("test-inbound-host")).andReturn( "test-inbound-rewritten-host" ).anyTimes();
     
-    HostMappingService hms = EasyMock.createNiceMock( HostMappingService.class );
+    HostMapperService hms = EasyMock.createNiceMock( HostMapperService.class );
 
     GatewayServices gatewayServices = EasyMock.createNiceMock( GatewayServices.class );
     EasyMock.expect( gatewayServices.getService( GatewayServices.HOST_MAPPING_SERVICE ) ).andReturn( hms ).anyTimes();
@@ -194,7 +194,7 @@ public class HostmapFunctionProcessorTest {
   }
 
   @Test
-  public void testMissingFunctionUseCase() throws Exception {
+  public void testInvalidFunctionNameUseCase() throws Exception {
     URL configUrl = TestUtils.getResourceUrl( this.getClass(), "hostmap.txt" );
 
     UrlRewriteEnvironment environment = EasyMock.createNiceMock( UrlRewriteEnvironment.class );
@@ -216,11 +216,11 @@ public class HostmapFunctionProcessorTest {
     Template output = rewriter.rewrite( resolver, input, UrlRewriter.Direction.IN, null );
     //System.out.println( output );
     assertThat( output, notNullValue() );
-    assertThat( output.getHost().getFirstValue().getPattern(), is( "test-inbound-host" ) );
+    assertThat( output.getHost().getFirstValue().getPattern(), is( "$invalid-function(host)" ) );
   }
 
   @Test
-  public void testEmptyHostmapUseCase() throws Exception {
+  public void testInvalidFunctionNameAndEmptyHostmapUseCase() throws Exception {
     URL configUrl = TestUtils.getResourceUrl( this.getClass(), "empty-hostmap.txt" );
 
     UrlRewriteEnvironment environment = EasyMock.createNiceMock( UrlRewriteEnvironment.class );
@@ -242,6 +242,32 @@ public class HostmapFunctionProcessorTest {
     Template output = rewriter.rewrite( resolver, input, UrlRewriter.Direction.IN, null );
     //System.out.println( output );
     assertThat( output, notNullValue() );
+    assertThat( output.getHost().getFirstValue().getPattern(), is( "$invalid-function(host)" ) );
+  }
+
+  @Test
+  public void testEmptyHostmapUseCase() throws Exception {
+    URL configUrl = TestUtils.getResourceUrl( this.getClass(), "empty-hostmap.txt" );
+
+    UrlRewriteEnvironment environment = EasyMock.createNiceMock( UrlRewriteEnvironment.class );
+    EasyMock.expect( environment.getResource( "/WEB-INF/hostmap.txt" ) ).andReturn( configUrl ).anyTimes();
+    Resolver resolver = EasyMock.createNiceMock( Resolver.class );
+    EasyMock.expect( resolver.resolve( "host" ) ).andReturn( Arrays.asList( "test-inbound-host" ) ).anyTimes();
+    EasyMock.replay( environment, resolver );
+
+    UrlRewriteRulesDescriptor descriptor = UrlRewriteRulesDescriptorFactory.create();
+    UrlRewriteRuleDescriptor rule = descriptor.addRule( "test-rule" );
+    rule.pattern( "{*}://{host}:{*}/{**}?{**}" );
+    UrlRewriteActionRewriteDescriptorExt rewrite = rule.addStep( "rewrite" );
+    rewrite.template( "{*}://{$hostmap(host)}:{*}/{**}?{**}" );
+
+    UrlRewriteProcessor rewriter = new UrlRewriteProcessor();
+    rewriter.initialize( environment, descriptor );
+
+    Template input = Parser.parse( "test-scheme://test-inbound-host:42/test-path/test-file?test-name=test-value" );
+    Template output = rewriter.rewrite( resolver, input, UrlRewriter.Direction.IN, null );
+    //System.out.println( output );
+    assertThat( output, notNullValue() );
     assertThat( output.getHost().getFirstValue().getPattern(), is( "test-inbound-host" ) );
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceAddressFunctionDescriptor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceAddressFunctionDescriptor.java b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceAddressFunctionDescriptor.java
index b271215..bfe8933 100644
--- a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceAddressFunctionDescriptor.java
+++ b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceAddressFunctionDescriptor.java
@@ -21,10 +21,11 @@ import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor
 
 public class ServiceAddressFunctionDescriptor implements UrlRewriteFunctionDescriptor<ServiceUrlFunctionDescriptor> {
 
-    public static final String FUNCTION_NAME = "serviceAddr";
-      @Override
-      public String name() {
-      return FUNCTION_NAME;
-    }
+  public static final String FUNCTION_NAME = "serviceAddr";
+
+  @Override
+  public String name() {
+    return FUNCTION_NAME;
+  }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceHostFunctionDescriptor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceHostFunctionDescriptor.java b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceHostFunctionDescriptor.java
index 83a66c2..cff251b 100644
--- a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceHostFunctionDescriptor.java
+++ b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceHostFunctionDescriptor.java
@@ -21,10 +21,11 @@ import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor
 
 public class ServiceHostFunctionDescriptor implements UrlRewriteFunctionDescriptor<ServiceUrlFunctionDescriptor> {
 
-    public static final String FUNCTION_NAME = "serviceHost";
-      @Override
-      public String name() {
-      return FUNCTION_NAME;
-    }
+  public static final String FUNCTION_NAME = "serviceHost";
+
+  @Override
+  public String name() {
+    return FUNCTION_NAME;
+  }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceMappedAddressFunctionDescriptor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceMappedAddressFunctionDescriptor.java b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceMappedAddressFunctionDescriptor.java
new file mode 100644
index 0000000..ae12de0
--- /dev/null
+++ b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceMappedAddressFunctionDescriptor.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.svcregfunc.api;
+
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor;
+
+public class ServiceMappedAddressFunctionDescriptor implements UrlRewriteFunctionDescriptor<ServiceUrlFunctionDescriptor> {
+
+  public static final String FUNCTION_NAME = "serviceMappedAddr";
+
+  @Override
+  public String name() {
+    return FUNCTION_NAME;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceMappedHostFunctionDescriptor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceMappedHostFunctionDescriptor.java b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceMappedHostFunctionDescriptor.java
new file mode 100644
index 0000000..dd8beb2
--- /dev/null
+++ b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceMappedHostFunctionDescriptor.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.svcregfunc.api;
+
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor;
+
+public class ServiceMappedHostFunctionDescriptor implements UrlRewriteFunctionDescriptor<ServiceUrlFunctionDescriptor> {
+
+  public static final String FUNCTION_NAME = "serviceMappedHost";
+
+  @Override
+  public String name() {
+    return FUNCTION_NAME;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceMappedUrlFunctionDescriptor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceMappedUrlFunctionDescriptor.java b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceMappedUrlFunctionDescriptor.java
new file mode 100644
index 0000000..8ea8271
--- /dev/null
+++ b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceMappedUrlFunctionDescriptor.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.svcregfunc.api;
+
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor;
+
+public class ServiceMappedUrlFunctionDescriptor implements UrlRewriteFunctionDescriptor<ServiceMappedUrlFunctionDescriptor> {
+
+  public static final String FUNCTION_NAME = "serviceMappedUrl";
+
+  @Override
+  public String name() {
+    return FUNCTION_NAME;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServicePathFunctionDescriptor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServicePathFunctionDescriptor.java b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServicePathFunctionDescriptor.java
index d819d61..ab69264 100644
--- a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServicePathFunctionDescriptor.java
+++ b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServicePathFunctionDescriptor.java
@@ -21,10 +21,11 @@ import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor
 
 public class ServicePathFunctionDescriptor implements UrlRewriteFunctionDescriptor<ServiceUrlFunctionDescriptor> {
 
-    public static final String FUNCTION_NAME = "servicePath";
-      @Override
-      public String name() {
-      return FUNCTION_NAME;
-    }
+  public static final String FUNCTION_NAME = "servicePath";
+
+  @Override
+  public String name() {
+    return FUNCTION_NAME;
+  }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServicePortFunctionDescriptor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServicePortFunctionDescriptor.java b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServicePortFunctionDescriptor.java
index 8a04ad2..cc05975 100644
--- a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServicePortFunctionDescriptor.java
+++ b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServicePortFunctionDescriptor.java
@@ -21,10 +21,11 @@ import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor
 
 public class ServicePortFunctionDescriptor implements UrlRewriteFunctionDescriptor<ServiceUrlFunctionDescriptor> {
 
-    public static final String FUNCTION_NAME = "servicePort";
-      @Override
-      public String name() {
-      return FUNCTION_NAME;
-    }
+  public static final String FUNCTION_NAME = "servicePort";
+
+  @Override
+  public String name() {
+    return FUNCTION_NAME;
+  }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceSchemeFunctionDescriptor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceSchemeFunctionDescriptor.java b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceSchemeFunctionDescriptor.java
index a391b72..dc73dee 100644
--- a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceSchemeFunctionDescriptor.java
+++ b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/api/ServiceSchemeFunctionDescriptor.java
@@ -21,10 +21,11 @@ import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor
 
 public class ServiceSchemeFunctionDescriptor implements UrlRewriteFunctionDescriptor<ServiceUrlFunctionDescriptor> {
 
-    public static final String FUNCTION_NAME = "serviceScheme";
-      @Override
-      public String name() {
-      return FUNCTION_NAME;
-    }
+  public static final String FUNCTION_NAME = "serviceScheme";
+
+  @Override
+  public String name() {
+    return FUNCTION_NAME;
+  }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceAddressFunctionProcessor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceAddressFunctionProcessor.java b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceAddressFunctionProcessor.java
index 350b6f9..c8b53a3 100644
--- a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceAddressFunctionProcessor.java
+++ b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceAddressFunctionProcessor.java
@@ -17,6 +17,7 @@
  */
 package org.apache.hadoop.gateway.svcregfunc.impl;
 
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriter;
 import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteContext;
 import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
 import org.apache.hadoop.gateway.svcregfunc.api.ServiceAddressFunctionDescriptor;
@@ -25,6 +26,9 @@ import org.apache.hadoop.gateway.util.urltemplate.Parser;
 import org.apache.hadoop.gateway.util.urltemplate.Port;
 import org.apache.hadoop.gateway.util.urltemplate.Template;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class ServiceAddressFunctionProcessor
     extends ServiceRegistryFunctionProcessorBase<ServiceAddressFunctionDescriptor>
     implements UrlRewriteFunctionProcessor<ServiceAddressFunctionDescriptor> {
@@ -34,19 +38,43 @@ public class ServiceAddressFunctionProcessor
     return ServiceAddressFunctionDescriptor.FUNCTION_NAME;
   }
 
-  public String resolve( UrlRewriteContext context, String parameter ) throws Exception {
+  @Override
+  public List<String> resolve( UrlRewriteContext context, List<String> parameters ) throws Exception {
+    List<String> results = null;
+    if( parameters != null ) {
+      UrlRewriter.Direction direction = context.getDirection();
+      results = new ArrayList<String>( parameters.size() );
+      for( String parameter : parameters ) {
+        parameter = resolve( parameter );
+        results.add( parameter );
+      }
+    }
+    return results;
+  }
+
+  public String resolve( String parameter ) throws Exception {
     String addr = parameter;
-    String url = super.resolve( context, parameter );
+    String url = lookupServiceUrl( parameter );
     if( url != null ) {
       Template template = Parser.parse( url );
       Host host = template.getHost();
+      String hostStr = null;
+      if( host != null ) {
+        hostStr = host.getFirstValue().getPattern();
+      }
+
       Port port = template.getPort();
-      if( host != null && port != null ) {
-        addr = host.getFirstValue().getPattern() + ":" + port.getFirstValue().getPattern();
+      String portStr = null;
+      if( port != null ) {
+        portStr = port.getFirstValue().getPattern();
+      }
+
+      if( hostStr != null && portStr != null ) {
+        addr = hostStr + ":" + portStr;
       } else if( host != null && port == null ) {
-        addr = host.getFirstValue().getPattern();
+        addr = hostStr;
       } else if( host == null && port != null ) {
-        addr = ":" + port.getFirstValue().getPattern();
+        addr = ":" + portStr;
       }
     }
     return addr;

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceHostFunctionProcessor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceHostFunctionProcessor.java b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceHostFunctionProcessor.java
index 2f50a82..c9e7f9b 100644
--- a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceHostFunctionProcessor.java
+++ b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceHostFunctionProcessor.java
@@ -24,6 +24,9 @@ import org.apache.hadoop.gateway.util.urltemplate.Host;
 import org.apache.hadoop.gateway.util.urltemplate.Parser;
 import org.apache.hadoop.gateway.util.urltemplate.Template;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class ServiceHostFunctionProcessor
     extends ServiceRegistryFunctionProcessorBase<ServiceHostFunctionDescriptor>
     implements UrlRewriteFunctionProcessor<ServiceHostFunctionDescriptor> {
@@ -33,17 +36,24 @@ public class ServiceHostFunctionProcessor
     return ServiceHostFunctionDescriptor.FUNCTION_NAME;
   }
 
-  public String resolve( UrlRewriteContext context, String parameter ) throws Exception {
-    String value = parameter;
-    String url = super.resolve( context, parameter );
-    if( url != null && !url.equals( parameter ) ) {
-      Template template = Parser.parse( url );
-      Host host = template.getHost();
-      if( host != null ) {
-        value = host.getFirstValue().getPattern();
+  @Override
+  public List<String> resolve( UrlRewriteContext context, List<String> parameters ) throws Exception {
+    List<String> results = null;
+    if( parameters != null ) {
+      results = new ArrayList<String>( parameters.size() );
+      for( String parameter : parameters ) {
+        String url = lookupServiceUrl( parameter );
+        if( url != null ) {
+          Template template = Parser.parse( url );
+          Host host = template.getHost();
+          if( host != null ) {
+            parameter = host.getFirstValue().getPattern();
+          }
+        }
+        results.add( parameter );
       }
     }
-    return value;
+    return results;
   }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedAddressFunctionProcessor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedAddressFunctionProcessor.java b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedAddressFunctionProcessor.java
new file mode 100644
index 0000000..5809eb8
--- /dev/null
+++ b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedAddressFunctionProcessor.java
@@ -0,0 +1,110 @@
+/**
+ * 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.svcregfunc.impl;
+
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteEnvironment;
+import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteContext;
+import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
+import org.apache.hadoop.gateway.services.GatewayServices;
+import org.apache.hadoop.gateway.services.hostmap.HostMapper;
+import org.apache.hadoop.gateway.services.hostmap.HostMapperService;
+import org.apache.hadoop.gateway.svcregfunc.api.ServiceMappedAddressFunctionDescriptor;
+import org.apache.hadoop.gateway.util.urltemplate.Host;
+import org.apache.hadoop.gateway.util.urltemplate.Parser;
+import org.apache.hadoop.gateway.util.urltemplate.Port;
+import org.apache.hadoop.gateway.util.urltemplate.Template;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriter.Direction;
+
+public class ServiceMappedAddressFunctionProcessor
+    extends ServiceRegistryFunctionProcessorBase<ServiceMappedAddressFunctionDescriptor>
+    implements UrlRewriteFunctionProcessor<ServiceMappedAddressFunctionDescriptor> {
+
+  private HostMapper hostmap = null;
+
+  @Override
+  public String name() {
+    return ServiceMappedAddressFunctionDescriptor.FUNCTION_NAME;
+  }
+
+  @Override
+  public void initialize( UrlRewriteEnvironment environment, ServiceMappedAddressFunctionDescriptor descriptor ) throws Exception {
+    super.initialize( environment, descriptor );
+    HostMapperService hostmapService = services().getService( GatewayServices.HOST_MAPPING_SERVICE );
+    if( hostmapService != null ) {
+      hostmap = hostmapService.getHostMapper( cluster() );
+    }
+  }
+
+  @Override
+  public List<String> resolve( UrlRewriteContext context, List<String> parameters ) throws Exception {
+    List<String> results = null;
+    if( parameters != null ) {
+      Direction direction = context.getDirection();
+      results = new ArrayList<String>( parameters.size() );
+      for( String parameter : parameters ) {
+        parameter = resolve( direction, parameter );
+        results.add( parameter );
+      }
+    }
+    return results;
+  }
+
+  public String resolve( Direction direction, String parameter ) throws Exception {
+    String addr = parameter;
+    String url = lookupServiceUrl( parameter );
+    if( url != null ) {
+      Template template = Parser.parse( url );
+      Host host = template.getHost();
+      String hostStr = null;
+      if( host != null ) {
+        hostStr = host.getFirstValue().getPattern();
+        if( hostmap != null ) {
+          switch( direction ) {
+            case IN:
+              hostStr = hostmap.resolveInboundHostName( hostStr );
+              break;
+            case OUT:
+              hostStr = hostmap.resolveOutboundHostName( hostStr );
+              break;
+          }
+        }
+      }
+
+      Port port = template.getPort();
+      String portStr = null;
+      if( port != null ) {
+        portStr = port.getFirstValue().getPattern();
+      }
+
+      if( hostStr != null && portStr != null ) {
+        addr = hostStr + ":" + portStr;
+      } else if( host != null && port == null ) {
+        addr = hostStr;
+      } else if( host == null && port != null ) {
+        addr = ":" + portStr;
+      }
+    }
+    return addr;
+  }
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedHostFunctionProcessor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedHostFunctionProcessor.java b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedHostFunctionProcessor.java
new file mode 100644
index 0000000..d7ab283
--- /dev/null
+++ b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedHostFunctionProcessor.java
@@ -0,0 +1,87 @@
+/**
+ * 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.svcregfunc.impl;
+
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteEnvironment;
+import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteContext;
+import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
+import org.apache.hadoop.gateway.services.GatewayServices;
+import org.apache.hadoop.gateway.services.hostmap.HostMapper;
+import org.apache.hadoop.gateway.services.hostmap.HostMapperService;
+import org.apache.hadoop.gateway.svcregfunc.api.ServiceMappedHostFunctionDescriptor;
+import org.apache.hadoop.gateway.util.urltemplate.Host;
+import org.apache.hadoop.gateway.util.urltemplate.Parser;
+import org.apache.hadoop.gateway.util.urltemplate.Template;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ServiceMappedHostFunctionProcessor
+    extends ServiceRegistryFunctionProcessorBase<ServiceMappedHostFunctionDescriptor>
+    implements UrlRewriteFunctionProcessor<ServiceMappedHostFunctionDescriptor> {
+
+  private HostMapper hostmap;
+
+  @Override
+  public String name() {
+    return ServiceMappedHostFunctionDescriptor.FUNCTION_NAME;
+  }
+
+  @Override
+  public void initialize( UrlRewriteEnvironment environment, ServiceMappedHostFunctionDescriptor descriptor ) throws Exception {
+    super.initialize( environment, descriptor );
+    HostMapperService hostmapService = services().getService( GatewayServices.HOST_MAPPING_SERVICE );
+    if( hostmapService != null ) {
+      hostmap = hostmapService.getHostMapper( cluster() );
+    }
+  }
+
+  @Override
+  public List<String> resolve( UrlRewriteContext context, List<String> parameters ) throws Exception {
+    List<String> results = null;
+    if( parameters != null ) {
+      results = new ArrayList<String>( parameters.size() );
+      for( String parameter : parameters ) {
+        String url = lookupServiceUrl( parameter );
+        if( url != null ) {
+          Template template = Parser.parse( url );
+          Host host = template.getHost();
+          if( host != null ) {
+            String hostStr = host.getFirstValue().getPattern();
+            if( hostmap != null ) {
+              switch( context.getDirection() ) {
+                case IN:
+                  parameter = hostmap.resolveInboundHostName( hostStr );
+                  break;
+                case OUT:
+                  parameter = hostmap.resolveOutboundHostName( hostStr );
+                  break;
+              }
+            } else {
+              parameter = hostStr;
+            }
+          }
+        }
+        results.add( parameter );
+      }
+    }
+    return results;
+  }
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedUrlFunctionProcessor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedUrlFunctionProcessor.java b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedUrlFunctionProcessor.java
new file mode 100644
index 0000000..2747681
--- /dev/null
+++ b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedUrlFunctionProcessor.java
@@ -0,0 +1,90 @@
+/**
+ * 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.svcregfunc.impl;
+
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteEnvironment;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriter;
+import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteContext;
+import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
+import org.apache.hadoop.gateway.services.GatewayServices;
+import org.apache.hadoop.gateway.services.hostmap.HostMapper;
+import org.apache.hadoop.gateway.services.hostmap.HostMapperService;
+import org.apache.hadoop.gateway.svcregfunc.api.ServiceMappedUrlFunctionDescriptor;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ServiceMappedUrlFunctionProcessor
+    extends ServiceRegistryFunctionProcessorBase<ServiceMappedUrlFunctionDescriptor>
+    implements UrlRewriteFunctionProcessor<ServiceMappedUrlFunctionDescriptor> {
+
+  private HostMapper hostmap;
+
+  @Override
+  public String name() {
+    return ServiceMappedUrlFunctionDescriptor.FUNCTION_NAME;
+  }
+
+  @Override
+  public void initialize( UrlRewriteEnvironment environment, ServiceMappedUrlFunctionDescriptor descriptor ) throws Exception {
+    super.initialize( environment, descriptor );
+    HostMapperService hostmapService = services().getService( GatewayServices.HOST_MAPPING_SERVICE );
+    if( hostmapService != null ) {
+      hostmap = hostmapService.getHostMapper( cluster() );
+    }
+  }
+
+  @Override
+  public List<String> resolve( UrlRewriteContext context, List<String> parameters ) throws Exception {
+    List<String> results = null;
+    if( parameters != null ) {
+      UrlRewriter.Direction direction = context.getDirection();
+      results = new ArrayList<String>( parameters.size() );
+      for( String parameter : parameters ) {
+        parameter = resolve( direction, parameter );
+        results.add( parameter );
+      }
+    }
+    return results;
+  }
+
+  public String resolve( UrlRewriter.Direction direction, String parameter ) throws Exception {
+    String url = lookupServiceUrl( parameter );
+    if( url != null ) {
+      URI outputUri;
+      URI inputUri = new URI( url );
+      String host = inputUri.getHost();
+      if( host != null && hostmap != null ) {
+        switch( direction ) {
+          case IN:
+            host = hostmap.resolveInboundHostName( host );
+            break;
+          case OUT:
+            host = hostmap.resolveOutboundHostName( host );
+            break;
+        }
+      }
+      outputUri = new URI( inputUri.getScheme(), inputUri.getUserInfo(), host, inputUri.getPort(), inputUri.getPath(), inputUri.getQuery(), inputUri.getFragment() );
+      parameter = outputUri.toString();
+    }
+    return parameter;
+  }
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServicePathFunctionProcessor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServicePathFunctionProcessor.java b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServicePathFunctionProcessor.java
index 4d2500d..d3a1229 100644
--- a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServicePathFunctionProcessor.java
+++ b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServicePathFunctionProcessor.java
@@ -24,6 +24,7 @@ import org.apache.hadoop.gateway.util.urltemplate.Parser;
 import org.apache.hadoop.gateway.util.urltemplate.Path;
 import org.apache.hadoop.gateway.util.urltemplate.Template;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public class ServicePathFunctionProcessor
@@ -35,19 +36,24 @@ public class ServicePathFunctionProcessor
     return ServicePathFunctionDescriptor.FUNCTION_NAME;
   }
 
-  public String resolve( UrlRewriteContext context, String parameter ) throws Exception {
-    String value = parameter;
-    String url = super.resolve( context, parameter );
-    if( url != null && !url.equals(  parameter ) ) {
-      Template template = Parser.parse( url );
-      List<Path> path = template.getPath();
-      if( path != null ) {
-        value = toString( path );
-      } else {
-        value = parameter;
+  @Override
+  public List<String> resolve( UrlRewriteContext context, List<String> parameters ) throws Exception {
+    List<String> results = null;
+    if( parameters != null ) {
+      results = new ArrayList<String>( parameters.size() );
+      for( String parameter : parameters ) {
+        String url = lookupServiceUrl( parameter );
+        if( url != null ) {
+          Template template = Parser.parse( url );
+          List<Path> path = template.getPath();
+          if( path != null ) {
+            parameter = toString( path );
+          }
+        }
+        results.add( parameter );
       }
     }
-    return value;
+    return results;
   }
 
   private String toString( List<Path> paths ) {

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServicePortFunctionProcessor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServicePortFunctionProcessor.java b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServicePortFunctionProcessor.java
index e4a5c79..7226922 100644
--- a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServicePortFunctionProcessor.java
+++ b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServicePortFunctionProcessor.java
@@ -24,6 +24,9 @@ import org.apache.hadoop.gateway.util.urltemplate.Parser;
 import org.apache.hadoop.gateway.util.urltemplate.Port;
 import org.apache.hadoop.gateway.util.urltemplate.Template;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class ServicePortFunctionProcessor
     extends ServiceRegistryFunctionProcessorBase<ServicePortFunctionDescriptor>
     implements UrlRewriteFunctionProcessor<ServicePortFunctionDescriptor> {
@@ -33,17 +36,24 @@ public class ServicePortFunctionProcessor
     return ServicePortFunctionDescriptor.FUNCTION_NAME;
   }
 
-  public String resolve( UrlRewriteContext context, String parameter ) throws Exception {
-    String value = parameter;
-    String url = super.resolve( context, value );
-    if( url != null && !url.equals( parameter ) ) {
-      Template template = Parser.parse( url );
-      Port port = template.getPort();
-      if( port != null ) {
-        value = port.getFirstValue().getPattern();
+  @Override
+  public List<String> resolve( UrlRewriteContext context, List<String> parameters ) throws Exception {
+    List<String> results = null;
+    if( parameters != null ) {
+      results = new ArrayList<String>( parameters.size() );
+      for( String parameter : parameters ) {
+        String url = lookupServiceUrl( parameter );
+        if( url != null ) {
+          Template template = Parser.parse( url );
+          Port port = template.getPort();
+          if( port != null ) {
+            parameter = port.getFirstValue().getPattern();
+          }
+        }
+        results.add( parameter );
       }
     }
-    return value;
+    return results;
   }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceRegistryFunctionProcessorBase.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceRegistryFunctionProcessorBase.java b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceRegistryFunctionProcessorBase.java
index 432a771..5e4479f 100644
--- a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceRegistryFunctionProcessorBase.java
+++ b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceRegistryFunctionProcessorBase.java
@@ -19,7 +19,6 @@ package org.apache.hadoop.gateway.svcregfunc.impl;
 
 import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteEnvironment;
 import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor;
-import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteContext;
 import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
 import org.apache.hadoop.gateway.services.GatewayServices;
 import org.apache.hadoop.gateway.services.registry.ServiceRegistry;
@@ -27,6 +26,7 @@ import org.apache.hadoop.gateway.services.registry.ServiceRegistry;
 abstract class ServiceRegistryFunctionProcessorBase<T extends UrlRewriteFunctionDescriptor> implements UrlRewriteFunctionProcessor<T> {
 
   private String cluster;
+  private GatewayServices services;
   private ServiceRegistry registry;
 
   @Override
@@ -38,7 +38,7 @@ abstract class ServiceRegistryFunctionProcessorBase<T extends UrlRewriteFunction
     if( cluster == null ) {
       throw new IllegalArgumentException( "cluster==null" );
     }
-    GatewayServices services = environment.getAttribute( GatewayServices.GATEWAY_SERVICES_ATTRIBUTE );
+    services = environment.getAttribute( GatewayServices.GATEWAY_SERVICES_ATTRIBUTE );
     if( services == null ) {
       throw new IllegalArgumentException( "services==null" );
     }
@@ -54,20 +54,19 @@ abstract class ServiceRegistryFunctionProcessorBase<T extends UrlRewriteFunction
     cluster = null;
   }
 
-
-  public String resolve( UrlRewriteContext context, String parameter ) throws Exception {
-    String value = parameter;
-    String url = registry.lookupServiceURL( cluster, parameter );
-    if( url != null ) {
-      value = url;
-    }
-    return value;
+  public String lookupServiceUrl( String role ) throws Exception {
+    String url = registry.lookupServiceURL( cluster, role );
+    return url;
   }
 
   String cluster() {
     return cluster;
   }
 
+  GatewayServices services() {
+    return services;
+  }
+
   ServiceRegistry registry() {
     return registry;
   }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceSchemeFunctionProcessor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceSchemeFunctionProcessor.java b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceSchemeFunctionProcessor.java
index 450df00..919f5c4 100644
--- a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceSchemeFunctionProcessor.java
+++ b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceSchemeFunctionProcessor.java
@@ -24,6 +24,9 @@ import org.apache.hadoop.gateway.util.urltemplate.Parser;
 import org.apache.hadoop.gateway.util.urltemplate.Scheme;
 import org.apache.hadoop.gateway.util.urltemplate.Template;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class ServiceSchemeFunctionProcessor
     extends ServiceRegistryFunctionProcessorBase<ServiceSchemeFunctionDescriptor>
     implements UrlRewriteFunctionProcessor<ServiceSchemeFunctionDescriptor> {
@@ -33,17 +36,24 @@ public class ServiceSchemeFunctionProcessor
     return ServiceSchemeFunctionDescriptor.FUNCTION_NAME;
   }
 
-  public String resolve( UrlRewriteContext context, String parameter ) throws Exception {
-    String value = parameter;
-    String url = super.resolve( context, parameter );
-    if( url != null && !url.equals( parameter ) ) {
-      Template template = Parser.parse( url );
-      Scheme scheme = template.getScheme();
-      if( scheme != null ) {
-        value = scheme.getFirstValue().getPattern();
+  @Override
+  public List<String> resolve( UrlRewriteContext context, List<String> parameters ) throws Exception {
+    List<String> results = null;
+    if( parameters != null ) {
+      results = new ArrayList<String>( parameters.size() );
+      for( String parameter : parameters ) {
+        String url = lookupServiceUrl( parameter );
+        if( url != null && !url.equals( parameter ) ) {
+          Template template = Parser.parse( url );
+          Scheme scheme = template.getScheme();
+          if( scheme != null ) {
+            parameter = scheme.getFirstValue().getPattern();
+          }
+        }
+        results.add( parameter );
       }
     }
-    return value;
+    return results;
   }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceUrlFunctionProcessor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceUrlFunctionProcessor.java b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceUrlFunctionProcessor.java
index dd4ed0e..2adb3ff 100644
--- a/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceUrlFunctionProcessor.java
+++ b/gateway-provider-rewrite-func-service-registry/src/main/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceUrlFunctionProcessor.java
@@ -17,10 +17,15 @@
  */
 package org.apache.hadoop.gateway.svcregfunc.impl;
 
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriter;
 import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteContext;
 import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
 import org.apache.hadoop.gateway.svcregfunc.api.ServiceUrlFunctionDescriptor;
 
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
 public class ServiceUrlFunctionProcessor
     extends ServiceRegistryFunctionProcessorBase<ServiceUrlFunctionDescriptor>
     implements UrlRewriteFunctionProcessor<ServiceUrlFunctionDescriptor> {
@@ -30,8 +35,30 @@ public class ServiceUrlFunctionProcessor
     return ServiceUrlFunctionDescriptor.FUNCTION_NAME;
   }
 
-  public String resolve( UrlRewriteContext context, String parameter ) throws Exception {
-    return super.resolve( context, parameter );
+  @Override
+  public List<String> resolve( UrlRewriteContext context, List<String> parameters ) throws Exception {
+    List<String> results = null;
+    if( parameters != null ) {
+      UrlRewriter.Direction direction = context.getDirection();
+      results = new ArrayList<String>( parameters.size() );
+      for( String parameter : parameters ) {
+        parameter = resolve( parameter );
+        results.add( parameter );
+      }
+    }
+    return results;
+  }
+
+  public String resolve( String parameter ) throws Exception {
+    String url = lookupServiceUrl( parameter );
+    if( url != null ) {
+      URI outputUri;
+      URI inputUri = new URI( url );
+      String host = inputUri.getHost();
+      outputUri = new URI( inputUri.getScheme(), inputUri.getUserInfo(), host, inputUri.getPort(), inputUri.getPath(), inputUri.getQuery(), inputUri.getFragment() );
+      parameter = outputUri.toString();
+    }
+    return parameter;
   }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/main/resources/META-INF/services/org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/main/resources/META-INF/services/org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor b/gateway-provider-rewrite-func-service-registry/src/main/resources/META-INF/services/org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor
index 8f50977..17adf92 100644
--- a/gateway-provider-rewrite-func-service-registry/src/main/resources/META-INF/services/org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor
+++ b/gateway-provider-rewrite-func-service-registry/src/main/resources/META-INF/services/org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor
@@ -21,4 +21,7 @@ org.apache.hadoop.gateway.svcregfunc.api.ServiceAddressFunctionDescriptor
 org.apache.hadoop.gateway.svcregfunc.api.ServiceSchemeFunctionDescriptor
 org.apache.hadoop.gateway.svcregfunc.api.ServiceHostFunctionDescriptor
 org.apache.hadoop.gateway.svcregfunc.api.ServicePortFunctionDescriptor
-org.apache.hadoop.gateway.svcregfunc.api.ServicePathFunctionDescriptor
\ No newline at end of file
+org.apache.hadoop.gateway.svcregfunc.api.ServicePathFunctionDescriptor
+org.apache.hadoop.gateway.svcregfunc.api.ServiceMappedUrlFunctionDescriptor
+org.apache.hadoop.gateway.svcregfunc.api.ServiceMappedAddressFunctionDescriptor
+org.apache.hadoop.gateway.svcregfunc.api.ServiceMappedHostFunctionDescriptor

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/main/resources/META-INF/services/org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/main/resources/META-INF/services/org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor b/gateway-provider-rewrite-func-service-registry/src/main/resources/META-INF/services/org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor
index d241c10..498d286 100644
--- a/gateway-provider-rewrite-func-service-registry/src/main/resources/META-INF/services/org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor
+++ b/gateway-provider-rewrite-func-service-registry/src/main/resources/META-INF/services/org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor
@@ -21,4 +21,7 @@ org.apache.hadoop.gateway.svcregfunc.impl.ServiceAddressFunctionProcessor
 org.apache.hadoop.gateway.svcregfunc.impl.ServiceSchemeFunctionProcessor
 org.apache.hadoop.gateway.svcregfunc.impl.ServiceHostFunctionProcessor
 org.apache.hadoop.gateway.svcregfunc.impl.ServicePortFunctionProcessor
-org.apache.hadoop.gateway.svcregfunc.impl.ServicePathFunctionProcessor
\ No newline at end of file
+org.apache.hadoop.gateway.svcregfunc.impl.ServicePathFunctionProcessor
+org.apache.hadoop.gateway.svcregfunc.impl.ServiceMappedUrlFunctionProcessor
+org.apache.hadoop.gateway.svcregfunc.impl.ServiceMappedAddressFunctionProcessor
+org.apache.hadoop.gateway.svcregfunc.impl.ServiceMappedHostFunctionProcessor

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceAddressFunctionProcessorTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceAddressFunctionProcessorTest.java b/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceAddressFunctionProcessorTest.java
index 21f2bf5..5e99482 100644
--- a/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceAddressFunctionProcessorTest.java
+++ b/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceAddressFunctionProcessorTest.java
@@ -23,11 +23,11 @@ import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
 import org.apache.hadoop.gateway.services.GatewayServices;
 import org.apache.hadoop.gateway.services.registry.ServiceRegistry;
 import org.apache.hadoop.gateway.svcregfunc.api.ServiceAddressFunctionDescriptor;
-import org.apache.hadoop.gateway.svcregfunc.api.ServiceSchemeFunctionDescriptor;
 import org.easymock.EasyMock;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.ServiceLoader;
 
@@ -36,6 +36,7 @@ import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.CoreMatchers.sameInstance;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
 import static org.junit.Assert.fail;
 
 public class ServiceAddressFunctionProcessorTest {
@@ -124,8 +125,8 @@ public class ServiceAddressFunctionProcessorTest {
     ServiceAddressFunctionProcessor func = new ServiceAddressFunctionProcessor();
     func.initialize( env, desc );
 
-    assertThat( func.resolve( ctx, "test-service" ), is( "test-host:777" ) );
-    assertThat( func.resolve( ctx, "invalid-test-service" ), is( "invalid-test-service" ) );
+    assertThat( func.resolve( ctx, Arrays.asList( "test-service" ) ), contains( "test-host:777" ) );
+    assertThat( func.resolve( ctx, Arrays.asList( "invalid-test-service" ) ), contains( "invalid-test-service" ) );
     assertThat( func.resolve( ctx, null ), nullValue() );
 
     func.destroy();

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceHostFunctionProcessorTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceHostFunctionProcessorTest.java b/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceHostFunctionProcessorTest.java
index 9544174..e9f2e6b 100644
--- a/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceHostFunctionProcessorTest.java
+++ b/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceHostFunctionProcessorTest.java
@@ -22,13 +22,12 @@ import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteContext;
 import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
 import org.apache.hadoop.gateway.services.GatewayServices;
 import org.apache.hadoop.gateway.services.registry.ServiceRegistry;
-import org.apache.hadoop.gateway.svcregfunc.api.ServiceAddressFunctionDescriptor;
 import org.apache.hadoop.gateway.svcregfunc.api.ServiceHostFunctionDescriptor;
-import org.apache.hadoop.gateway.svcregfunc.api.ServiceSchemeFunctionDescriptor;
 import org.easymock.EasyMock;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.ServiceLoader;
 
@@ -37,6 +36,7 @@ import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.CoreMatchers.sameInstance;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
 import static org.junit.Assert.fail;
 
 public class ServiceHostFunctionProcessorTest {
@@ -125,8 +125,8 @@ public class ServiceHostFunctionProcessorTest {
     ServiceHostFunctionProcessor func = new ServiceHostFunctionProcessor();
     func.initialize( env, desc );
 
-    assertThat( func.resolve( ctx, "test-service" ), is( "test-host" ) );
-    assertThat( func.resolve( ctx, "invalid-test-service" ), is( "invalid-test-service" ) );
+    assertThat( func.resolve( ctx, Arrays.asList( "test-service" ) ), contains( "test-host" ) );
+    assertThat( func.resolve( ctx, Arrays.asList( "invalid-test-service" ) ), contains( "invalid-test-service" ) );
     assertThat( func.resolve( ctx, null ), nullValue() );
 
     func.destroy();

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e338fe64/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedAddressFunctionProcessorTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedAddressFunctionProcessorTest.java b/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedAddressFunctionProcessorTest.java
new file mode 100644
index 0000000..c1f2b06
--- /dev/null
+++ b/gateway-provider-rewrite-func-service-registry/src/test/java/org/apache/hadoop/gateway/svcregfunc/impl/ServiceMappedAddressFunctionProcessorTest.java
@@ -0,0 +1,148 @@
+/**
+ * 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.svcregfunc.impl;
+
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteEnvironment;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriter;
+import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteContext;
+import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
+import org.apache.hadoop.gateway.services.GatewayServices;
+import org.apache.hadoop.gateway.services.hostmap.HostMapper;
+import org.apache.hadoop.gateway.services.hostmap.HostMapperService;
+import org.apache.hadoop.gateway.services.registry.ServiceRegistry;
+import org.apache.hadoop.gateway.svcregfunc.api.ServiceMappedAddressFunctionDescriptor;
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.ServiceLoader;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
+import static org.junit.Assert.fail;
+
+public class ServiceMappedAddressFunctionProcessorTest {
+
+  HostMapperService hms;
+  HostMapper hm;
+  ServiceRegistry reg;
+  GatewayServices svc;
+  UrlRewriteEnvironment env;
+  UrlRewriteContext ctx;
+  ServiceMappedAddressFunctionDescriptor desc;
+
+  @Before
+  public void setUp() {
+    hm = EasyMock.createNiceMock( HostMapper.class );
+    EasyMock.expect( hm.resolveInboundHostName( "test-host" ) ).andReturn( "test-internal-host" ).anyTimes();
+
+    hms = EasyMock.createNiceMock( HostMapperService.class );
+    EasyMock.expect( hms.getHostMapper( "test-cluster" ) ).andReturn( hm ).anyTimes();
+
+    reg = EasyMock.createNiceMock( ServiceRegistry.class );
+    EasyMock.expect( reg.lookupServiceURL( "test-cluster", "test-service" ) ).andReturn( "test-scheme://test-host:777/test-path" ).anyTimes();
+
+    svc = EasyMock.createNiceMock( GatewayServices.class );
+    EasyMock.expect( svc.getService( GatewayServices.SERVICE_REGISTRY_SERVICE ) ).andReturn( reg ).anyTimes();
+    EasyMock.expect( svc.getService( GatewayServices.HOST_MAPPING_SERVICE ) ).andReturn( hms ).anyTimes();
+
+    env = EasyMock.createNiceMock( UrlRewriteEnvironment.class );
+    EasyMock.expect( env.getAttribute( GatewayServices.GATEWAY_SERVICES_ATTRIBUTE ) ).andReturn( svc ).anyTimes();
+    EasyMock.expect( env.getAttribute( GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE ) ).andReturn( "test-cluster" ).anyTimes();
+
+    ctx = EasyMock.createNiceMock( UrlRewriteContext.class );
+    EasyMock.expect( ctx.getDirection() ).andReturn( UrlRewriter.Direction.IN ).anyTimes();
+
+    desc = EasyMock.createNiceMock( ServiceMappedAddressFunctionDescriptor.class );
+
+    EasyMock.replay( hm, hms, reg, svc, env, desc, ctx );
+  }
+
+  @Test
+  public void testServiceLoader() throws Exception {
+    ServiceLoader loader = ServiceLoader.load( UrlRewriteFunctionProcessor.class );
+    Iterator iterator = loader.iterator();
+    assertThat( "Service iterator empty.", iterator.hasNext() );
+    while( iterator.hasNext() ) {
+      Object object = iterator.next();
+      if( object instanceof ServiceMappedAddressFunctionProcessor ) {
+        return;
+      }
+    }
+    fail( "Failed to find " + ServiceMappedAddressFunctionProcessor.class.getName() + " via service loader." );
+  }
+
+  @Test
+  public void testName() throws Exception {
+    ServiceMappedAddressFunctionProcessor func = new ServiceMappedAddressFunctionProcessor();
+    assertThat( func.name(), is( "serviceMappedAddr" ) );
+  }
+
+  @Test
+  public void testInitialize() throws Exception {
+    ServiceMappedAddressFunctionProcessor func = new ServiceMappedAddressFunctionProcessor();
+    try {
+      func.initialize( null, desc );
+      fail( "Should have thrown an IllegalArgumentException" );
+    } catch( IllegalArgumentException e ) {
+      assertThat( e.getMessage(), containsString( "environment" ) );
+    }
+
+    func = new ServiceMappedAddressFunctionProcessor();
+    try {
+      func.initialize( env, null );
+    } catch( Exception e ) {
+      e.printStackTrace();
+      fail( "Should not have thrown an exception" );
+    }
+
+    func.initialize( env, desc );
+
+    assertThat( func.cluster(), is( "test-cluster" ) );
+    assertThat( func.registry(), sameInstance( reg ) );
+  }
+
+  @Test
+  public void testDestroy() throws Exception {
+    ServiceMappedAddressFunctionProcessor func = new ServiceMappedAddressFunctionProcessor();
+    func.initialize( env, desc );
+    func.destroy();
+
+    assertThat( func.cluster(), nullValue() );
+    assertThat( func.registry(), nullValue() );
+  }
+
+  @Test
+  public void testResolve() throws Exception {
+    ServiceMappedAddressFunctionProcessor func = new ServiceMappedAddressFunctionProcessor();
+    func.initialize( env, desc );
+
+    assertThat( func.resolve( ctx, Arrays.asList( "test-service" ) ), contains( "test-internal-host:777" ) );
+    assertThat( func.resolve( ctx, Arrays.asList( "invalid-test-service" ) ), contains( "invalid-test-service" ) );
+    assertThat( func.resolve( ctx, null ), nullValue() );
+
+    func.destroy();
+  }
+
+}