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

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

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/json/JsonUrlRewriteStreamFilter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/json/JsonUrlRewriteStreamFilter.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/json/JsonUrlRewriteStreamFilter.java
new file mode 100644
index 0000000..bebc616
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/json/JsonUrlRewriteStreamFilter.java
@@ -0,0 +1,59 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.filter.rewrite.impl.json;
+
+import org.apache.commons.io.input.ReaderInputStream;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriter;
+import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteStreamFilter;
+import org.apache.knox.gateway.util.urltemplate.Resolver;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+public class JsonUrlRewriteStreamFilter implements UrlRewriteStreamFilter {
+
+  private static String[] TYPES = new String[]{ "application/json", "text/json", "*/json" };
+  private static String[] NAMES = new String[]{ null };
+
+  @Override
+  public String[] getTypes() {
+    return TYPES;
+  }
+
+  @Override
+  public String[] getNames() {
+    return NAMES;
+  }
+
+  @Override
+  public InputStream filter(
+      InputStream stream,
+      String encoding,
+      UrlRewriter rewriter,
+      Resolver resolver,
+      UrlRewriter.Direction direction,
+      UrlRewriteFilterContentDescriptor config )
+          throws IOException {
+    return new ReaderInputStream(
+        new JsonUrlRewriteFilterReader(
+            new InputStreamReader( stream, encoding ), rewriter, resolver, direction, config ), encoding );
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/noop/NoOpUrlRewriteStreamFilter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/noop/NoOpUrlRewriteStreamFilter.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/noop/NoOpUrlRewriteStreamFilter.java
new file mode 100644
index 0000000..3db2bbd
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/noop/NoOpUrlRewriteStreamFilter.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.filter.rewrite.impl.noop;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriter;
+import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteStreamFilter;
+import org.apache.knox.gateway.util.urltemplate.Resolver;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class NoOpUrlRewriteStreamFilter implements UrlRewriteStreamFilter {
+
+  private static String[] TYPES = new String[]{ null };
+  private static String[] NAMES = new String[]{ null };
+
+  @Override
+  public String[] getTypes() {
+    return TYPES;
+  }
+
+  @Override
+  public String[] getNames() {
+    return NAMES;
+  }
+
+  @Override
+  public InputStream filter(
+      InputStream stream,
+      String encoding,
+      UrlRewriter rewriter,
+      Resolver resolver,
+      UrlRewriter.Direction direction,
+      UrlRewriteFilterContentDescriptor config )
+          throws IOException {
+    return stream;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlFilterReader.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlFilterReader.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlFilterReader.java
new file mode 100644
index 0000000..b5c2593
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlFilterReader.java
@@ -0,0 +1,643 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.filter.rewrite.impl.xml;
+
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterApplyDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterBufferDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterDetectDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterGroupDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterPathDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterScopeDescriptor;
+import org.apache.knox.gateway.filter.rewrite.i18n.UrlRewriteMessages;
+import org.apache.knox.gateway.filter.rewrite.i18n.UrlRewriteResources;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.i18n.resources.ResourcesFactory;
+import org.apache.knox.gateway.util.XmlUtils;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+import javax.xml.namespace.QName;
+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.Attribute;
+import javax.xml.stream.events.Characters;
+import javax.xml.stream.events.Comment;
+import javax.xml.stream.events.EndElement;
+import javax.xml.stream.events.Namespace;
+import javax.xml.stream.events.StartDocument;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Iterator;
+import java.util.Stack;
+import java.util.regex.Pattern;
+
+public abstract class XmlFilterReader extends Reader {
+
+  private static final UrlRewriteResources RES = ResourcesFactory.get( UrlRewriteResources.class );
+
+  private static final String DEFAULT_XML_VERSION = "1.0";
+
+  private static final UrlRewriteMessages LOG = MessagesFactory.get( UrlRewriteMessages.class );
+  private static final UrlRewriteFilterPathDescriptor.Compiler<XPathExpression> XPATH_COMPILER = new XmlPathCompiler();
+  private static final UrlRewriteFilterPathDescriptor.Compiler<Pattern> REGEX_COMPILER = new RegexCompiler();
+
+  private Reader reader;
+  private UrlRewriteFilterContentDescriptor config;
+  private int offset;
+  private StringWriter writer;
+  private StringBuffer buffer;
+  private XMLInputFactory factory;
+  private XMLEventReader parser;
+  private Document document;
+  private Stack<Level> stack;
+  private boolean isEmptyElement;
+
+  protected XmlFilterReader( Reader reader, UrlRewriteFilterContentDescriptor config ) throws IOException, XMLStreamException {
+    this.reader = reader;
+    this.config = config;
+    writer = new StringWriter();
+    buffer = writer.getBuffer();
+    offset = 0;
+    document = null;
+    stack = new Stack<Level>();
+    isEmptyElement = false;
+    factory = XMLInputFactory.newFactory();
+    //KNOX-620 factory.setProperty( XMLConstants.ACCESS_EXTERNAL_DTD, "false" );
+    //KNOX-620 factory.setProperty( XMLConstants.ACCESS_EXTERNAL_SCHEMA, "false" );
+    factory.setProperty( "javax.xml.stream.isReplacingEntityReferences", Boolean.FALSE );
+    factory.setProperty("http://java.sun.com/xml/stream/"
+                + "properties/report-cdata-event", Boolean.TRUE);
+    parser = factory.createXMLEventReader( reader );
+  }
+
+  protected abstract String filterAttribute( QName elementName, QName attributeName, String attributeValue, String ruleName );
+
+  protected abstract String filterText( QName elementName, String text, String ruleName );
+
+  @Override
+  public int read( char[] destBuffer, int destOffset, int destCount ) throws IOException {
+    int count = 0;
+    int available = buffer.length() - offset;
+
+    if( available == 0 ) {
+      if( parser.hasNext() ) {
+        try {
+          XMLEvent event = parser.nextEvent();
+          processEvent( event );
+        } catch( IOException e ) {
+          throw e;
+        } catch( RuntimeException e ) {
+          throw e;
+        } catch ( Exception e ) {
+          throw new RuntimeException( e );
+        }
+        available = buffer.length() - offset;
+      } else {
+        count = -1;
+      }
+    }
+
+    if( available > 0 ) {
+      count = Math.min( destCount, available );
+      buffer.getChars( offset, offset + count, destBuffer, destOffset );
+      offset += count;
+      if( offset == buffer.length() ) {
+        offset = 0;
+        buffer.setLength( 0 );
+      }
+    }
+    return count;
+  }
+
+  private void processEvent( XMLEvent event ) throws ParserConfigurationException, XPathExpressionException, IOException, XMLStreamException {
+    int type = event.getEventType();
+    switch( type ) {
+      case XMLEvent.START_DOCUMENT:
+        processStartDocument( (StartDocument)event );
+        break;
+      case XMLEvent.END_DOCUMENT:
+        processEndDocument();
+        break;
+      case XMLEvent.START_ELEMENT:
+        if( parser.peek().getEventType() == XMLEvent.END_ELEMENT )
+          isEmptyElement = true;
+        processStartElement( event.asStartElement());
+        break;
+      case XMLEvent.END_ELEMENT:
+        processEndElement( event.asEndElement() );
+        isEmptyElement = false;
+        break;
+      case XMLEvent.CHARACTERS:
+      case XMLEvent.CDATA:
+      case XMLEvent.SPACE:
+        processCharacters( event.asCharacters() );
+        break;
+      case XMLEvent.COMMENT:
+        processComment( (Comment)event );
+        break;
+      case XMLEvent.DTD:
+      case XMLEvent.NAMESPACE:
+      case XMLEvent.ATTRIBUTE:
+      case XMLEvent.ENTITY_REFERENCE:
+      case XMLEvent.ENTITY_DECLARATION:
+      case XMLEvent.NOTATION_DECLARATION:
+      case XMLEvent.PROCESSING_INSTRUCTION:
+      default:
+        // Fail if we run into any of these for now.
+        throw new IllegalStateException( Integer.toString( type ) );
+    }
+  }
+
+  private void processStartDocument( StartDocument event ) throws ParserConfigurationException {
+    //System.out.println( "SD=" + event );
+    String s;
+
+    document = XmlUtils.createDocument( false );
+    pushLevel( null, event, document, document, config );
+
+    writer.write( "<?xml" );
+
+    s = event.getVersion();
+    if( s == null ) {
+      s = DEFAULT_XML_VERSION;
+    }
+    writer.write( " version=\"");
+    writer.write( s );
+    writer.write( "\"" );
+
+    s = event.getCharacterEncodingScheme();
+    if( s != null ) {
+      writer.write( " encoding=\"");
+      writer.write( s );
+      writer.write( "\"" );
+    }
+
+    writer.write( " standalone=\"");
+    writer.write( event.isStandalone() ? "yes" : "no" );
+    writer.write( "\"" );
+
+    writer.write( "?>" );
+  }
+
+  private void processEndDocument() {
+    stack.clear();
+    document = null;
+  }
+
+  private void processStartElement( StartElement event ) throws XPathExpressionException {
+    //System.out.println( "SE=" + event );
+
+    // Create a new "empty" element and add it to the document.
+    Element element = bufferElement( event );
+    Level parent = stack.peek();
+    parent.node.appendChild( element );
+
+    // If already buffering just continue to do so.
+    // Note: Don't currently support nested buffer or scope descriptors.
+    if( currentlyBuffering() ) {
+      pushLevel( parent, event, element, parent.scopeNode, parent.scopeConfig );
+      bufferAttributes( event, element );
+    // Else not currently buffering
+    } else {
+      // See if there is a matching path descriptor in the current scope.
+      UrlRewriteFilterPathDescriptor descriptor = pickFirstMatchingPath( parent );
+      if( descriptor != null ) {
+        // If this is a buffer descriptor then switch to buffering and buffer the attributes.
+        if( descriptor instanceof UrlRewriteFilterBufferDescriptor ) {
+          pushLevel( parent, event, element, element, (UrlRewriteFilterBufferDescriptor)descriptor );
+          bufferAttributes( event, element );
+        // Otherwise if this is a scope descriptor then change the scope and stream the attributes.
+        } else if( descriptor instanceof UrlRewriteFilterScopeDescriptor ) {
+          pushLevel( parent, event, element, element, (UrlRewriteFilterScopeDescriptor)descriptor );
+          streamElement( event, element );
+        // Else found an unexpected matching path.
+        } else {
+          // This is likely because there is an <apply> targeted at the text of an element.
+          // That "convenience" config will be taken care of in the streamElement() processing.
+          pushLevel( parent, event, element, parent.scopeNode, parent.scopeConfig );
+          streamElement( event, element );
+        }
+      // If there is no matching path descriptor then continue streaming.
+      } else {
+        pushLevel( parent, event, element, parent.scopeNode, parent.scopeConfig );
+        streamElement( event, element );
+      }
+    }
+  }
+
+  private void processEndElement( EndElement event ) throws XPathExpressionException, IOException {
+    //System.out.println( "EE=" + event );
+    boolean buffering = currentlyBuffering();
+    Level child = stack.pop();
+    if( buffering ) {
+      if( child.node == child.scopeNode ) {
+        processBufferedElement( child );
+      }
+    } else {
+      if( ! isEmptyElement ) {
+        QName n = event.getName();
+        writer.write( "</" );
+        String p = n.getPrefix();
+        if( p != null && !p.isEmpty() ) {
+          writer.write( p );
+          writer.write( ":" );
+        }
+        writer.write( n.getLocalPart() );
+        writer.write( ">" );
+      }
+      child.node.getParentNode().removeChild( child.node );
+    }
+  }
+
+  private Element bufferElement( StartElement event ) {
+    QName qname = event.getName();
+    String prefix = qname.getPrefix();
+    String uri = qname.getNamespaceURI();
+    Element element;
+    if( uri == null || uri.isEmpty() ) {
+      element = document.createElement( qname.getLocalPart() );
+    } else {
+      element = document.createElementNS( qname.getNamespaceURI(), qname.getLocalPart() );
+      if( prefix != null && !prefix.isEmpty() ) {
+        element.setPrefix( prefix );
+      }
+    }
+    // Always need to buffer the namespaces regardless of what else happens so that XPath will work on attributes
+    // namespace qualified attributes.
+    bufferNamespaces( event, element );
+    return element;
+  }
+
+  private void bufferNamespaces( StartElement event, Element element ) {
+    Iterator namespaces = event.getNamespaces();
+    while( namespaces.hasNext() ) {
+      Namespace namespace = (Namespace)namespaces.next();
+      if( namespace.isDefaultNamespaceDeclaration() ) {
+        element.setAttribute( "xmlns", namespace.getNamespaceURI() );
+      } else {
+        element.setAttribute( "xmlns:" + namespace.getPrefix(), namespace.getNamespaceURI() );
+      }
+    }
+  }
+
+  private void streamElement( StartElement event, Element element ) throws XPathExpressionException {
+    writer.write( "<" );
+    QName qname = event.getName();
+    String prefix = event.getName().getPrefix();
+    if( prefix != null && !prefix.isEmpty() ) {
+      writer.write( prefix );
+      writer.write( ":" );
+    }
+    writer.write( qname.getLocalPart() );
+    streamNamespaces( event );
+    streamAttributes( event, element );
+    if( isEmptyElement ) {
+      writer.write("/>");
+    } else {
+      writer.write(">");
+    }
+  }
+
+  private void processBufferedElement( Level level, UrlRewriteFilterGroupDescriptor config ) throws XPathExpressionException {
+    for( UrlRewriteFilterPathDescriptor selector : config.getSelectors() ) {
+      if( selector instanceof UrlRewriteFilterApplyDescriptor ) {
+        XPathExpression path = (XPathExpression)selector.compiledPath( XPATH_COMPILER );
+        Object node = path.evaluate( level.scopeNode, XPathConstants.NODE );
+        if( node != null ) {
+          UrlRewriteFilterApplyDescriptor apply = (UrlRewriteFilterApplyDescriptor)selector;
+          if( node instanceof Element ) {
+            Element element = (Element)node;
+            String value = element.getTextContent();
+            value = filterText( extractQName( element ), value, apply.rule() );
+            element.setTextContent( value );
+          } else if( node instanceof Text ) {
+            Text text = (Text)node;
+            String value = text.getWholeText();
+            value = filterText( extractQName( text.getParentNode() ), value, apply.rule() );
+            text.replaceWholeText( value );
+          } else if( node instanceof Attr ) {
+            Attr attr = (Attr)node;
+            String value = attr.getValue();
+            value = filterAttribute( extractQName( attr.getOwnerElement() ), extractQName( attr ), value, apply.rule() );
+            attr.setValue( value );
+          } else {
+            throw new IllegalArgumentException( RES.unexpectedSelectedNodeType( node ) );
+          }
+        }
+      } else if( selector instanceof UrlRewriteFilterDetectDescriptor) {
+        XPathExpression path = (XPathExpression)selector.compiledPath( XPATH_COMPILER );
+        Object node = path.evaluate( level.scopeNode, XPathConstants.NODE );
+        if( node != null ) {
+          UrlRewriteFilterDetectDescriptor detect = (UrlRewriteFilterDetectDescriptor)selector;
+          String value = null;
+          if( node instanceof Element ) {
+            Element element = (Element)node;
+            value = element.getTextContent();
+          } else if( node instanceof Text ) {
+            Text text = (Text)node;
+            value = text.getWholeText();
+          } else if( node instanceof Attr ) {
+            Attr attr = (Attr)node;
+            value = attr.getValue();
+          } else {
+            throw new IllegalArgumentException( RES.unexpectedSelectedNodeType( node ) );
+          }
+          if( detect.compiledValue( REGEX_COMPILER ).matcher( value ).matches() ) {
+            processBufferedElement( level, detect );
+          }
+        }
+      } else {
+        throw new IllegalArgumentException( RES.unexpectedRewritePathSelector( selector ) );
+      }
+    }
+  }
+
+  private void processBufferedElement( Level level ) throws XPathExpressionException, IOException {
+    processBufferedElement( level, level.scopeConfig );
+    writeBufferedElement( level.node, writer );
+  }
+
+  private QName extractQName( Node node ) {
+    QName qname;
+    String localName = node.getLocalName();
+    if( localName == null ) {
+      qname = new QName( node.getNodeName() );
+    } else {
+      if ( node.getPrefix() == null ) { 
+        qname = new QName( node.getNamespaceURI(), localName );
+      } else {
+        qname = new QName( node.getNamespaceURI(), localName, node.getPrefix() );
+      }
+      
+    }
+    return qname;
+  }
+
+  private void bufferAttributes( StartElement event, Element element ) {
+    Iterator attributes = event.getAttributes();
+    while( attributes.hasNext() ) {
+      Attribute attribute = (Attribute)attributes.next();
+      bufferAttribute( element, attribute );
+    }
+  }
+
+  private Attr bufferAttribute( Element element, Attribute attribute ) {
+    QName name = attribute.getName();
+    String prefix = name.getPrefix();
+    String uri = name.getNamespaceURI();
+    Attr node;
+    if( uri == null || uri.isEmpty() ) {
+      node = document.createAttribute( name.getLocalPart() );
+      element.setAttributeNode( node );
+    } else {
+      node = document.createAttributeNS( uri, name.getLocalPart() );
+      if( prefix != null && !prefix.isEmpty() ) {
+        node.setPrefix( prefix );
+      }
+      element.setAttributeNodeNS( node );
+    }
+    node.setTextContent( attribute.getValue() );
+    return node;
+  }
+
+  private void streamNamespaces( StartElement event ) {
+    Iterator i = event.getNamespaces();
+    while( i.hasNext() ) {
+      Namespace ns = (Namespace)i.next();
+      writer.write( " xmlns" );
+      if( !ns.isDefaultNamespaceDeclaration() ) {
+        writer.write( ":" );
+        writer.write( ns.getPrefix() );
+      }
+      writer.write( "=\"" );
+      writer.write( ns.getNamespaceURI() );
+      writer.write( "\"" );
+    }
+  }
+
+  private void streamAttributes( StartElement event, Element element ) throws XPathExpressionException {
+    Iterator i = event.getAttributes();
+    while( i.hasNext() ) {
+      Attribute attribute = (Attribute)i.next();
+      streamAttribute( element, attribute );
+    }
+  }
+
+  private void streamAttribute( Element element, Attribute attribute ) throws XPathExpressionException {
+    Attr node;
+    QName name = attribute.getName();
+    String prefix = name.getPrefix();
+    String uri = name.getNamespaceURI();
+    if( uri == null || uri.isEmpty() ) {
+      node = document.createAttribute( name.getLocalPart() );
+      element.setAttributeNode( node );
+    } else {
+      node = document.createAttributeNS( uri, name.getLocalPart() );
+      if( prefix != null && !prefix.isEmpty() ) {
+        node.setPrefix( prefix );
+      }
+      element.setAttributeNodeNS( node );
+    }
+
+    String value = attribute.getValue();
+    Level level = stack.peek();
+    if( ( level.scopeConfig ) == null || ( level.scopeConfig.getSelectors().isEmpty() ) ) {
+      value = filterAttribute( null, attribute.getName(), value, null );
+      node.setValue( value );
+    } else {
+      UrlRewriteFilterPathDescriptor path = pickFirstMatchingPath( level );
+      if( path instanceof UrlRewriteFilterApplyDescriptor ) {
+        String rule = ((UrlRewriteFilterApplyDescriptor)path).rule();
+        value = filterAttribute( null, attribute.getName(), value, rule );
+        node.setValue( value );
+      }
+    }
+
+    //dump( document );
+
+    if( prefix == null || prefix.isEmpty() ) {
+      writer.write( " " );
+      writer.write( name.getLocalPart() );
+    } else {
+      writer.write( " " );
+      writer.write( prefix );
+      writer.write( ":" );
+      writer.write( name.getLocalPart() );
+    }
+    writer.write( "=\"" );
+    writer.write( value );
+    writer.write( "\"" );
+    element.removeAttributeNode( node );
+  }
+
+  private void processCharacters( Characters event ) throws XPathExpressionException {
+    //System.out.println( "T[" + event.isCData() + "," + event.isWhiteSpace() + "," + event.isIgnorableWhiteSpace() + "]=" + event );
+    Level level = stack.peek();
+    Node node = stack.peek().node;
+    if( event.isCData() ) {
+      node.appendChild( document.createCDATASection( event.getData() ) );
+    } else {
+      node.appendChild( document.createTextNode( event.getData() ) );
+    }
+    if( !currentlyBuffering() ) {
+      String value = event.getData();
+      if( !event.isWhiteSpace() ) {
+        if( level.scopeConfig == null || level.scopeConfig.getSelectors().isEmpty() ) {
+          value = filterText( extractQName( node ), value, null );
+        } else {
+          UrlRewriteFilterPathDescriptor path = pickFirstMatchingPath( level );
+          if( path instanceof UrlRewriteFilterApplyDescriptor ) {
+            String rule = ((UrlRewriteFilterApplyDescriptor)path).rule();
+            value = filterText( extractQName( node ), value, rule );
+          }
+        }
+      }
+      if( event.isCData() ) {
+        writer.write( "<![CDATA[" );
+        writer.write( value );
+        writer.write( "]]>" );
+      } else {
+        writer.write( StringEscapeUtils.escapeXml( value ) );
+      }  
+    }
+  }
+
+  private void processComment( Comment event ) {
+    //System.out.println( "C=" + event );
+    if( currentlyBuffering() ) {
+      stack.peek().node.appendChild( document.createComment( event.getText() ) );
+    } else {
+      writer.write( "<!--" );
+      writer.write( event.getText() );
+      writer.write( "-->" );
+    }
+  }
+
+  @Override
+  public void close() throws IOException {
+    try {
+      parser.close();
+    } catch( XMLStreamException e ) {
+      throw new IOException( e );
+    }
+    reader.close();
+    writer.close();
+    stack.clear();
+  }
+
+  protected UrlRewriteFilterPathDescriptor pickFirstMatchingPath( Level level ) {
+    UrlRewriteFilterPathDescriptor match = null;
+    if( level.scopeConfig != null ) {
+      for( UrlRewriteFilterPathDescriptor selector : level.scopeConfig.getSelectors() ) {
+        try {
+          XPathExpression path = (XPathExpression)selector.compiledPath( XPATH_COMPILER );
+          Object node = path.evaluate( level.scopeNode, XPathConstants.NODE );
+          if( node != null ) {
+            match = selector;
+            break;
+          }
+        } catch( XPathExpressionException e ) {
+          throw new IllegalArgumentException( selector.path(), e );
+        }
+      }
+    }
+    return match;
+  }
+
+  private boolean currentlyBuffering() {
+    return stack.peek().buffered;
+  }
+
+  private Level pushLevel( Level parent, XMLEvent event, Node node, Node scopeNode, UrlRewriteFilterGroupDescriptor scopeConfig ) {
+    Level level = new Level( parent, event, node, scopeNode, scopeConfig );
+    stack.push( level );
+    return level;
+  }
+
+  private static class Level {
+//    private Level parent;
+//    private XMLEvent event;
+    private Node node;
+    private UrlRewriteFilterGroupDescriptor scopeConfig;
+    private Node scopeNode;
+    private boolean buffered;
+
+    private Level( Level parent, XMLEvent event, Node node, Node scopeNode, UrlRewriteFilterGroupDescriptor scopeConfig ) {
+//      this.parent = parent;
+//      this.event = event;
+      this.node = node;
+      this.scopeConfig = scopeConfig;
+      this.scopeNode = scopeNode;
+      this.buffered = ( ( parent != null ) && parent.buffered ) ||
+                      ( ( scopeConfig != null ) && ( scopeConfig instanceof UrlRewriteFilterBufferDescriptor ) );
+    }
+  }
+
+  private static class XmlPathCompiler implements UrlRewriteFilterPathDescriptor.Compiler<XPathExpression> {
+    private static XPath XPATH = XPathFactory.newInstance().newXPath();
+    @Override
+    public XPathExpression compile( String expression, XPathExpression compiled ) {
+      try {
+        return XPATH.compile( expression );
+      } catch( XPathExpressionException e ) {
+        throw new IllegalArgumentException( e );
+      }
+    }
+  }
+
+  private static class RegexCompiler implements UrlRewriteFilterPathDescriptor.Compiler<Pattern> {
+    @Override
+    public Pattern compile( String expression, Pattern compiled ) {
+      if( compiled != null ) {
+        return compiled;
+      } else {
+        return Pattern.compile( expression );
+      }
+    }
+  }
+
+  private static final void writeBufferedElement( Node node, Writer writer ) throws IOException {
+    try {
+      Transformer t = XmlUtils.getTransformer( false, false, 0, true );
+      t.transform( new DOMSource( node ), new StreamResult( writer ) );
+    } catch( TransformerException e ) {
+      throw new IOException( e );
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlRewriteRulesDigester.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlRewriteRulesDigester.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlRewriteRulesDigester.java
new file mode 100644
index 0000000..2c5b3c6
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlRewriteRulesDigester.java
@@ -0,0 +1,239 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.filter.rewrite.impl.xml;
+
+import org.apache.commons.digester3.Digester;
+import org.apache.commons.digester3.Rule;
+import org.apache.commons.digester3.SetPropertiesRule;
+import org.apache.commons.digester3.binder.AbstractRulesModule;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterGroupDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterPathDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFlowDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptorFactory;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteRuleDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteRulesDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteRulesDescriptorFactory;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteStepDescriptorFactory;
+import org.apache.knox.gateway.filter.rewrite.impl.UrlRewriteFilterApplyDescriptorImpl;
+import org.apache.knox.gateway.filter.rewrite.impl.UrlRewriteFilterBufferDescriptorImpl;
+import org.apache.knox.gateway.filter.rewrite.impl.UrlRewriteFilterDetectDescriptorImpl;
+import org.apache.knox.gateway.filter.rewrite.impl.UrlRewriteFilterScopeDescriptorImpl;
+import org.xml.sax.Attributes;
+
+public class XmlRewriteRulesDigester extends AbstractRulesModule implements XmlRewriteRulesTags {
+
+  @Override
+  protected void configure() {
+    forPattern( ROOT ).addRule( new RulesFactory() );
+    forPattern( ROOT ).addRule( new SetPropertiesRule() );
+
+    for( String name : UrlRewriteFunctionDescriptorFactory.getNames() ) {
+      forPattern( ROOT + "/" + FUNCTIONS + "/" + name ).addRule( new FunctionFactory() );
+      forPattern( ROOT + "/" + FUNCTIONS + "/" + name ).addRule( new SetPropertiesRule() );
+    }
+
+    forPattern( ROOT + "/" + RULE ).addRule( new RuleFactory() );
+    forPattern( ROOT + "/" + RULE ).addRule( new SetPropertiesRule() );
+    for( String type : UrlRewriteStepDescriptorFactory.getTypes() ) {
+      forPattern( "*/" + type ).addRule( new StepFactory() );
+      forPattern( "*/" + type ).addRule( new SetPropertiesRule() );
+    }
+
+    forPattern( ROOT + "/" + FILTER ).addRule( new FilterFactory() );
+    forPattern( ROOT + "/" + FILTER ).addRule( new SetPropertiesRule() );
+    forPattern( ROOT + "/" + FILTER + "/" + CONTENT ).addRule( new FilterContentFactory() );
+    forPattern( ROOT + "/" + FILTER + "/" + CONTENT ).addRule( new SetPropertiesRule() );
+
+    forPattern( ROOT + "/" + FILTER + "/" + CONTENT + "/*/" + APPLY ).addRule( new FilterApplyFactory() );
+    forPattern( ROOT + "/" + FILTER + "/" + CONTENT + "/*/" + APPLY ).addRule( new SetPropertiesRule() );
+
+    forPattern( ROOT + "/" + FILTER + "/" + CONTENT + "/" + SCOPE ).addRule( new FilterScopeFactory() );
+    forPattern( ROOT + "/" + FILTER + "/" + CONTENT + "/" + SCOPE ).addRule( new SetPropertiesRule() );
+
+    forPattern( ROOT + "/" + FILTER + "/" + CONTENT + "/" + BUFFER ).addRule( new FilterBufferFactory() );
+    forPattern( ROOT + "/" + FILTER + "/" + CONTENT + "/" + BUFFER ).addRule( new SetPropertiesRule() );
+
+    forPattern( ROOT + "/" + FILTER + "/" + CONTENT + "/" + BUFFER + "/" + DETECT ).addRule( new FilterDetectFactory() );
+    forPattern( ROOT + "/" + FILTER + "/" + CONTENT + "/" + BUFFER + "/" + DETECT ).addRule( new SetPropertiesRule() );
+
+//    forPattern( "*/" + MATCH ).addRule( new MatchFactory() );
+//    forPattern( "*/" + MATCH ).addRule( new SetPropertiesRule() );
+//    forPattern( "*/" + CHECK ).addRule( new CheckFactory() );
+//    forPattern( "*/" + CHECK ).addRule( new SetPropertiesRule() );
+//    forPattern( "*/" + CONTROL ).addRule( new ControlFactory() );
+//    forPattern( "*/" + CONTROL ).addRule( new SetPropertiesRule() );
+//    forPattern( "*/" + ACTION ).addRule( new ActionFactory() );
+//    forPattern( "*/" + ACTION ).addRule( new SetPropertiesRule() );
+  }
+
+  private static class RulesFactory extends FactoryRule {
+    @Override
+    public Object create( String namespace, String name, Attributes attributes ) {
+      return UrlRewriteRulesDescriptorFactory.create();
+    }
+  }
+
+  private static class RuleFactory extends Rule {
+    @Override
+    public void begin( String namespace, String name, Attributes attributes ) throws Exception {
+      Digester digester = getDigester();
+      UrlRewriteRulesDescriptor rules = digester.peek();
+      UrlRewriteRuleDescriptor rule = rules.newRule();
+      getDigester().push( rule );
+    }
+
+    @Override
+    public void end( String namespace, String name ) throws Exception {
+      Digester digester = getDigester();
+      UrlRewriteRuleDescriptor rule = digester.pop();
+      UrlRewriteRulesDescriptor rules = digester.peek();
+      rules.addRule( rule );
+    }
+  }
+
+  private static class StepFactory extends FactoryRule {
+    @Override
+    public Object create( String namespace, String name, Attributes attributes ) {
+      UrlRewriteFlowDescriptor flow = getDigester().peek();
+      return flow.addStep( name );
+    }
+  }
+
+  private static class FunctionFactory extends FactoryRule {
+    @Override
+    public Object create( String namespace, String name, Attributes attributes ) {
+      UrlRewriteRulesDescriptor rules = getDigester().peek();
+      return rules.addFunction( name );
+    }
+  }
+
+  private static class FilterFactory extends FactoryRule {
+    @Override
+    public Object create( String namespace, String name, Attributes attributes ) {
+      UrlRewriteRulesDescriptor parent = getDigester().peek();
+      return parent.addFilter( attributes.getValue( "name" ) );
+    }
+  }
+
+  private static class FilterContentFactory extends FactoryRule {
+    @Override
+    public Object create( String namespace, String name, Attributes attributes ) {
+      UrlRewriteFilterDescriptor parent = getDigester().peek();
+      UrlRewriteFilterContentDescriptor descriptor = parent.addContent( attributes.getValue( "type" ) );
+      if (attributes.getValue( "asType" ) != null) {
+        descriptor = descriptor.asType(attributes.getValue( "asType" ));
+      }
+      return descriptor;
+    }
+  }
+
+  private static class FilterApplyFactory extends FactoryRule {
+    @Override
+    public Object create( String namespace, String name, Attributes attributes ) {
+      UrlRewriteFilterGroupDescriptor parent = getDigester().peek();
+      UrlRewriteFilterPathDescriptor child = new UrlRewriteFilterApplyDescriptorImpl();
+      child.path( attributes.getValue( "path" ) );
+      parent.addSelector( child );
+      return child;
+    }
+  }
+
+  private static class FilterScopeFactory extends FactoryRule {
+    @Override
+    public Object create( String namespace, String name, Attributes attributes ) {
+      UrlRewriteFilterGroupDescriptor parent = getDigester().peek();
+      UrlRewriteFilterPathDescriptor child = new UrlRewriteFilterScopeDescriptorImpl();
+      child.path( attributes.getValue( "path" ) );
+      parent.addSelector( child );
+      return child;
+    }
+  }
+
+  private static class FilterBufferFactory extends FactoryRule {
+    @Override
+    public Object create( String namespace, String name, Attributes attributes ) {
+      UrlRewriteFilterGroupDescriptor parent = getDigester().peek();
+      UrlRewriteFilterPathDescriptor child = new UrlRewriteFilterBufferDescriptorImpl();
+      child.path( attributes.getValue( "path" ) );
+      parent.addSelector( child );
+      return child;
+    }
+  }
+
+  private static class FilterDetectFactory extends FactoryRule {
+    @Override
+    public Object create( String namespace, String name, Attributes attributes ) {
+      UrlRewriteFilterGroupDescriptor parent = getDigester().peek();
+      UrlRewriteFilterPathDescriptor child = new UrlRewriteFilterDetectDescriptorImpl();
+      child.path( attributes.getValue( "path" ) );
+      parent.addSelector( child );
+      return child;
+    }
+  }
+
+//  private static class MatchFactory extends FactoryRule {
+//    @Override
+//    public Object create( String namespace, String name, Attributes attributes ) {
+//      UrlRewriteRuleDescriptor rule = getDigester().peek();
+//      return rule.addMatch();
+//    }
+//  }
+//
+//  private static class CheckFactory extends FactoryRule {
+//    @Override
+//    public Object create( String namespace, String name, Attributes attributes ) {
+//      UrlRewriteRuleDescriptor rule = getDigester().peek();
+//      return rule.addCheck();
+//    }
+//  }
+//
+//  private static class ActionFactory extends FactoryRule {
+//    @Override
+//    public Object create( String namespace, String name, Attributes attributes ) {
+//      UrlRewriteRuleDescriptor rule = getDigester().peek();
+//      return rule.addAction();
+//    }
+//  }
+//
+//  private static class ControlFactory extends FactoryRule {
+//    @Override
+//    public Object create( String namespace, String name, Attributes attributes ) {
+//      UrlRewriteRuleDescriptor rule = getDigester().peek();
+//      return rule.addControl();
+//    }
+//  }
+
+  private static abstract class FactoryRule extends Rule {
+
+    protected abstract Object create( String namespace, String name, Attributes attributes );
+
+    @Override
+    public void begin( String namespace, String name, Attributes attributes ) throws Exception {
+      getDigester().push( create( namespace, name, attributes ) );
+    }
+
+    @Override
+    public void end( String namespace, String name ) throws Exception {
+      getDigester().pop();
+    }
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlRewriteRulesTags.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlRewriteRulesTags.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlRewriteRulesTags.java
new file mode 100644
index 0000000..872521a
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlRewriteRulesTags.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.filter.rewrite.impl.xml;
+
+/**
+ * <rules>
+ *   <filter name="">
+ *     <content type="json"> == <scope path="$"/>
+ *       <apply/>
+ *       <select>
+ *         <choice>
+ *           <apply/>
+ *         </choice>
+ *       </select>
+ *     </content>
+ *   </filter>
+ * </rules>
+ */
+public interface XmlRewriteRulesTags {
+
+  static final String ROOT = "rules";
+
+  static final String FUNCTIONS = "functions";
+
+  static final String RULE = "rule";
+
+//  static final String MATCH = "match";
+//  static final String CHECK = "check";
+//  static final String CONTROL = "control";
+//  static final String ACTION = "action";
+
+  static final String FILTER = "filter";
+  static final String CONTENT = "content";
+  static final String SCOPE = "scope";
+  static final String BUFFER = "buffer";
+  static final String DETECT = "detect";
+  static final String APPLY = "apply";
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteFilterReader.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteFilterReader.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteFilterReader.java
new file mode 100644
index 0000000..68d13db
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteFilterReader.java
@@ -0,0 +1,80 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.filter.rewrite.impl.xml;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriter;
+import org.apache.knox.gateway.filter.rewrite.i18n.UrlRewriteMessages;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.util.urltemplate.Parser;
+import org.apache.knox.gateway.util.urltemplate.Resolver;
+import org.apache.knox.gateway.util.urltemplate.Template;
+
+import javax.xml.namespace.QName;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
+import java.io.IOException;
+import java.io.Reader;
+import java.net.URISyntaxException;
+
+public class XmlUrlRewriteFilterReader extends XmlFilterReader {
+
+  private static final UrlRewriteMessages LOG = MessagesFactory.get( UrlRewriteMessages.class );
+
+  private Resolver resolver;
+  private UrlRewriter rewriter;
+  private UrlRewriter.Direction direction;
+
+  public XmlUrlRewriteFilterReader( Reader reader, UrlRewriter rewriter, Resolver resolver, UrlRewriter.Direction direction, UrlRewriteFilterContentDescriptor config )
+      throws IOException, ParserConfigurationException, XMLStreamException {
+    super( reader, config );
+    this.resolver = resolver;
+    this.rewriter = rewriter;
+    this.direction = direction;
+  }
+
+  //TODO: Need to limit which values are attempted to be filtered by the name.
+  private String filterValueString( String name, String value, String rule ) {
+    try {
+      Template input = Parser.parseLiteral( value );
+      if( input != null ) {
+        Template output = rewriter.rewrite( resolver, input, direction, rule );
+        if( output != null ) {
+          value = output.getPattern();
+        } else {
+          LOG.failedToFilterValue( value, rule );
+        }
+      } else {
+        LOG.failedToParseValueForUrlRewrite( value );
+      }
+    } catch( URISyntaxException e ) {
+      LOG.failedToParseValueForUrlRewrite( value );
+    }
+    return value;
+  }
+
+  @Override
+  protected String filterAttribute( QName elementName, QName attributeName, String attributeValue, String ruleName ) {
+    return filterValueString( attributeName.getLocalPart(), attributeValue, ruleName );
+  }
+
+  @Override
+  protected String filterText( QName elementName, String text, String ruleName ) {
+    return filterValueString( elementName.getLocalPart(), text, ruleName );
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteRulesExporter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteRulesExporter.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteRulesExporter.java
new file mode 100644
index 0000000..00927b6
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteRulesExporter.java
@@ -0,0 +1,200 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.filter.rewrite.impl.xml;
+
+import org.apache.commons.beanutils.BeanUtils;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterBufferDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterGroupDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterPathDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterScopeDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFlowDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteRuleDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteRulesDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteStepDescriptor;
+import org.apache.knox.gateway.filter.rewrite.i18n.UrlRewriteMessages;
+import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteRulesExporter;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterApplyDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterDetectDescriptor;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.util.XmlUtils;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.IOException;
+import java.io.Writer;
+import java.lang.reflect.InvocationTargetException;
+
+public class XmlUrlRewriteRulesExporter implements UrlRewriteRulesExporter, XmlRewriteRulesTags {
+
+  private static final UrlRewriteMessages LOG = MessagesFactory.get( UrlRewriteMessages.class );
+  
+  @Override
+  public String getFormat() {
+    return "xml";
+  }
+
+  @Override
+  public void store( UrlRewriteRulesDescriptor descriptor, Writer writer ) throws IOException {
+    try {
+      Document document = XmlUtils.createDocument();
+
+      Element root = document.createElement( ROOT );
+      document.appendChild( root );
+
+      if( !descriptor.getFunctions().isEmpty() ) {
+        Element functionsElement = document.createElement( FUNCTIONS );
+        root.appendChild( functionsElement );
+        for( UrlRewriteFunctionDescriptor function : descriptor.getFunctions() ) {
+          Element functionElement = createElement( document, function.name(), function );
+          functionsElement.appendChild( functionElement );
+        }
+      }
+
+      if( !descriptor.getRules().isEmpty() ) {
+        for( UrlRewriteRuleDescriptor rule : descriptor.getRules() ) {
+          Element ruleElement = createRule( document, rule );
+          root.appendChild( ruleElement );
+        }
+      }
+
+      if( !descriptor.getFilters().isEmpty() ) {
+        for( UrlRewriteFilterDescriptor filter : descriptor.getFilters() ) {
+          Element filterElement = createFilter( document, filter );
+          root.appendChild( filterElement );
+        }
+      }
+
+      XmlUtils.writeXml( document, writer );
+
+    } catch( ParserConfigurationException e ) {
+      throw new IOException( e );
+    } catch( TransformerException e ) {
+      throw new IOException( e );
+    } catch( InvocationTargetException e ) {
+      LOG.failedToWriteRulesDescriptor( e );
+    } catch( NoSuchMethodException e ) {
+      LOG.failedToWriteRulesDescriptor( e );
+    } catch( IntrospectionException e ) {
+      LOG.failedToWriteRulesDescriptor( e );
+    } catch( IllegalAccessException e ) {
+      LOG.failedToWriteRulesDescriptor( e );
+    }
+  }
+
+  private Element createFilter( Document document, UrlRewriteFilterDescriptor parent )
+      throws IntrospectionException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
+    Element parentElement = createElement( document, FILTER, parent );
+    for( UrlRewriteFilterContentDescriptor child: parent.getContents() ) {
+      Element childElement = createFilterContent( document, child );
+      parentElement.appendChild( childElement );
+    }
+    return parentElement;
+  }
+
+  private Element createFilterContent( Document document, UrlRewriteFilterContentDescriptor parent )
+      throws IntrospectionException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
+    Element parentElement = createElement( document, CONTENT, parent );
+    for( UrlRewriteFilterPathDescriptor child: parent.getSelectors() ) {
+      Element childElement = createFilterSelector( document, child );
+      parentElement.appendChild( childElement );
+    }
+    return parentElement;
+  }
+
+  private Element createFilterSelector( Document document, UrlRewriteFilterPathDescriptor parent )
+      throws IntrospectionException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
+    Element parentElement = createElement( document, toTagName( parent ), parent );
+    if( parent instanceof UrlRewriteFilterGroupDescriptor) {
+      for( UrlRewriteFilterPathDescriptor child: ((UrlRewriteFilterGroupDescriptor)parent).getSelectors() ) {
+        Element childElement = createFilterSelector( document, child );
+        parentElement.appendChild( childElement );
+      }
+    }
+    return parentElement;
+  }
+
+  private Element createRule( Document document, UrlRewriteRuleDescriptor rule )
+      throws IntrospectionException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
+    Element ruleElement = createElement( document, RULE, rule );
+    for( UrlRewriteStepDescriptor step: rule.steps() ) {
+      Element childElement = createStep( document, step );
+      ruleElement.appendChild( childElement );
+    }
+    return ruleElement;
+  }
+
+  private Element createStep( Document document, UrlRewriteStepDescriptor step )
+      throws IntrospectionException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
+    Element parentElement = createElement( document, step.type(), step );
+    if( step instanceof UrlRewriteFlowDescriptor) {
+      UrlRewriteFlowDescriptor flow = (UrlRewriteFlowDescriptor)step;
+      for( Object child: flow.steps() ) {
+        UrlRewriteStepDescriptor childStep = (UrlRewriteStepDescriptor)child;
+        Element childElement = createStep( document, childStep );
+        parentElement.appendChild( childElement );
+      }
+
+    }
+    return parentElement;
+  }
+
+  private Element createElement( Document document, String name, Object bean )
+      throws IntrospectionException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
+    Element element = document.createElement( name );
+    BeanInfo beanInfo = Introspector.getBeanInfo( bean.getClass(), Object.class );
+    for( PropertyDescriptor propInfo: beanInfo.getPropertyDescriptors() ) {
+      String propName = propInfo.getName();
+      if( propInfo.getReadMethod() != null && String.class.isAssignableFrom( propInfo.getPropertyType() ) ) {
+        String propValue = BeanUtils.getProperty( bean, propName );
+        if( propValue != null && !propValue.isEmpty() ) {
+          // Doing it the hard way to avoid having the &'s in the query string escaped at &amp;
+          Attr attr = document.createAttribute( propName );
+          attr.setValue( propValue );
+          element.setAttributeNode( attr );
+          //element.setAttribute( propName, propValue );
+        }
+      }
+    }
+    return element;
+  }
+
+  private static String toTagName( final UrlRewriteFilterPathDescriptor descriptor ) {
+    if( descriptor instanceof UrlRewriteFilterApplyDescriptor) {
+      return APPLY;
+    } else if( descriptor instanceof UrlRewriteFilterDetectDescriptor) {
+      return DETECT;
+    } else if( descriptor instanceof UrlRewriteFilterBufferDescriptor) {
+      return BUFFER;
+    } else if( descriptor instanceof UrlRewriteFilterScopeDescriptor) {
+      return SCOPE;
+    } else {
+      throw new IllegalArgumentException();
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteRulesImporter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteRulesImporter.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteRulesImporter.java
new file mode 100644
index 0000000..ec60826
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteRulesImporter.java
@@ -0,0 +1,52 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.filter.rewrite.impl.xml;
+
+import org.apache.commons.digester3.Digester;
+import org.apache.commons.digester3.ExtendedBaseRules;
+import org.apache.commons.digester3.binder.DigesterLoader;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteRulesDescriptor;
+import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteRulesImporter;
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import static org.apache.commons.digester3.binder.DigesterLoader.newLoader;
+
+public class XmlUrlRewriteRulesImporter implements UrlRewriteRulesImporter {
+
+  private static DigesterLoader loader = newLoader( new XmlRewriteRulesDigester() );
+
+  @Override
+  public String getFormat() {
+    return "xml";
+  }
+
+  @Override
+  public UrlRewriteRulesDescriptor load( Reader reader ) throws IOException {
+    Digester digester = loader.newDigester( new ExtendedBaseRules() );
+    digester.setValidating( false );
+    try {
+      UrlRewriteRulesDescriptor rules = digester.parse( reader );
+      return rules;
+    } catch( SAXException e ) {
+      throw new IOException( e );
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteStreamFilter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteStreamFilter.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteStreamFilter.java
new file mode 100644
index 0000000..d2aa47f
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/xml/XmlUrlRewriteStreamFilter.java
@@ -0,0 +1,67 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.filter.rewrite.impl.xml;
+
+import org.apache.commons.io.input.ReaderInputStream;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriter;
+import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteStreamFilter;
+import org.apache.knox.gateway.util.urltemplate.Resolver;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+public class XmlUrlRewriteStreamFilter implements UrlRewriteStreamFilter {
+
+  private static String[] TYPES = new String[]{ "application/xml", "text/xml", "*/xml" };
+  private static String[] NAMES = new String[]{ null };
+
+  @Override
+  public String[] getTypes() {
+    return TYPES;
+  }
+
+  @Override
+  public String[] getNames() {
+    return NAMES;
+  }
+
+  @Override
+  public InputStream filter(
+      InputStream stream,
+      String encoding,
+      UrlRewriter rewriter,
+      Resolver resolver,
+      UrlRewriter.Direction direction,
+      UrlRewriteFilterContentDescriptor config )
+          throws IOException {
+    try {
+      return new ReaderInputStream(
+          new XmlUrlRewriteFilterReader(
+              new InputStreamReader( stream, encoding ), rewriter, resolver, direction, config ), encoding );
+    } catch( ParserConfigurationException e ) {
+      throw new IOException( e );
+    } catch( XMLStreamException e ) {
+      throw new IOException( e );
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteActionDescriptorBase.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteActionDescriptorBase.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteActionDescriptorBase.java
new file mode 100644
index 0000000..7451415
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteActionDescriptorBase.java
@@ -0,0 +1,83 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.filter.rewrite.spi;
+
+import org.apache.knox.gateway.filter.rewrite.ext.UrlRewriteActionDescriptor;
+
+public abstract class UrlRewriteActionDescriptorBase
+    extends UrlRewriteStepDescriptorBase<UrlRewriteActionDescriptor>
+    implements UrlRewriteActionDescriptor {
+
+  private String operation;
+  private String parameter;
+
+  protected UrlRewriteActionDescriptorBase( String type ) {
+    super( type );
+  }
+
+  @Override
+  public String operation() {
+    return operation;
+  }
+
+  @Override
+  public UrlRewriteActionDescriptor operation( String operation ) {
+    this.operation = operation;
+    return this;
+  }
+
+  public void setOperation( String operation ) {
+    operation( operation );
+  }
+
+  public void setOper( String operation ) {
+    operation( operation );
+  }
+
+  public void setOp( String operation ) {
+    operation( operation );
+  }
+
+  public String getOper() {
+    return operation();
+  }
+
+  @Override
+  public String parameter() {
+    return parameter;
+  }
+
+  @Override
+  public UrlRewriteActionDescriptor parameter( String parameter ) {
+    this.parameter = parameter;
+    return this;
+  }
+
+  public void setParameter( String parameter ) {
+    parameter( parameter );
+  }
+
+  public void setParam( String parameter ) {
+    parameter( parameter );
+  }
+
+  public String getParam() {
+    return parameter();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteContext.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteContext.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteContext.java
new file mode 100644
index 0000000..5aa82c1
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteContext.java
@@ -0,0 +1,45 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.filter.rewrite.spi;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriter;
+import org.apache.knox.gateway.util.urltemplate.Evaluator;
+import org.apache.knox.gateway.util.urltemplate.Params;
+import org.apache.knox.gateway.util.urltemplate.Template;
+
+public interface UrlRewriteContext {
+
+  UrlRewriter.Direction getDirection();
+
+  Template getOriginalUrl();
+
+  Template getCurrentUrl();
+
+  void setCurrentUrl( Template url );
+
+  /**
+   * Adds parameters to the rewrite context and replaces some of them if they already exist
+   * @param parameters the parameters to be added or replaced
+   */
+  void addParameters( Params parameters );
+
+  Params getParameters();
+
+  Evaluator getEvaluator();
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteFlowDescriptorBase.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteFlowDescriptorBase.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteFlowDescriptorBase.java
new file mode 100644
index 0000000..fcfee24
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteFlowDescriptorBase.java
@@ -0,0 +1,115 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.filter.rewrite.spi;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFlowDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteStepDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteStepDescriptorFactory;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteStepFlow;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class UrlRewriteFlowDescriptorBase<T> extends UrlRewriteStepDescriptorBase<T> implements
+    UrlRewriteFlowDescriptor<T> {
+
+  private UrlRewriteStepFlow flow;
+  private List<UrlRewriteStepDescriptor> steps = new ArrayList<UrlRewriteStepDescriptor>();
+
+  public UrlRewriteFlowDescriptorBase( String type ) {
+    super( type );
+  }
+
+  @Override
+  public UrlRewriteStepFlow flow() {
+    return flow;
+  }
+
+  @SuppressWarnings( "unchecked" )
+  @Override
+  public <F extends UrlRewriteFlowDescriptor<?>> F flow( String flow ) {
+    setFlow( flow );
+    return (F)this;
+  }
+
+  @SuppressWarnings( "unchecked" )
+  @Override
+  public <F extends UrlRewriteFlowDescriptor<?>> F flow( UrlRewriteStepFlow flow ) {
+    setFlow( flow );
+    return (F)this;
+  }
+
+  public void setFlow( UrlRewriteStepFlow flow ) {
+    this.flow = flow;
+  }
+
+  public void setFlow( String flow ) {
+    flow = flow.trim().toUpperCase();
+    this.flow = Enum.valueOf( UrlRewriteStepFlow.class, flow );
+  }
+
+  public String getFlow() {
+    String str = null;
+    if( flow != null ) {
+      str = flow.toString();
+    }
+    return str;
+  }
+
+  @Override
+  public List<UrlRewriteStepDescriptor> steps() {
+    return steps;
+  }
+
+//  @Override
+//  public UrlRewriteMatchDescriptor addMatch() {
+//    UrlRewriteMatchDescriptor step = new UrlRewriteMatchDescriptorExt();
+//    steps.add( step );
+//    return step;
+//  }
+//
+//  @Override
+//  public UrlRewriteCheckDescriptor addCheck() {
+//    UrlRewriteCheckDescriptor step = new UrlRewriteCheckDescriptorExt();
+//    steps.add( step );
+//    return step;
+//  }
+//
+//  @Override
+//  public UrlRewriteControlDescriptor addControl() {
+//    UrlRewriteControlDescriptor step = new UrlRewriteControlDescriptorExt();
+//    steps.add( step );
+//    return step;
+//  }
+//
+//  @Override
+//  public UrlRewriteActionDescriptor addAction() {
+//    UrlRewriteActionDescriptor step = new UrlRewriteActionDescriptorBase();
+//    steps.add( step );
+//    return step;
+//  }
+
+  @SuppressWarnings( "unchecked" )
+  @Override
+  public <T extends UrlRewriteStepDescriptor<?>> T addStep( String type ) {
+    T step = (T)UrlRewriteStepDescriptorFactory.create( type );
+    steps.add( step );
+    return (T)step;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteFunctionProcessor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteFunctionProcessor.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteFunctionProcessor.java
new file mode 100644
index 0000000..8028145
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteFunctionProcessor.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.knox.gateway.filter.rewrite.spi;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteEnvironment;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor;
+
+public interface UrlRewriteFunctionProcessor<T extends UrlRewriteFunctionDescriptor> extends UrlRewriteResolver {
+
+  String name();
+
+  void initialize( UrlRewriteEnvironment environment, T descriptor ) throws Exception;
+
+  void destroy() throws Exception;
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteFunctionProcessorBase.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteFunctionProcessorBase.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteFunctionProcessorBase.java
new file mode 100644
index 0000000..7638f37
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteFunctionProcessorBase.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.knox.gateway.filter.rewrite.spi;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteEnvironment;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor;
+
+public abstract class UrlRewriteFunctionProcessorBase<T extends UrlRewriteFunctionDescriptor> implements UrlRewriteFunctionProcessor<T> {
+
+  public void initialize( UrlRewriteEnvironment environment, T descriptor ) throws Exception {
+  }
+
+  public void destroy() throws Exception {
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteResolver.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteResolver.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteResolver.java
new file mode 100644
index 0000000..c190f55
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteResolver.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.knox.gateway.filter.rewrite.spi;
+
+import java.util.List;
+
+public interface UrlRewriteResolver {
+
+  List<String> resolve( UrlRewriteContext context, List<String> parameter ) throws Exception;
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteRulesExporter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteRulesExporter.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteRulesExporter.java
new file mode 100644
index 0000000..d2dd56e
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteRulesExporter.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.knox.gateway.filter.rewrite.spi;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteRulesDescriptor;
+
+import java.io.IOException;
+import java.io.Writer;
+
+public interface UrlRewriteRulesExporter {
+
+  String getFormat();
+
+  void store( UrlRewriteRulesDescriptor rules, Writer writer ) throws IOException;
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteRulesImporter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteRulesImporter.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteRulesImporter.java
new file mode 100644
index 0000000..ae963bb
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteRulesImporter.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.knox.gateway.filter.rewrite.spi;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteRulesDescriptor;
+
+import java.io.IOException;
+import java.io.Reader;
+
+public interface UrlRewriteRulesImporter {
+
+  String getFormat();
+
+  UrlRewriteRulesDescriptor load( Reader reader ) throws IOException;
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteStepDescriptorBase.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteStepDescriptorBase.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteStepDescriptorBase.java
new file mode 100644
index 0000000..b51d036
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteStepDescriptorBase.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.filter.rewrite.spi;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteStepDescriptor;
+
+public abstract class UrlRewriteStepDescriptorBase<T> implements UrlRewriteStepDescriptor<T> {
+
+  private String type;
+
+  public UrlRewriteStepDescriptorBase( String type ) {
+    this.type = type;
+  }
+
+  @Override
+  public String type() {
+    return type;
+  }
+
+  @Override
+  @SuppressWarnings( "unchecked" )
+  public T type( String type ) {
+    this.type = type;
+    return (T)this;
+  }
+
+  public void setType( String type ) {
+    this.type = type;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteStepProcessor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteStepProcessor.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteStepProcessor.java
new file mode 100644
index 0000000..bc44db2
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteStepProcessor.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.filter.rewrite.spi;
+
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteEnvironment;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteStepDescriptor;
+
+public interface UrlRewriteStepProcessor<T extends UrlRewriteStepDescriptor> {
+
+  String getType();
+
+  void initialize( UrlRewriteEnvironment environment, T descriptor ) throws Exception;
+
+  UrlRewriteStepStatus process( UrlRewriteContext context ) throws Exception;
+
+  void destroy() throws Exception;
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteStepStatus.java
----------------------------------------------------------------------
diff --git a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteStepStatus.java b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteStepStatus.java
new file mode 100644
index 0000000..67e8a36
--- /dev/null
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/spi/UrlRewriteStepStatus.java
@@ -0,0 +1,20 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.filter.rewrite.spi;
+
+public enum UrlRewriteStepStatus { SUCCESS, FAILURE, FINISHED }