knox-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kmin...@apache.org
Subject [3/6] KNOX-77: Add support for selecting rewrite rules by path.
Date Fri, 16 Aug 2013 20:55:11 GMT
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest.java b/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest.java
index d5af677..833a927 100644
--- a/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest.java
+++ b/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest.java
@@ -19,31 +19,45 @@ package org.apache.hadoop.gateway.filter.rewrite.impl.json;
 
 import com.jayway.jsonassert.JsonAssert;
 import org.apache.commons.io.IOUtils;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFilterApplyDescriptor;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFilterBufferDescriptor;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFilterDescriptor;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFilterDetectDescriptor;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteRulesDescriptor;
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteRulesDescriptorFactory;
+import org.apache.hadoop.gateway.filter.rewrite.impl.xml.XmlFilterReader;
+import org.apache.hadoop.test.TestUtils;
 import org.junit.Test;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.StringReader;
+import java.nio.charset.Charset;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.fail;
 
 public class JsonFilterReaderTest {
 
   @Test
   public void testSimple() throws IOException {
-    String inputJson = "{ \"name\" : \"value\" }";
+    String inputJson = "{ \"test-name\" : \"test-value\" }";
     StringReader inputReader = new StringReader( inputJson );
-    JsonFilterReader filterReader = new JsonFilterReader( inputReader );
+    JsonFilterReader filterReader = new TestJsonFilterReader( inputReader, null );
     String outputJson = new String( IOUtils.toCharArray( filterReader ) );
+    //System.out.println( "JSON=" + outputJson );
 
-    JsonAssert.with( outputJson ).assertThat( "name", is( "value" ) );
+    JsonAssert.with( outputJson ).assertThat( "name<test-name>", is( "value:null<test-value>" ) );
   }
 
   @Test
   public void testEmptyObject() throws IOException {
     String inputJson = "{}";
     StringReader inputReader = new StringReader( inputJson );
-    JsonFilterReader filterReader = new JsonFilterReader( inputReader );
+    JsonFilterReader filterReader = new TestJsonFilterReader( inputReader, null );
     String outputJson = new String( IOUtils.toCharArray( filterReader ) );
 
     assertThat( outputJson, is( "{}" ) );
@@ -53,10 +67,218 @@ public class JsonFilterReaderTest {
   public void testEmptyArray() throws IOException {
     String inputJson = "[]";
     StringReader inputReader = new StringReader( inputJson );
-    JsonFilterReader filterReader = new JsonFilterReader( inputReader );
+    JsonFilterReader filterReader = new TestJsonFilterReader( inputReader, null );
     String outputJson = new String( IOUtils.toCharArray( filterReader ) );
 
     assertThat( outputJson, is( "[]" ) );
   }
 
+  @Test
+  public void testUnscopedStreaming() throws IOException {
+    InputStream stream = TestUtils.getResourceStream( this.getClass(), "simple-values.json" );
+    String input = IOUtils.toString( stream, Charset.forName( "UTF-8" ) );
+
+    //System.out.println( "INPUT=" + input );
+
+    UrlRewriteRulesDescriptor rulesConfig = UrlRewriteRulesDescriptorFactory.create();
+    UrlRewriteFilterDescriptor filterConfig = rulesConfig.addFilter( "filter=1" );
+    UrlRewriteFilterContentDescriptor contentConfig = filterConfig.addContent( "text/json" );
+    UrlRewriteFilterApplyDescriptor applyConfig = contentConfig.addApply( "$['test-str']", "test-rule" );
+
+    JsonFilterReader filter = new TestJsonFilterReader( new StringReader( input ), contentConfig );
+    String output = IOUtils.toString( filter );
+
+    //System.out.println( "OUTPUT=" + output );
+
+    JsonAssert.with( output ).assertThat( "name<test-str>", is( "value:null<text>" ) );
+  }
+
+//  @Test
+//  public void testJsonPathObject() throws IOException {
+//    InputStream stream = TestUtils.getResourceStream( this.getClass(), "complex.json" );
+//    String input = IOUtils.toString( stream, Charset.forName( "UTF-8" ) );
+//
+//    Object o;
+//
+//    o = JsonPath.read( "$", input, JsonNode.class );
+//    assertThat( o, instanceOf( ObjectNode.class ) );
+//    assertThat( o.toString(), startsWith( "{" ) );
+//    System.out.println( o.getClass() + "=" + o );
+//
+//    o = JsonPath.read( "$['test-str']", input, JsonNode.class );
+//    System.out.println( o.getClass() + "=" + o );
+//
+//    o = JsonPath.read( "$['test-obj-multi']", input, JsonNode.class );
+//    System.out.println( o.getClass() + "=" + o );
+//
+//    o = JsonPath.read( "$['val']", (JsonNode)o, JsonNode.class );
+//    System.out.println( o.getClass() + "=" + o );
+//
+//    JsonPath p = JsonPath.compile( "$['test-obj-multi']['val']" );
+//    o = JsonPath.read( "$['test-obj-multi']['val']", input, JsonNode.class );
+//    JsonNode pp = ((JsonNode)o).findParent("val");
+//    System.out.println( "$['test-obj-multi']['val']=" + o.getClass() + "=" + o );
+//
+//  }
+//
+//  @Test
+//  public void testJsonPathArray() throws IOException {
+//    InputStream stream = TestUtils.getResourceStream( this.getClass(), "array.json" );
+//    String input = IOUtils.toString( stream, Charset.forName( "UTF-8" ) );
+//
+//    Object o;
+//
+//    o = JsonPath.read( "$", input, JsonNode.class );
+//    System.out.println( o.getClass() + "=" + o );
+//
+//    o = JsonPath.read( "$[0]", input, JsonNode.class );
+//    System.out.println( o.getClass() + "=" + o );
+//
+//    o = JsonPath.read( "$[*]", input, JsonNode.class );
+//    System.out.println( "$[*]=" + o.getClass() + "=" + o );
+//
+//    o = JsonPath.read( "$['obj1-fld1']", (JsonNode)o, JsonNode.class );
+//    System.out.println( o.getClass() + "=" + o );
+//
+//    o = JsonPath.read( "$[0]['obj1-fld1']", input, JsonNode.class );
+//    System.out.println( o.getClass() + "=" + o );
+//
+//  }
+
+  @Test
+  public void testBuffered() throws IOException {
+    InputStream stream = TestUtils.getResourceStream( this.getClass(), "simple-values.json" );
+    String input = IOUtils.toString( stream, Charset.forName( "UTF-8" ) );
+
+    //System.out.println( "INPUT=" + input );
+
+    UrlRewriteRulesDescriptor rulesConfig = UrlRewriteRulesDescriptorFactory.create();
+    UrlRewriteFilterDescriptor filterConfig = rulesConfig.addFilter( "filter-1" );
+    UrlRewriteFilterContentDescriptor contentConfig = filterConfig.addContent( "text/json" );
+    UrlRewriteFilterBufferDescriptor bufferConfig = contentConfig.addBuffer( "$" );
+    UrlRewriteFilterApplyDescriptor applyConfig = bufferConfig.addApply( "$['name<test-str>']", "test-rule" );
+    //UrlRewriteRulesDescriptorFactory.store( rulesConfig, "xml", new PrintWriter( System.out ) );
+
+    JsonFilterReader filter = new TestJsonFilterReader( new StringReader( input ), contentConfig );
+    String output = IOUtils.toString( filter );
+
+    //System.out.println( "OUTPUT=" + output );
+
+    JsonAssert.with( output ).assertThat( "name<test-str>", is( "value:test-rule<text>" ) );
+  }
+
+  @Test
+  public void testBufferedDetectApply() throws IOException {
+    InputStream stream = TestUtils.getResourceStream( this.getClass(), "properties.json" );
+    String input = IOUtils.toString( stream, Charset.forName( "UTF-8" ) );
+
+    //System.out.println( "INPUT=" + input );
+
+    UrlRewriteRulesDescriptor rulesConfig = UrlRewriteRulesDescriptorFactory.create();
+    UrlRewriteFilterDescriptor filterConfig = rulesConfig.addFilter( "filter-1" );
+    UrlRewriteFilterContentDescriptor contentConfig = filterConfig.addContent( "text/json" );
+    UrlRewriteFilterBufferDescriptor bufferConfig = contentConfig.addBuffer( "$.name<properties>.*.name<property>" );
+    UrlRewriteFilterDetectDescriptor detectConfig = bufferConfig.addDetect( "$.name<property-name>", "test-name-2" );
+    UrlRewriteFilterApplyDescriptor applyConfig = detectConfig.addApply( "$.name<property-value>", "test-rule-2" );
+
+    //UrlRewriteRulesDescriptorFactory.store( rulesConfig, "xml", new PrintWriter( System.out ) );
+
+    JsonFilterReader filter = new TestJsonFilterReader( new StringReader( input ), contentConfig );
+    String output = IOUtils.toString( filter );
+
+    //System.out.println( "OUTPUT=" + output );
+
+    JsonAssert.with( output ).assertThat( "name<properties>[0].name<property>.name<property-name>", is( "test-name-1" ) );
+    JsonAssert.with( output ).assertThat( "name<properties>[0].name<property>.name<property-value>", is( "test-value-1" ) );
+    JsonAssert.with( output ).assertThat( "name<properties>[1].name<property>.name<property-name>", is( "test-name-2" ) );
+    JsonAssert.with( output ).assertThat( "name<properties>[1].name<property>.name<property-value>", is( "value:test-rule-2<test-value-2>" ) );
+    JsonAssert.with( output ).assertThat( "name<properties>[2].name<property>.name<property-name>", is( "test-name-3" ) );
+    JsonAssert.with( output ).assertThat( "name<properties>[2].name<property>.name<property-value>", is( "test-value-3" ) );
+  }
+
+  @Test
+  public void testBufferedApply() throws IOException {
+    InputStream stream = TestUtils.getResourceStream( this.getClass(), "properties.json" );
+    String input = IOUtils.toString( stream, Charset.forName( "UTF-8" ) );
+
+    //System.out.println( "INPUT=" + input );
+
+    UrlRewriteRulesDescriptor rulesConfig = UrlRewriteRulesDescriptorFactory.create();
+    UrlRewriteFilterDescriptor filterConfig = rulesConfig.addFilter( "filter-1" );
+    UrlRewriteFilterContentDescriptor contentConfig = filterConfig.addContent( "text/json" );
+    UrlRewriteFilterBufferDescriptor bufferConfig = contentConfig.addBuffer( "$.name<properties>.*.name<property>" );
+    UrlRewriteFilterApplyDescriptor applyConfig = bufferConfig.addApply( "$.name<property-value>", "test-rule" );
+
+    //UrlRewriteRulesDescriptorFactory.store( rulesConfig, "xml", new PrintWriter( System.out ) );
+
+    JsonFilterReader filter = new TestJsonFilterReader( new StringReader( input ), contentConfig );
+    String output = IOUtils.toString( filter );
+
+    //System.out.println( "OUTPUT=" + output );
+
+    JsonAssert.with( output ).assertThat( "name<properties>[0].name<property>.name<property-name>", is( "test-name-1" ) );
+    JsonAssert.with( output ).assertThat( "name<properties>[0].name<property>.name<property-value>", is( "value:test-rule<test-value-1>" ) );
+    JsonAssert.with( output ).assertThat( "name<properties>[1].name<property>.name<property-name>", is( "test-name-2" ) );
+    JsonAssert.with( output ).assertThat( "name<properties>[1].name<property>.name<property-value>", is( "value:test-rule<test-value-2>" ) );
+    JsonAssert.with( output ).assertThat( "name<properties>[2].name<property>.name<property-name>", is( "test-name-3" ) );
+    JsonAssert.with( output ).assertThat( "name<properties>[2].name<property>.name<property-value>", is( "value:test-rule<test-value-3>" ) );
+  }
+
+  @Test
+  public void testBufferedMultiApply() throws IOException {
+    InputStream stream = TestUtils.getResourceStream( this.getClass(), "properties.json" );
+    String input = IOUtils.toString( stream, Charset.forName( "UTF-8" ) );
+
+    //System.out.println( "INPUT=" + input );
+
+    UrlRewriteRulesDescriptor rulesConfig = UrlRewriteRulesDescriptorFactory.create();
+    UrlRewriteFilterDescriptor filterConfig = rulesConfig.addFilter( "filter-1" );
+    UrlRewriteFilterContentDescriptor contentConfig = filterConfig.addContent( "text/json" );
+    UrlRewriteFilterBufferDescriptor bufferConfig = contentConfig.addBuffer( "$.name<properties>" );
+    UrlRewriteFilterApplyDescriptor applyConfig = bufferConfig.addApply( "$.*.name<property>.name<property-value>", "test-rule" );
+
+    //UrlRewriteRulesDescriptorFactory.store( rulesConfig, "xml", new PrintWriter( System.out ) );
+
+    JsonFilterReader filter = new TestJsonFilterReader( new StringReader( input ), contentConfig );
+    String output = IOUtils.toString( filter );
+
+    //System.out.println( "OUTPUT=" + output );
+
+    JsonAssert.with( output ).assertThat( "name<properties>[0].name<property>.name<property-name>", is( "test-name-1" ) );
+    JsonAssert.with( output ).assertThat( "name<properties>[0].name<property>.name<property-value>", is( "value:test-rule<test-value-1>" ) );
+    JsonAssert.with( output ).assertThat( "name<properties>[1].name<property>.name<property-name>", is( "test-name-2" ) );
+    JsonAssert.with( output ).assertThat( "name<properties>[1].name<property>.name<property-value>", is( "value:test-rule<test-value-2>" ) );
+    JsonAssert.with( output ).assertThat( "name<properties>[2].name<property>.name<property-name>", is( "test-name-3" ) );
+    JsonAssert.with( output ).assertThat( "name<properties>[2].name<property>.name<property-value>", is( "value:test-rule<test-value-3>" ) );
+  }
+
+  @Test
+  public void testInvalidConfigShouldThrowException() throws Exception {
+    String input = "{ \"test-name\" : \"test-value\" }";
+
+    //System.out.println( "INPUT=" + input );
+
+    UrlRewriteRulesDescriptor rulesConfig = UrlRewriteRulesDescriptorFactory.create();
+    UrlRewriteFilterDescriptor filterConfig = rulesConfig.addFilter( "filter-1" );
+    UrlRewriteFilterContentDescriptor contentConfig = filterConfig.addContent( "*/json" );
+    contentConfig.addApply( "/root/@url", "test-rule" );
+
+    //UrlRewriteRulesDescriptorFactory.store( rulesConfig, "xml", new PrintWriter( System.out ) );
+
+    try {
+      JsonFilterReader filter = new TestJsonFilterReader( new StringReader( input ), contentConfig );
+      IOUtils.toString( filter );
+      fail( "Should have thrown an IllegalArgumentException." );
+    } catch ( IOException e ) {
+      fail( "Should have thrown an IllegalArgumentException." );
+    } catch ( IllegalArgumentException e ) {
+      assertThat( e.getMessage(), containsString( "/root/@url" ) );
+    }
+  }
+
+//  private void dump( ObjectMapper mapper, JsonGenerator generator, JsonNode node ) throws IOException {
+//    mapper.writeTree( generator, node );
+//    System.out.println();
+//  }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/json/TestJsonFilterReader.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/json/TestJsonFilterReader.java b/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/json/TestJsonFilterReader.java
new file mode 100644
index 0000000..e335429
--- /dev/null
+++ b/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/json/TestJsonFilterReader.java
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.gateway.filter.rewrite.impl.json;
+
+import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+
+import java.io.IOException;
+import java.io.Reader;
+
+public class TestJsonFilterReader extends JsonFilterReader {
+
+  public TestJsonFilterReader( Reader reader, UrlRewriteFilterContentDescriptor config ) throws IOException {
+    super( reader, config );
+  }
+
+  protected String filterFieldName( String name ) {
+    return "name<" + name + ">";
+  }
+
+  protected String filterValueString( String name, String value, String rule ) {
+    return "value:" + rule + "<" + value + ">";
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/rewrite.xml
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/rewrite.xml b/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/rewrite.xml
new file mode 100644
index 0000000..a6ca78d
--- /dev/null
+++ b/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/rewrite.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<rules>
+
+    <filter>
+        <role>rewrite</role>
+        <name>url-rewrite</name>
+        <class>org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteServletFilter</class>
+        <param><name>url.rule</name><value>{rule-name}</value></param>
+        <param><name>request.filter</name><value>{filters-name}</value></param>
+        <param><name>response.filter</name><value>{filters-name}</value></param>
+    </filter>
+
+    <!--
+    If no filter/rule specified it should attempt to filter everything like it did before.
+    -->
+
+    <filter name="NAMENODE/request">
+        <content type="http/header">
+            <apply target="Location" rule="{rewrite-rule-name}"/>
+            <apply>...</apply>
+        </content>
+        <content type="http/cookie">
+            <apply target="hadoop.auth" rule="{rewrite-rule-name}"/>
+        </content>
+        <content type="*/json" name="{filter-impl-name}">
+            <select node="/config/property">
+                <choice source="name" pattern="YarnNodeManager ">
+                    <apply target="value[2]" rule="{rewrite-rule-name}"/>
+                    <apply target="value[3]" rule="{rewrite-rule-name}"/>
+                </choice>
+                <choice>...</choice>
+            </select>
+        </content>
+    </filter>
+
+    <!--
+    If there isn't a ContentFilter for the required type it is a failure.
+    The default ContentFilter ie type="*/*" can be present to transparently stream content.
+    The most specific content filter applies.
+
+    The most specific apply choice applies.
+    Missing rule="" uses URL pattern matching.
+    The rule="*" uses URL pattern matching.
+    The rule="-" prevents any rule being applied.
+
+    ContentParser
+    ContentParserFactory
+    ContentParserEvent
+
+    ContentFilter
+    ContentFilterFactory
+    ContentFilterAction
+    ContentFilterApply
+    ContentFilterChoice
+    ContentFilterSelect
+    ContentFilterSelectNode
+
+    ContentPath
+    ContentPathNode
+    ContentPathMatcher
+    ContentPathParser
+    -->
+
+    <rule dir="IN" name="NAMENODE/hdfs/namenode/root/inbound" pattern="*://*:*/**/namenode/api/v1/?{**}">
+        <rewrite template="http://vm:50070/webhdfs/v1/?{**}"/>
+    </rule>
+    <rule dir="IN" name="NAMENODE/hdfs/namenode/file/inbound" pattern="*://*:*/**/namenode/api/v1/{path=**}?{**}">
+        <rewrite template="http://vm:50070/webhdfs/v1/{path=**}?{**}"/>
+    </rule>
+    <rule dir="IN" name="NAMENODE/hdfs/datanode/inbound" pattern="*://*:*/**/datanode/api/v1/{path=**}?**">
+        <decode-query/>
+        <match pattern="*://*:*/**/datanode/api/v1/{path=**}?{host}&amp;{port}&amp;{**}"/>
+        <rewrite template="http://{host}:{port}/{path=**}?{**}"/>
+    </rule>
+    <rule dir="OUT" name="NAMENODE/hdfs/datanode/outbound" pattern="*://*:*/**?**">
+        <match pattern="*://{host}:{port}/{path=**}?{**}"/>
+        <rewrite template="{gateway.url}/datanode/api/v1/{path=**}?{host}&amp;{port}&amp;{**}"/>
+        <encode-query/>
+    </rule>
+    <rule dir="IN" name="TEMPLETON/templeton/templeton/request" pattern="*://*:*/**/templeton/api/v1/{path=**}?{**}">
+        <rewrite template="http://vm:50111/templeton/v1/{path=**}?{**}"/>
+    </rule>
+    <rule dir="IN" name="OOZIE/oozie/root/inbound" pattern="*://*:*/**/oozie/api/{**}?{**}">
+        <rewrite template="http://vm:11000/oozie/{**}?{**}"/>
+    </rule>
+    <rule dir="IN" name="OOZIE/oozie/api/inbound" pattern="*://*:*/**/oozie/api/v1/{**}?{**}">
+        <rewrite template="http://vm:11000/oozie/v1/{**}?{**}"/>
+    </rule>
+
+</rules>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/xml/XmlFilterReaderTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/xml/XmlFilterReaderTest.java b/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/xml/XmlFilterReaderTest.java
index 91ec9fe..ca68004 100644
--- a/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/xml/XmlFilterReaderTest.java
+++ b/gateway-provider-rewrite/src/test/java/org/apache/hadoop/gateway/filter/rewrite/impl/xml/XmlFilterReaderTest.java
@@ -17,31 +17,61 @@
  */
 package org.apache.hadoop.gateway.filter.rewrite.impl.xml;
 
+import net.htmlparser.jericho.Attribute;
+import net.htmlparser.jericho.Segment;
+import net.htmlparser.jericho.StartTag;
+import net.htmlparser.jericho.StreamedSource;
 import org.apache.commons.digester3.Digester;
 import org.apache.commons.digester3.ExtendedBaseRules;
 import org.apache.commons.digester3.binder.DigesterLoader;
 import org.apache.commons.io.IOUtils;
-import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteRuleDescriptor;
-import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteRulesDescriptor;
-import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteStepDescriptor;
-import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriteStepFlow;
-import org.apache.hadoop.gateway.filter.rewrite.api.UrlRewriter;
+import org.apache.hadoop.gateway.filter.rewrite.api.*;
 import org.apache.hadoop.gateway.filter.rewrite.ext.UrlRewriteCheckDescriptorExt;
 import org.apache.hadoop.gateway.filter.rewrite.ext.UrlRewriteControlDescriptor;
 import org.apache.hadoop.gateway.filter.rewrite.ext.UrlRewriteMatchDescriptor;
 import org.apache.hadoop.gateway.filter.rewrite.ext.UrlRewriteMatchDescriptorExt;
 import org.apache.hadoop.gateway.filter.rewrite.spi.UrlRewriteActionDescriptorBase;
+import org.apache.hadoop.test.TestUtils;
 import org.hamcrest.Matchers;
+import org.jdom2.Content;
+import org.jdom2.filter.AttributeFilter;
+import org.jdom2.filter.ContentFilter;
+import org.jdom2.output.Format;
+import org.jdom2.output.XMLOutputter;
+import org.jdom2.xpath.XPathExpression;
+import org.jdom2.xpath.XPathFactory;
 import org.junit.Before;
 import org.junit.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
 import org.xml.sax.SAXException;
 import org.xmlmatchers.namespace.SimpleNamespaceContext;
 
 import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.XMLEvent;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
 import java.io.Reader;
 import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.nio.charset.Charset;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
@@ -52,24 +82,26 @@ import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.fail;
 import static org.xmlmatchers.XmlMatchers.hasXPath;
 import static org.xmlmatchers.transform.XmlConverters.the;
 
 public class XmlFilterReaderTest {
 
   public static class NoopXmlFilterReader extends XmlFilterReader {
-    public NoopXmlFilterReader( Reader reader ) throws IOException {
-      super( reader );
+    public NoopXmlFilterReader( Reader reader, UrlRewriteFilterContentDescriptor config ) throws IOException, ParserConfigurationException, XMLStreamException {
+      super( reader, config );
     }
 
     @Override
-    protected String filterText( QName elementName, String text ) {
+    protected String filterText( QName elementName, String text, String ruleName ) {
       return text;
     }
 
     @Override
-    protected String filterAttribute( QName elementName, QName attributeName, String attributeValue ) {
+    protected String filterAttribute( QName elementName, QName attributeName, String attributeValue, String ruleName ) {
       return attributeValue;
     }
   }
@@ -77,36 +109,78 @@ public class XmlFilterReaderTest {
   public static class MapXmlFilterReader extends XmlFilterReader {
     private Map<String,String> map;
 
-    public MapXmlFilterReader( Reader reader, Map<String,String> map ) throws IOException {
-      super( reader );
+    public MapXmlFilterReader( Reader reader, Map<String,String> map ) throws IOException, ParserConfigurationException, XMLStreamException {
+      super( reader, null );
       this.map = map;
     }
 
     @Override
-    protected String filterAttribute( QName elementName, QName attributeName, String attributeValue ) {
+    protected String filterAttribute( QName elementName, QName attributeName, String attributeValue, String ruleName ) {
       return map.get( attributeValue.trim() );
     }
 
     @Override
-    protected String filterText( QName elementName, String text ) {
+    protected String filterText( QName elementName, String text, String ruleName ) {
       return map.get( text.trim() );
     }
   }
 
   @Test
-  public void testSimple() throws IOException {
+  public void testSimple() throws IOException, ParserConfigurationException, XMLStreamException {
     String inputXml = "<root/>";
     StringReader inputReader = new StringReader( inputXml );
-    XmlFilterReader filterReader = new NoopXmlFilterReader( inputReader );
+    XmlFilterReader filterReader = new NoopXmlFilterReader( inputReader, null );
     String outputHtml = new String( IOUtils.toCharArray( filterReader ) );
     assertThat( the( outputHtml ), hasXPath( "/root" ) );
   }
 
   @Test
-  public void testSimpleNested() throws IOException {
+  public void testSimpleStreaming() throws IOException, ParserConfigurationException, XMLStreamException {
+    UrlRewriteRulesDescriptor rulesConfig = UrlRewriteRulesDescriptorFactory.create();
+    UrlRewriteFilterDescriptor filterConfig = rulesConfig.addFilter( "filter-1" );
+    UrlRewriteFilterContentDescriptor contentConfig = filterConfig.addContent( "text/xml" );
+
+    String inputXml = "<root/>";
+    StringReader inputReader = new StringReader( inputXml );
+    XmlFilterReader filterReader = new NoopXmlFilterReader( inputReader, contentConfig );
+    String outputHtml = new String( IOUtils.toCharArray( filterReader ) );
+    assertThat( the( outputHtml ), hasXPath( "/root" ) );
+  }
+
+//  @Test
+//  public void testSimpleScoped() throws IOException, ParserConfigurationException, XMLStreamException {
+//    UrlRewriteRulesDescriptor rulesConfig = UrlRewriteRulesDescriptorFactory.create();
+//    UrlRewriteFilterDescriptor filterConfig = rulesConfig.addFilter( "filter-1" );
+//    UrlRewriteFilterContentDescriptor contentConfig = filterConfig.addContent( "text/xml" );
+//
+//    String inputXml = "<root/>";
+//    StringReader inputReader = new StringReader( inputXml );
+//    XmlStaxFilterReader filterReader = new NoopXmlFilterReader( inputReader );
+//    String outputHtml = new String( IOUtils.toCharArray( filterReader ) );
+//    assertThat( the( outputHtml ), hasXPath( "/root" ) );
+//  }
+
+  @Test
+  public void testSimpleBuffered() throws IOException, ParserConfigurationException, XMLStreamException {
+    UrlRewriteRulesDescriptor rulesConfig = UrlRewriteRulesDescriptorFactory.create();
+    UrlRewriteFilterDescriptor filterConfig = rulesConfig.addFilter( "filter-1" );
+    UrlRewriteFilterContentDescriptor contentConfig = filterConfig.addContent( "text/xml" );
+    UrlRewriteFilterBufferDescriptor scopeConfig = contentConfig.addBuffer( "/root" );
+
+    String input = "<root/>";
+    //System.out.println( "INPUT=" + input );
+    StringReader inputReader = new StringReader( input );
+    XmlFilterReader filterReader = new NoopXmlFilterReader( inputReader, contentConfig );
+    String output = new String( IOUtils.toCharArray( filterReader ) );
+    //System.out.println( "OUTPUT=" + output );
+    assertThat( the( output ), hasXPath( "/root" ) );
+  }
+
+  @Test
+  public void testSimpleNested() throws IOException, ParserConfigurationException, XMLStreamException {
     String inputXml = "<root><child1><child11/><child12/></child1><child2><child21/><child22/></child2></root>";
     StringReader inputReader = new StringReader( inputXml );
-    XmlFilterReader filterReader = new NoopXmlFilterReader( inputReader );
+    XmlFilterReader filterReader = new NoopXmlFilterReader( inputReader, null );
     String outputHtml = new String( IOUtils.toCharArray( filterReader ) );
     assertThat( the( outputHtml ), hasXPath( "/root" ) );
     assertThat( the( outputHtml ), hasXPath( "/root/child1" ) );
@@ -118,10 +192,10 @@ public class XmlFilterReaderTest {
   }
 
   @Test
-  public void testSimpleWithNamespace() throws IOException {
+  public void testSimpleWithNamespace() throws IOException, ParserConfigurationException, XMLStreamException {
     String inputXml = "<ns:root xmlns:ns='http://hortonworks.com/xml/ns'></ns:root>";
     StringReader inputReader = new StringReader( inputXml );
-    XmlFilterReader filterReader = new NoopXmlFilterReader( inputReader );
+    XmlFilterReader filterReader = new NoopXmlFilterReader( inputReader, null );
     String outputHtml = new String( IOUtils.toCharArray( filterReader ) );
 
     //System.out.println( outputHtml );
@@ -131,27 +205,57 @@ public class XmlFilterReaderTest {
   }
 
   @Test
-  public void testSimpleTextNode() throws IOException {
+  public void testSimpleTextNode() throws IOException, ParserConfigurationException, XMLStreamException {
     String inputXml = "<root>text</root>";
     StringReader inputReader = new StringReader( inputXml );
-    XmlFilterReader filterReader = new NoopXmlFilterReader( inputReader );
+    XmlFilterReader filterReader = new NoopXmlFilterReader( inputReader, null );
+    String outputXml = new String( IOUtils.toCharArray( filterReader ) );
+    //System.out.println( "OUTPUT=" + outputXml );
+    assertThat( the( outputXml ), hasXPath( "/root/text()", equalTo( "text" ) ) );
+  }
+
+  @Test
+  public void testSimpleAttribute() throws IOException, ParserConfigurationException, XMLStreamException {
+    String inputXml = "<root name='value'/>";
+    StringReader inputReader = new StringReader( inputXml );
+    XmlFilterReader filterReader = new NoopXmlFilterReader( inputReader, null );
+    String outputXml = new String( IOUtils.toCharArray( filterReader ) );
+    //System.out.println( outputHtml );
+    assertThat( the( outputXml ), hasXPath( "/root/@name", equalTo( "value" ) ) );
+  }
+
+  @Test
+  public void testSimpleTextNodeBuffered() throws IOException, ParserConfigurationException, XMLStreamException {
+    UrlRewriteRulesDescriptor rulesConfig = UrlRewriteRulesDescriptorFactory.create();
+    UrlRewriteFilterDescriptor filterConfig = rulesConfig.addFilter( "filter-1" );
+    UrlRewriteFilterContentDescriptor contentConfig = filterConfig.addContent( "text/xml" );
+    UrlRewriteFilterBufferDescriptor scopeConfig = contentConfig.addBuffer( "/root" );
+
+    String inputXml = "<root>text</root>";
+    StringReader inputReader = new StringReader( inputXml );
+    XmlFilterReader filterReader = new NoopXmlFilterReader( inputReader, contentConfig );
     String outputHtml = new String( IOUtils.toCharArray( filterReader ) );
     //System.out.println( outputHtml );
     assertThat( the( outputHtml ), hasXPath( "/root/text()", equalTo( "text" ) ) );
   }
 
   @Test
-  public void testSimpleAttribute() throws IOException {
+  public void testSimpleAttributeBuffered() throws IOException, ParserConfigurationException, XMLStreamException {
+    UrlRewriteRulesDescriptor rulesConfig = UrlRewriteRulesDescriptorFactory.create();
+    UrlRewriteFilterDescriptor filterConfig = rulesConfig.addFilter( "filter-1" );
+    UrlRewriteFilterContentDescriptor contentConfig = filterConfig.addContent( "text/xml" );
+    UrlRewriteFilterBufferDescriptor scopeConfig = contentConfig.addBuffer( "/root" );
+
     String inputXml = "<root name='value'/>";
     StringReader inputReader = new StringReader( inputXml );
-    XmlFilterReader filterReader = new NoopXmlFilterReader( inputReader );
+    XmlFilterReader filterReader = new NoopXmlFilterReader( inputReader, contentConfig );
     String outputHtml = new String( IOUtils.toCharArray( filterReader ) );
     //System.out.println( outputHtml );
     assertThat( the( outputHtml ), hasXPath( "/root/@name", equalTo( "value" ) ) );
   }
 
   @Test
-  public void testMappedText() throws IOException {
+  public void testMappedText() throws IOException, ParserConfigurationException, XMLStreamException {
     Map<String,String> map = new HashMap<String,String>();
     map.put( "input-text", "output-text" );
     String inputXml = "<root>input-text</root>";
@@ -163,7 +267,7 @@ public class XmlFilterReaderTest {
   }
 
   @Test
-  public void testMappedAttribute() throws IOException {
+  public void testMappedAttribute() throws IOException, ParserConfigurationException, XMLStreamException {
     Map<String,String> map = new HashMap<String,String>();
     map.put( "input-text", "output-text" );
     String inputXml = "<root attribute='input-text'/>";
@@ -175,7 +279,7 @@ public class XmlFilterReaderTest {
   }
 
   @Test
-  public void testCombined() throws IOException {
+  public void testCombined() throws IOException, ParserConfigurationException, XMLStreamException {
     Map<String,String> map = new HashMap<String,String>();
     map.put( "attr1-input", "attr1-output" );
     map.put( "attr2-input", "attr2-output" );
@@ -580,25 +684,257 @@ public class XmlFilterReaderTest {
       assertThat( step.flow(), is( UrlRewriteStepFlow.OR ) );
     }
   }
-  
+
   @Test
-  public void testTagNameLetterCase() throws IOException {
+  public void testTagNameLetterCase() throws Exception {
     String inputXml = "<Root/>";
     StringReader inputReader = new StringReader( inputXml );
-    
-    XmlFilterReader filterReader = new NoopXmlFilterReader( inputReader );
+
+    XmlFilterReader filterReader = new NoopXmlFilterReader( inputReader, null );
     String outputXml = new String( IOUtils.toCharArray( filterReader ) );
     assertThat( the( outputXml ), hasXPath( "/Root" ) );
   }
-  
+
   @Test
-  public void testXmlWithHtmlTagNames() throws IOException {
+  public void testXmlWithHtmlTagNames() throws Exception {
     String inputXml = "<root><br><table name=\"table1\"/><table name=\"table2\"/></br></root>";
     StringReader inputReader = new StringReader( inputXml );
-    
-    XmlFilterReader filterReader = new NoopXmlFilterReader( inputReader );
+
+    XmlFilterReader filterReader = new NoopXmlFilterReader( inputReader, null );
     String outputXml = new String( IOUtils.toCharArray( filterReader ) );
     assertThat( the( outputXml ), hasXPath( "/root/br/table[1]/@name", equalTo( "table1" ) ) );
     assertThat( the( outputXml ), hasXPath( "/root/br/table[2]/@name", equalTo( "table2" ) ) );
   }
+
+  @Test
+  public void testStreamedApplyForElements() throws Exception {
+    InputStream stream = TestUtils.getResourceStream( this.getClass(), "properties-elements.xml" );
+    String input = IOUtils.toString( stream, Charset.forName( "UTF-8" ) );
+
+    //System.out.println( "INPUT=" + input );
+
+    UrlRewriteRulesDescriptor rulesConfig = UrlRewriteRulesDescriptorFactory.create();
+    UrlRewriteFilterDescriptor filterConfig = rulesConfig.addFilter( "filter-1" );
+    UrlRewriteFilterContentDescriptor contentConfig = filterConfig.addContent( "text/xml" );
+    UrlRewriteFilterApplyDescriptor applyConfig = contentConfig.addApply( "/properties/property/value/text()", "test-rule-2" );
+
+    //UrlRewriteRulesDescriptorFactory.store( rulesConfig, "xml", new PrintWriter( System.out ) );
+
+    XmlFilterReader filter = new TestXmlFilterReader( new StringReader( input ), contentConfig );
+    String output = IOUtils.toString( filter );
+
+    //System.out.println( "OUTPUT=" + output );
+
+    assertThat( the( output ), hasXPath( "/properties/property[1]/name/text()", equalTo( "test-name-1" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[1]/value/text()", equalTo( "text:test-rule-2{test-value-1}" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[2]/name/text()", equalTo( "test-name-2" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[2]/value/text()", equalTo( "text:test-rule-2{test-value-2}" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[3]/name/text()", equalTo( "test-name-3" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[3]/value/text()", equalTo( "text:test-rule-2{test-value-3}" ) ) );
+  }
+
+  @Test
+  public void testStreamedApplyForElementsConfigShortcut() throws Exception {
+    InputStream stream = TestUtils.getResourceStream( this.getClass(), "properties-elements.xml" );
+    String input = IOUtils.toString( stream, Charset.forName( "UTF-8" ) );
+
+    //System.out.println( "INPUT=" + input );
+
+    UrlRewriteRulesDescriptor rulesConfig = UrlRewriteRulesDescriptorFactory.create();
+    UrlRewriteFilterDescriptor filterConfig = rulesConfig.addFilter( "filter-1" );
+    UrlRewriteFilterContentDescriptor contentConfig = filterConfig.addContent( "text/xml" );
+    UrlRewriteFilterApplyDescriptor applyConfig = contentConfig.addApply( "/properties/property/value", "test-rule-2" );
+
+    //UrlRewriteRulesDescriptorFactory.store( rulesConfig, "xml", new PrintWriter( System.out ) );
+
+    XmlFilterReader filter = new TestXmlFilterReader( new StringReader( input ), contentConfig );
+    String output = IOUtils.toString( filter );
+
+    //System.out.println( "OUTPUT=" + output );
+
+    assertThat( the( output ), hasXPath( "/properties/property[1]/name/text()", equalTo( "test-name-1" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[1]/value/text()", equalTo( "text:test-rule-2{test-value-1}" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[2]/name/text()", equalTo( "test-name-2" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[2]/value/text()", equalTo( "text:test-rule-2{test-value-2}" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[3]/name/text()", equalTo( "test-name-3" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[3]/value/text()", equalTo( "text:test-rule-2{test-value-3}" ) ) );
+  }
+
+  @Test
+  public void testStreamedApplyForAttributes() throws Exception {
+    InputStream stream = TestUtils.getResourceStream( this.getClass(), "properties-attributes.xml" );
+    String input = IOUtils.toString( stream, Charset.forName( "UTF-8" ) );
+
+    //System.out.println( "INPUT=" + input );
+
+    UrlRewriteRulesDescriptor rulesConfig = UrlRewriteRulesDescriptorFactory.create();
+    UrlRewriteFilterDescriptor filterConfig = rulesConfig.addFilter( "filter-1" );
+    UrlRewriteFilterContentDescriptor contentConfig = filterConfig.addContent( "text/xml" );
+    UrlRewriteFilterApplyDescriptor applyConfig = contentConfig.addApply( "/properties/property/@value", "test-rule-2" );
+
+    //UrlRewriteRulesDescriptorFactory.store( rulesConfig, "xml", new PrintWriter( System.out ) );
+
+    XmlFilterReader filter = new TestXmlFilterReader( new StringReader( input ), contentConfig );
+    String output = IOUtils.toString( filter );
+
+    //System.out.println( "OUTPUT=" + output );
+
+    assertThat( the( output ), hasXPath( "/properties/property[1]/@name", equalTo( "test-name-1" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[1]/@value", equalTo( "attr:test-rule-2{test-value-1}" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[2]/@name", equalTo( "test-name-2" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[2]/@value", equalTo( "attr:test-rule-2{test-value-2}" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[3]/@name", equalTo( "test-name-3" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[3]/@value", equalTo( "attr:test-rule-2{test-value-3}" ) ) );
+  }
+
+  @Test
+  public void testBufferedApplyForAttributes() throws Exception {
+    InputStream stream = TestUtils.getResourceStream( this.getClass(), "properties-attributes.xml" );
+    String input = IOUtils.toString( stream, Charset.forName( "UTF-8" ) );
+
+    //System.out.println( "INPUT=" + input );
+
+    UrlRewriteRulesDescriptor rulesConfig = UrlRewriteRulesDescriptorFactory.create();
+    UrlRewriteFilterDescriptor filterConfig = rulesConfig.addFilter( "filter-1" );
+    UrlRewriteFilterContentDescriptor contentConfig = filterConfig.addContent( "text/xml" );
+    UrlRewriteFilterBufferDescriptor bufferconfig = contentConfig.addBuffer( "/properties/property" );
+    UrlRewriteFilterApplyDescriptor applyConfig = bufferconfig.addApply( "@value", "test-rule-2" );
+
+    //UrlRewriteRulesDescriptorFactory.store( rulesConfig, "xml", new PrintWriter( System.out ) );
+
+    XmlFilterReader filter = new TestXmlFilterReader( new StringReader( input ), contentConfig );
+    String output = IOUtils.toString( filter );
+
+    //System.out.println( "OUTPUT=" + output );
+
+    assertThat( the( output ), hasXPath( "/properties/property[1]/@name", equalTo( "test-name-1" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[1]/@value", equalTo( "attr:test-rule-2{test-value-1}" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[2]/@name", equalTo( "test-name-2" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[2]/@value", equalTo( "attr:test-rule-2{test-value-2}" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[3]/@name", equalTo( "test-name-3" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[3]/@value", equalTo( "attr:test-rule-2{test-value-3}" ) ) );
+  }
+
+  @Test
+  public void testBufferedDetectApplyForElements() throws Exception {
+    InputStream stream = TestUtils.getResourceStream( this.getClass(), "properties-elements.xml" );
+    String input = IOUtils.toString( stream, Charset.forName( "UTF-8" ) );
+
+    //System.out.println( "INPUT=" + input );
+
+    UrlRewriteRulesDescriptor rulesConfig = UrlRewriteRulesDescriptorFactory.create();
+    UrlRewriteFilterDescriptor filterConfig = rulesConfig.addFilter( "filter-1" );
+    UrlRewriteFilterContentDescriptor contentConfig = filterConfig.addContent( "text/xml" );
+    UrlRewriteFilterBufferDescriptor bufferConfig = contentConfig.addBuffer( "/properties/property" );
+    UrlRewriteFilterDetectDescriptor detectConfig = bufferConfig.addDetect( "name", "test-name-2" );
+    UrlRewriteFilterApplyDescriptor applyConfig = detectConfig.addApply( "value", "test-rule-2" );
+
+    //UrlRewriteRulesDescriptorFactory.store( rulesConfig, "xml", new PrintWriter( System.out ) );
+
+    XmlFilterReader filter = new TestXmlFilterReader( new StringReader( input ), contentConfig );
+    String output = IOUtils.toString( filter );
+
+    //System.out.println( "OUTPUT=" + output );
+
+    assertThat( the( output ), hasXPath( "/properties/property[1]/name/text()", equalTo( "test-name-1" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[1]/value/text()", equalTo( "test-value-1" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[2]/name/text()", equalTo( "test-name-2" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[2]/value/text()", equalTo( "text:test-rule-2{test-value-2}" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[3]/name/text()", equalTo( "test-name-3" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[3]/value/text()", equalTo( "test-value-3" ) ) );
+  }
+
+  @Test
+  public void testBufferedDetectApplyForAttributes() throws Exception {
+    InputStream stream = TestUtils.getResourceStream( this.getClass(), "properties-attributes.xml" );
+    String input = IOUtils.toString( stream, Charset.forName( "UTF-8" ) );
+
+    //System.out.println( "INPUT=" + input );
+
+    UrlRewriteRulesDescriptor rulesConfig = UrlRewriteRulesDescriptorFactory.create();
+    UrlRewriteFilterDescriptor filterConfig = rulesConfig.addFilter( "filter-1" );
+    UrlRewriteFilterContentDescriptor contentConfig = filterConfig.addContent( "text/xml" );
+    UrlRewriteFilterBufferDescriptor bufferConfig = contentConfig.addBuffer( "/properties/property" );
+    UrlRewriteFilterDetectDescriptor detectConfig = bufferConfig.addDetect( "@name", "test-name-2" );
+    UrlRewriteFilterApplyDescriptor applyConfig = detectConfig.addApply( "@value", "test-rule-2" );
+
+    //UrlRewriteRulesDescriptorFactory.store( rulesConfig, "xml", new PrintWriter( System.out ) );
+
+    XmlFilterReader filter = new TestXmlFilterReader( new StringReader( input ), contentConfig );
+    String output = IOUtils.toString( filter );
+
+    //System.out.println( "OUTPUT=" + output );
+
+    assertThat( the( output ), hasXPath( "/properties/property[1]/@name", equalTo( "test-name-1" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[1]/@value", equalTo( "test-value-1" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[2]/@name", equalTo( "test-name-2" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[2]/@value", equalTo( "attr:test-rule-2{test-value-2}" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[3]/@name", equalTo( "test-name-3" ) ) );
+    assertThat( the( output ), hasXPath( "/properties/property[3]/@value", equalTo( "test-value-3" ) ) );
+  }
+
+  @Test
+  public void testInvalidConfigShouldThrowException() throws Exception {
+    String input = "<root url='http://mock-host:42/test-input-path-1'><url>http://mock-host:42/test-input-path-2</url></root>";
+
+    //System.out.println( "INPUT=" + input );
+
+    UrlRewriteRulesDescriptor rulesConfig = UrlRewriteRulesDescriptorFactory.create();
+    UrlRewriteFilterDescriptor filterConfig = rulesConfig.addFilter( "filter-1" );
+    UrlRewriteFilterContentDescriptor contentConfig = filterConfig.addContent( "*/xml" );
+    contentConfig.addApply( "$.url", "test-rule" );
+
+    //UrlRewriteRulesDescriptorFactory.store( rulesConfig, "xml", new PrintWriter( System.out ) );
+
+    try {
+      XmlFilterReader filter = new TestXmlFilterReader( new StringReader( input ), contentConfig );
+      IOUtils.toString( filter );
+      fail( "Should have thrown an IllegalArgumentException." );
+    } catch ( IOException e ) {
+      fail( "Should have thrown an IllegalArgumentException." );
+    } catch ( IllegalArgumentException e ) {
+      assertThat( e.getMessage(), containsString( "$.url" ) );
+    }
+  }
+
+  private class TestXmlFilterReader extends XmlFilterReader {
+
+    protected TestXmlFilterReader( Reader reader, UrlRewriteFilterContentDescriptor contentConfig ) throws IOException, ParserConfigurationException, XMLStreamException {
+      super( reader, contentConfig );
+    }
+
+    @Override
+    protected String filterAttribute( QName elementName, QName attributeName, String attributeValue, String ruleName ) {
+      return "attr:" + ruleName + "{" + attributeValue + "}";
+    }
+
+    @Override
+    protected String filterText( QName elementName, String text, String ruleName ) {
+      return "text:" + ruleName + "{" + text + "}";
+    }
+
+  }
+
+  public void dump( Node node, Writer writer ) throws TransformerException {
+    Transformer t = TransformerFactory.newInstance().newTransformer();
+    t.setOutputProperty( OutputKeys.METHOD, "xml" );
+    t.setOutputProperty( OutputKeys.ENCODING, "UTF-8" );
+    t.setOutputProperty( OutputKeys.INDENT, "yes" );
+    t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
+    t.transform( new DOMSource( node ), new StreamResult( writer ) );
+  }
+
+  public void dump( Node node, OutputStream stream ) throws TransformerException {
+    Transformer t = TransformerFactory.newInstance().newTransformer();
+    t.setOutputProperty( OutputKeys.METHOD, "xml" );
+    t.setOutputProperty( OutputKeys.ENCODING, "UTF-8" );
+    t.setOutputProperty( OutputKeys.INDENT, "yes" );
+    t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
+    t.transform( new DOMSource( node ), new StreamResult( stream ) );
+  }
+
+//  public void dump( Node node ) throws TransformerException {
+//    dump( node, System.out );
+//  }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteProcessorTest/rewrite-with-same-rules.xml
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteProcessorTest/rewrite-with-same-rules.xml b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteProcessorTest/rewrite-with-same-rules.xml
index 5187084..e3be214 100644
--- a/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteProcessorTest/rewrite-with-same-rules.xml
+++ b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteProcessorTest/rewrite-with-same-rules.xml
@@ -15,12 +15,25 @@
   limitations under the License.
 -->
 <rules>
-    <rule dir="OUT" name="test1" pattern="*://*:*/**?**">
+
+    <rule name="test-rule-1" dir="OUT" pattern="*://*:*/**?**">
         <match pattern="*://{host}:{port}/{path=**}?{**}" />
-        <rewrite template="http://host1:{port}/{path=**}" />
+        <rewrite template="output-mock-scheme-1://output-mock-host-1:{port}/{path=**}" />
     </rule>
-    <rule dir="OUT" name="test2" pattern="*://*:*/**?**">
+
+    <rule name="test-rule-2" dir="OUT" pattern="*://*:*/**?**">
         <match pattern="*://{host}:{port}/{path=**}?{**}" />
-        <rewrite template="http://host2:{port}/{path=**}" />
+        <rewrite template="output-mock-scheme-2://output-mock-host-2:{port}/{path=**}" />
+    </rule>
+
+    <rule name="test-rule-3" dir="OUT" pattern="*://*:*/no-query">
+        <match pattern="{scheme}://{host}:{port}/{path=**}" />
+        <rewrite template="{scheme}://output-mock-host-3:{port}/{path=**}" />
     </rule>
+
+    <rule name="test-rule-4" dir="OUT" pattern="*://*:*/no-query">
+        <match pattern="{scheme}://{host}:{port}/{path=**}" />
+        <rewrite template="{scheme}://output-mock-host-4:{port}/{path=**}" />
+    </rule>
+
 </rules>

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteProcessorTest/rewrite.xml
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteProcessorTest/rewrite.xml b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteProcessorTest/rewrite.xml
index 90d37ee..5e0d5b5 100644
--- a/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteProcessorTest/rewrite.xml
+++ b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteProcessorTest/rewrite.xml
@@ -15,7 +15,7 @@
   limitations under the License.
 -->
 <rules>
-    <rule name="test" url="{scheme=*}://{host=*}:{port=*}/{path=**}">
+    <rule name="test-rule-1" url="{scheme=*}://{host=*}:{port=*}/{path=**}">
         <rewrite param="{scheme}://{host}:{port}/test-output-path"/>
     </rule>
 </rules>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteRulesDescriptorFactoryTest/filter-complete.xml
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteRulesDescriptorFactoryTest/filter-complete.xml b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteRulesDescriptorFactoryTest/filter-complete.xml
new file mode 100644
index 0000000..54789c5
--- /dev/null
+++ b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteRulesDescriptorFactoryTest/filter-complete.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<rules>
+    <filter name="test-filter-name-1">
+        <content type="test-content-type-1/test-content-subtype-1">
+            <apply path="test-apply-path-1" rule="test-apply-rule-1"/>
+            <scope path="test-scope-path-1">
+                <apply path="test-apply-path-2" rule="test-apply-rule-2"/>
+            </scope>
+            <buffer path="test-buffer-path-1">
+                <apply path="test-apply-path-3" rule="test-apply-rule-3"/>
+                <detect path="test-detect-path-1" value="test-detect-value-1">
+                    <apply path="test-apply-path-4" rule="test-apply-rule-4"/>
+                </detect>
+            </buffer>
+        </content>
+    </filter>
+</rules>

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteRulesDescriptorFactoryTest/filter-sample.xml
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteRulesDescriptorFactoryTest/filter-sample.xml b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteRulesDescriptorFactoryTest/filter-sample.xml
new file mode 100644
index 0000000..043ce1c
--- /dev/null
+++ b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteRulesDescriptorFactoryTest/filter-sample.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<rules>
+    <filter name="NAMENODE/request">
+        <content type="http/header">
+            <apply target="Location" rule="{rewrite-rule-name}"/>
+            <apply>...</apply>
+        </content>
+        <content type="http/cookie">
+            <apply target="hadoop.auth" rule="{rewrite-rule-name}"/>
+        </content>
+        <content type="*/json" name="{filter-impl-name}">
+            <select node="/config/property">
+                <choice source="name" pattern="YarnNodeManager ">
+                    <apply target="value[2]" rule="{rewrite-rule-name}"/>
+                    <apply target="value[3]" rule="{rewrite-rule-name}"/>
+                </choice>
+                <choice>...</choice>
+            </select>
+        </content>
+    </filter>
+</rules>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteRulesDescriptorFactoryTest/filter-simple.xml
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteRulesDescriptorFactoryTest/filter-simple.xml b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteRulesDescriptorFactoryTest/filter-simple.xml
new file mode 100644
index 0000000..f31de77
--- /dev/null
+++ b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteRulesDescriptorFactoryTest/filter-simple.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<rules>
+    <filter name="test-filter-1">
+        <content type="test-content-type-1/test-content-subtype-1">
+            <apply path="test-apply-path-1" rule="test-apply-rule-1"/>
+        </content>
+    </filter>
+</rules>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteServletFilterTest/rewrite.xml
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteServletFilterTest/rewrite.xml b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteServletFilterTest/rewrite.xml
index 90d37ee..89257c4 100644
--- a/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteServletFilterTest/rewrite.xml
+++ b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/api/UrlRewriteServletFilterTest/rewrite.xml
@@ -15,7 +15,45 @@
   limitations under the License.
 -->
 <rules>
-    <rule name="test" url="{scheme=*}://{host=*}:{port=*}/{path=**}">
-        <rewrite param="{scheme}://{host}:{port}/test-output-path"/>
+
+    <rule name="test-rule-1" url="{scheme=*}://{host=*}:{port=*}/{path=**}">
+        <rewrite param="{scheme}://{host}:{port}/test-output-path-1"/>
+    </rule>
+
+    <rule name="test-rule-2" url="{scheme=*}://{host=*}:{port=*}/{path=**}">
+        <rewrite param="{scheme}://{host}:{port}/test-output-path-2"/>
     </rule>
+
+    <filter name="test-filter-1">
+        <content type="application/json">
+            <apply path="$.url" rule="test-rule-1"/>
+        </content>
+        <content type="*/xml">
+            <apply path="/root/@url" rule="test-rule-1"/>
+            <apply path="/root/url" rule="test-rule-1"/>
+        </content>
+    </filter>
+
+    <filter name="test-filter-2">
+        <content type="application/x-http-headers">
+            <apply path="Location" rule="test-rule-2"/>
+        </content>
+        <content type="application/x-www-form-urlencoded">
+            <apply path="url" rule="test-rule-2"/>
+        </content>
+        <content type="application/json">
+            <apply path="$.url" rule="test-rule-2"/>
+        </content>
+        <content type="*/xml">
+            <apply path="/root/@url" rule="test-rule-2"/>
+            <apply path="/root/url" rule="test-rule-2"/>
+        </content>
+    </filter>
+
+    <filter name="test-filter-3">
+        <content type="*/xml">
+            <apply path="$.url" rule="test-rule-2"/>
+        </content>
+    </filter>
+
 </rules>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/array.json
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/array.json b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/array.json
new file mode 100644
index 0000000..d42309d
--- /dev/null
+++ b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/array.json
@@ -0,0 +1,4 @@
+[
+  { "obj1-fld1" : "obj1-val1" },
+  { "obj2-fld1" : "obj2-val1" }
+]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/complex.json
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/complex.json b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/complex.json
new file mode 100644
index 0000000..b9fcf6b
--- /dev/null
+++ b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/complex.json
@@ -0,0 +1,16 @@
+{
+  "test-str": "text",
+  "test-int": 42,
+  "test-flt": 3.1415927,
+  "test-bool": true,
+  "test-null": null,
+  "test-obj-empty": {},
+  "test-ary-empty": [],
+  "test-obj-simple": { "obj-inner-name" : "obj-inner-value" },
+  "test-ary-simple": [ "ary-inner-value" ],
+  "test-obj-nest": { "nested-name": { "obj-inner-name" : "obj-inner-value" } },
+  "test-ary-nest": [["nested-value"]],
+  "test-ary-obj": [ { "obj-inner-name": "obj-inner-value" } ],
+  "test-ary-multi": [ "text", 3.14, { "obj-inner-name": "obj-inner-value" }, [ "arry-inner-value" ] ],
+  "test-obj-multi": { "val":"text", "obj": { "obj-inner-name": "obj-inner-value" }, "ary": [ "arry-inner-value" ] }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/empty-array-value.json
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/empty-array-value.json b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/empty-array-value.json
new file mode 100644
index 0000000..a7f5fb8
--- /dev/null
+++ b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/empty-array-value.json
@@ -0,0 +1,3 @@
+{
+  "empty-array" : []
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/empty-object-value.json
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/empty-object-value.json b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/empty-object-value.json
new file mode 100644
index 0000000..414f014
--- /dev/null
+++ b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/empty-object-value.json
@@ -0,0 +1,3 @@
+{
+  "empty-object" : {}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/properties.json
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/properties.json b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/properties.json
new file mode 100644
index 0000000..841e95d
--- /dev/null
+++ b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/properties.json
@@ -0,0 +1,19 @@
+{ "properties" :
+  [
+    { "property" :
+      { "property-name" : "test-name-1",
+        "property-value" : "test-value-1"
+      }
+    },
+    { "property" :
+      { "property-name" : "test-name-2",
+        "property-value" : "test-value-2"
+      }
+    },
+    { "property" :
+      { "property-name" : "test-name-3",
+        "property-value" : "test-value-3"
+      }
+    }
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/simple-values.json
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/simple-values.json b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/simple-values.json
new file mode 100644
index 0000000..dd38059
--- /dev/null
+++ b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/json/JsonFilterReaderTest/simple-values.json
@@ -0,0 +1,7 @@
+{
+  "test-str": "text",
+  "test-int": 42,
+  "test-flt": 3.1415927,
+  "test-bool": true,
+  "test-null": null
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/xml/XmlFilterReaderTest/properties-attributes.xml
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/xml/XmlFilterReaderTest/properties-attributes.xml b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/xml/XmlFilterReaderTest/properties-attributes.xml
new file mode 100644
index 0000000..ae308d4
--- /dev/null
+++ b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/xml/XmlFilterReaderTest/properties-attributes.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<properties>
+    <property name="test-name-1" value="test-value-1"/>
+    <property name="test-name-2" value="test-value-2"/>
+    <property name="test-name-3" value="test-value-3"/>
+</properties>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/xml/XmlFilterReaderTest/properties-elements.xml
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/xml/XmlFilterReaderTest/properties-elements.xml b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/xml/XmlFilterReaderTest/properties-elements.xml
new file mode 100644
index 0000000..cb27162
--- /dev/null
+++ b/gateway-provider-rewrite/src/test/resources/org/apache/hadoop/gateway/filter/rewrite/impl/xml/XmlFilterReaderTest/properties-elements.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<properties>
+    <property>
+        <name>test-name-1</name>
+        <value>test-value-1</value>
+    </property>
+    <property>
+        <name>test-name-2</name>
+        <value>test-value-2</value>
+    </property>
+    <property>
+        <name>test-name-3</name>
+        <value>test-value-3</value>
+    </property>
+</properties>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayServer.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayServer.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayServer.java
index 85d35de..5c2dd18 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayServer.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayServer.java
@@ -84,7 +84,7 @@ public class GatewayServer {
         GatewayCommandLine.printHelp();
       } else if( cmd.hasOption( GatewayCommandLine.VERSION_LONG ) ) {
         buildProperties = loadBuildProperties();
-        System.out.println( res.gatewayVersionMessage(
+        System.out.println( res.gatewayVersionMessage( // I18N not required.
             buildProperties.getProperty( "build.version", "unknown" ),
             buildProperties.getProperty( "build.hash", "unknown" ) ) );
       } else {

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-server/src/main/java/org/apache/hadoop/gateway/deploy/impl/DispatchDeploymentContributor.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/deploy/impl/DispatchDeploymentContributor.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/deploy/impl/DispatchDeploymentContributor.java
index 25ce411..91951da 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/deploy/impl/DispatchDeploymentContributor.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/deploy/impl/DispatchDeploymentContributor.java
@@ -19,6 +19,7 @@ package org.apache.hadoop.gateway.deploy.impl;
 
 import org.apache.hadoop.gateway.deploy.DeploymentContext;
 import org.apache.hadoop.gateway.deploy.ProviderDeploymentContributorBase;
+import org.apache.hadoop.gateway.descriptor.FilterDescriptor;
 import org.apache.hadoop.gateway.descriptor.FilterParamDescriptor;
 import org.apache.hadoop.gateway.descriptor.ResourceDescriptor;
 import org.apache.hadoop.gateway.dispatch.HttpClientDispatch;
@@ -41,7 +42,10 @@ public class DispatchDeploymentContributor extends ProviderDeploymentContributor
 
   @Override
   public void contributeFilter( DeploymentContext context, Provider provider, Service service, ResourceDescriptor resource, List<FilterParamDescriptor> params ) {
-    resource.addFilter().name( getName() ).role( getRole() ).impl( HttpClientDispatch.class );
+    FilterDescriptor filter = resource.addFilter().name( getName() ).role( getRole() ).impl( HttpClientDispatch.class );
+    if( context.getGatewayConfig().isHadoopKerberosSecured() ) {
+      filter.param().name("kerberos").value("true");
+    }
   }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatch.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatch.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatch.java
index 00b00e2..2d38aea 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatch.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatch.java
@@ -35,6 +35,7 @@ import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.methods.HttpPut;
 import org.apache.http.client.methods.HttpUriRequest;
 import org.apache.http.client.params.AuthPolicy;
+import org.apache.http.entity.BufferedHttpEntity;
 import org.apache.http.entity.ByteArrayEntity;
 import org.apache.http.entity.ContentType;
 import org.apache.http.entity.InputStreamEntity;
@@ -43,6 +44,7 @@ import org.apache.http.impl.client.DefaultHttpClient;
 import org.apache.http.protocol.BasicHttpContext;
 import org.apache.http.protocol.HttpContext;
 
+import javax.activation.MimeType;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
@@ -122,39 +124,57 @@ public class HttpClientDispatch extends AbstractGatewayDispatch {
 
   protected HttpEntity createRequestEntity(HttpServletRequest request)
       throws IOException {
-    InputStream contentStream = request.getInputStream();
-    int contentLength = request.getContentLength();
+
     String contentType = request.getContentType();
-    String contentEncoding = request.getCharacterEncoding();
-    HttpEntity entity = null;
-    if ((contentType != null)
-        && (contentType.startsWith(CT_APP_WWW_FORM_URL_ENCODED) || 
-            contentType.equalsIgnoreCase(CT_APP_XML))) {
-      if (contentLength <= REPLAY_BUFFER_MAX_SIZE) {
-        if (contentEncoding == null) {
-          contentEncoding = Charset.defaultCharset().name();
-        }
-        String body = IOUtils.toString(contentStream, contentEncoding);
-        // ASCII is OK here because the urlEncode about should have already
-        // escaped
-        byte[] bodyBytes = body.getBytes("US-ASCII");
-        ContentType ct = contentType.equalsIgnoreCase(CT_APP_XML) ? ContentType.APPLICATION_XML
-            : ContentType.APPLICATION_FORM_URLENCODED;
-        entity = new ByteArrayEntity(bodyBytes, ct);
-      } else {
-        entity = new InputStreamEntity(contentStream, contentLength);
-      }
+//    String contentEncoding = request.getCharacterEncoding();
+    int contentLength = request.getContentLength();
+    InputStream contentStream = request.getInputStream();
+
+    HttpEntity entity;
+    if( contentType == null ) {
+      entity = new InputStreamEntity( contentStream, contentLength );
     } else {
-      InputStreamEntity streamEntity = new RepeatableInputStreamEntity(
-          contentStream, contentLength);
-      if (contentType != null) {
-        streamEntity.setContentType(contentType);
-      }
-      if (contentEncoding != null) {
-        streamEntity.setContentEncoding(contentEncoding);
-      }
-      entity = streamEntity;
+      entity = new InputStreamEntity(contentStream, contentLength, ContentType.parse( contentType ) );
     }
+    //TODO: Need a better solution than this for replaying bodies when required.
+    // Perhaps we should pessimistically buffer the first REPLAY_BUFFER_MAX_SIZE bytes and then
+    // switch to the remaining stream once that is consumed.  The buffer size would probably need
+    // to match the underlying socket buffer size for this to be meaningful.
+    // This would require writing a special version of HttpEntity/BufferedHttpEntity.
+    // Might also look into mark()/reset() as a solution.
+    if( contentLength <= REPLAY_BUFFER_MAX_SIZE ) {
+      entity = new BufferedHttpEntity( entity );
+    }
+
+//    HttpEntity entity = null;
+//    if ((contentType != null)
+//        && (contentType.startsWith(CT_APP_WWW_FORM_URL_ENCODED) ||
+//            contentType.equalsIgnoreCase(CT_APP_XML))) {
+//      if (contentLength <= REPLAY_BUFFER_MAX_SIZE) {
+//        if (contentEncoding == null) {
+//          contentEncoding = Charset.defaultCharset().name();
+//        }
+//        String body = IOUtils.toString(contentStream, contentEncoding);
+//        // ASCII is OK here because the urlEncode about should have already
+//        // escaped
+//        byte[] bodyBytes = body.getBytes("US-ASCII");
+//        ContentType ct = contentType.equalsIgnoreCase(CT_APP_XML) ? ContentType.APPLICATION_XML
+//            : ContentType.APPLICATION_FORM_URLENCODED;
+//        entity = new ByteArrayEntity(bodyBytes, ct);
+//      } else {
+//        entity = new InputStreamEntity(contentStream, contentLength);
+//      }
+//    } else {
+//      InputStreamEntity streamEntity = new RepeatableInputStreamEntity(
+//          contentStream, contentLength);
+//      if (contentType != null) {
+//        streamEntity.setContentType(contentType);
+//      }
+//      if (contentEncoding != null) {
+//        streamEntity.setContentEncoding(contentEncoding);
+//      }
+//      entity = streamEntity;
+//    }
     return entity;
   }
 
@@ -201,24 +221,24 @@ public class HttpClientDispatch extends AbstractGatewayDispatch {
     executeRequest( method, request, response );
   }
   
-  private static class RepeatableInputStreamEntity extends InputStreamEntity {
-
-    public RepeatableInputStreamEntity(InputStream contentStream,
-        int contentLength) {
-      super(contentStream, contentLength);
-    }
-
-    @Override
-    public boolean isRepeatable() {
-      return true;
-    }
-
-    @Override
-    public InputStream getContent() throws IOException {
-      return super.getContent();
-    }
-
-  }
+//  private static class RepeatableInputStreamEntity extends InputStreamEntity {
+//
+//    public RepeatableInputStreamEntity(InputStream contentStream,
+//        int contentLength) {
+//      super(contentStream, contentLength);
+//    }
+//
+//    @Override
+//    public boolean isRepeatable() {
+//      return true;
+//    }
+//
+//    @Override
+//    public InputStream getContent() throws IOException {
+//      return super.getContent();
+//    }
+//
+//  }
   
   private static class EmptyJaasCredentials implements Credentials {
 

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-server/src/main/java/org/apache/hadoop/gateway/services/registry/impl/DefaultServiceRegistryService.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/registry/impl/DefaultServiceRegistryService.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/registry/impl/DefaultServiceRegistryService.java
index 92b8621..21b7991 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/registry/impl/DefaultServiceRegistryService.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/registry/impl/DefaultServiceRegistryService.java
@@ -111,7 +111,7 @@ public class DefaultServiceRegistryService implements ServiceRegistry, Service {
         rc = true;
       } catch (IOException e) {
         // log appropriately
-        e.printStackTrace();
+        e.printStackTrace(); //TODO: I18N
       }
     }
     
@@ -127,7 +127,7 @@ public class DefaultServiceRegistryService implements ServiceRegistry, Service {
       json = mapper.writeValueAsString((Object)registry);
     
     } catch ( JsonProcessingException e ) {
-      e.printStackTrace();
+      e.printStackTrace(); //TODO: I18N
     }
     return json;
   }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/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 cd353e7..4d6b8dd 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
@@ -152,7 +152,7 @@ public class CMFMasterService {
         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);
+        System.out.println("Loading from persistent master: " + tag); //TODO: I18N
         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/7c91f044/gateway-spi/src/test/java/org/apache/hadoop/gateway/services/security/impl/CMFMasterServiceTest.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/test/java/org/apache/hadoop/gateway/services/security/impl/CMFMasterServiceTest.java b/gateway-spi/src/test/java/org/apache/hadoop/gateway/services/security/impl/CMFMasterServiceTest.java
index 72d1121..b2adf99 100644
--- a/gateway-spi/src/test/java/org/apache/hadoop/gateway/services/security/impl/CMFMasterServiceTest.java
+++ b/gateway-spi/src/test/java/org/apache/hadoop/gateway/services/security/impl/CMFMasterServiceTest.java
@@ -45,7 +45,7 @@ public class CMFMasterServiceTest {
   public void testMasterService() {
     try {
       ms.setupMasterSecret(".", true);
-      System.out.println("MASTER: " + new String(ms.getMasterSecret()));
+      //System.out.println("MASTER: " + new String(ms.getMasterSecret()));
       assertTrue(new String(ms.getMasterSecret()).equals("testmastersecret"));
       File file = new File("ambari-master");
       assertTrue(file.exists());

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-test-utils/pom.xml
----------------------------------------------------------------------
diff --git a/gateway-test-utils/pom.xml b/gateway-test-utils/pom.xml
index d2ccd19..b251168 100644
--- a/gateway-test-utils/pom.xml
+++ b/gateway-test-utils/pom.xml
@@ -59,6 +59,16 @@
             <artifactId>hamcrest-library</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.xmlmatchers</groupId>
+            <artifactId>xml-matchers</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>uk.co.datumedge</groupId>
+            <artifactId>hamcrest-json</artifactId>
+            <scope>provided</scope>
+        </dependency>
 
         <dependency>
             <groupId>org.slf4j</groupId>

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/7c91f044/gateway-test-utils/src/main/java/org/apache/hadoop/test/Console.java
----------------------------------------------------------------------
diff --git a/gateway-test-utils/src/main/java/org/apache/hadoop/test/Console.java b/gateway-test-utils/src/main/java/org/apache/hadoop/test/Console.java
index 7fe03a2..e5bce70 100644
--- a/gateway-test-utils/src/main/java/org/apache/hadoop/test/Console.java
+++ b/gateway-test-utils/src/main/java/org/apache/hadoop/test/Console.java
@@ -31,7 +31,7 @@ public class Console {
     newErrBuf = new ByteArrayOutputStream();
     newErr = new PrintStream( newErrBuf );
 
-    oldOut = System.out;
+    oldOut = System.out; // I18N not required.
     newOutBuf = new ByteArrayOutputStream();
     newOut = new PrintStream( newOutBuf );
 


Mime
View raw message