Index: src/main/java/com/xpn/xwiki/pdf/impl/PdfURLFactory.java
===================================================================
--- src/main/java/com/xpn/xwiki/pdf/impl/PdfURLFactory.java	(revision 3062)
+++ src/main/java/com/xpn/xwiki/pdf/impl/PdfURLFactory.java	(working copy)
@@ -83,6 +83,7 @@
     public String getURL(URL url, XWikiContext context) {
         if (url==null)
             return "";
-        return url.toString();
+        return filterURL(url.toString(), context);
     }
+
 }
Index: src/main/java/com/xpn/xwiki/web/ReWriteFilter.java
===================================================================
--- src/main/java/com/xpn/xwiki/web/ReWriteFilter.java	(revision 0)
+++ src/main/java/com/xpn/xwiki/web/ReWriteFilter.java	(revision 0)
@@ -0,0 +1,68 @@
+package com.xpn.xwiki.web;
+
+import com.xpn.xwiki.XWikiContext;
+import com.xpn.xwiki.XWiki;
+import com.xpn.xwiki.XWikiException;
+import com.xpn.xwiki.util.Util;
+import com.xpn.xwiki.doc.XWikiDocument;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.util.*;
+
+import org.apache.tools.ant.filters.StringInputStream;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: ldubost
+ * Date: 2 mai 2007
+ * Time: 18:57:10
+ * To change this template use File | Settings | File Templates.
+ */
+public class ReWriteFilter implements Filter {
+    private static final Log log = LogFactory.getLog(ReWriteFilter.class);
+
+    protected ServletContext servlet;
+    protected RulesMatcher rulesMatcher;
+    protected XWiki xwiki;
+
+    public void init(FilterConfig filterConfig) {
+        this.servlet = filterConfig.getServletContext();
+        XWikiContext context = new XWikiContext();
+        context.setDatabase("xwiki");
+        context.setEngineContext(new XWikiServletContext(servlet));
+        try {
+            xwiki = XWiki.getXWiki(context);
+        } catch (XWikiException e) {
+            // silent failure
+            e.printStackTrace();
+        }
+        if (rulesMatcher==null) {
+             String rules = xwiki.Param("xwiki.rewrite.inbound","");
+            if ((rules!=null)&&(!rules.equals("")))
+                rulesMatcher = new RulesMatcher(rules);
+        }
+    }
+
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {
+        if (rulesMatcher!=null) {
+            XWikiContext context = new XWikiContext();
+            context.setDatabase("xwiki");
+            context.setWiki(xwiki);
+            String origurl = ((HttpServletRequest)servletRequest).getRequestURI();
+            String newurl = rulesMatcher.applyRules(origurl, context);
+            if (!origurl.equals(newurl)) {
+                servletRequest.getRequestDispatcher(newurl).forward(servletRequest, servletResponse);
+                return;
+            }
+        }
+        filterChain.doFilter(servletRequest, servletResponse);
+    }
+
+    public void destroy() {
+        this.rulesMatcher = null;
+    }
+}
Index: src/main/java/com/xpn/xwiki/web/RulesMatcher.java
===================================================================
--- src/main/java/com/xpn/xwiki/web/RulesMatcher.java	(revision 0)
+++ src/main/java/com/xpn/xwiki/web/RulesMatcher.java	(revision 0)
@@ -0,0 +1,159 @@
+package com.xpn.xwiki.web;
+
+import com.xpn.xwiki.doc.XWikiDocument;
+import com.xpn.xwiki.XWikiContext;
+import com.xpn.xwiki.XWikiException;
+import com.xpn.xwiki.util.Util;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.*;
+import java.io.IOException;
+
+import org.apache.tools.ant.filters.StringInputStream;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * RulesMatcher class allowing to manage rules inside a wiki page
+ * and filter text strings based on these rules
+ *
+ * Example rules:
+ *
+ * rule1=^/xwiki/test/([a-zA-Z0-9\\-]+)/(.*)$
+ * rule1-target=/xwiki/bin/view/Space/Test?param1=$1&param2=$2
+ * rule2=..
+ * rule2-target=..
+
+ * Example usage:
+ * RulesMatcher rulesMatcher = new RulesMatcher("XWiki.Rules");
+ * String targettext = rulesMatcher.applyRules("/xwiki/bin/view/Main/Test?id=12", context);
+ * assertEquals("Text should have been transformed", "/xwiki/test/12", targettext);
+ *
+ */
+
+public class RulesMatcher {
+    private static final Log log = LogFactory.getLog(RulesMatcher.class);
+
+    /**
+     * This stores the name of the wiki page holding the rules
+     */
+    protected String rulesPage;
+
+    /**
+     * This stores the version of the rules page which has been loaded
+     * If this version evolves it means we need to reload the rules
+     */
+    protected String rulesPageVersion;
+
+    /**
+     * Ordered Map storing the rules
+     */
+    protected SortedMap rules;
+
+    /**
+     * Rules matcher constructor
+     * @param rulesPage Name of the wiki page holding the rules
+     */
+    public RulesMatcher(String rulesPage) {
+        this.rulesPage = rulesPage;
+    }
+
+    /**
+     * Retrives the rules page
+     * @return
+     */
+    public String getRulesPage() {
+        return rulesPage;
+    }
+
+    /**
+     * Sets a new rules page and forces reload of the rules
+     * @param rulesPage Name of the wiki page holding the rules
+     */
+    public void setRulesPage(String rulesPage) {
+        this.rulesPage = rulesPage;
+        rulesPageVersion = null;
+        rules = null;
+    }
+
+    /**
+     * Applying the rewrite rule
+     * @param rule  Rule to apply
+     * @param ruleTarget Result of rule
+     * @param text Text to apply rule on
+     * @return
+     */
+    private String applyRule(String rule, String ruleTarget, String text) {
+        try {
+            Util myutil = new Util();
+            String targettext = myutil.substitute(rule, ruleTarget, text);
+            if (text.equals(targettext))
+                return null;
+
+            return targettext;
+        } catch (Exception e) {
+            if (log.isErrorEnabled())
+                log.error("Error applying rule " + rule + " with target " + ruleTarget, e);
+            return null;
+        }
+    }
+
+    /**
+     * Loading of the rules defined in the content field
+     * @param content text containing the rules (see rules format in Class comment)
+     */
+    private void initRules(String content) {
+        try {
+            Properties props = new Properties();
+            props.load(new StringInputStream(content));
+            rules = new TreeMap();
+            int i=1;
+            boolean hasNext = true;
+            while (hasNext) {
+                String rulename = "rule" + i;
+                String rule = (String) props.get(rulename);
+                if (rule==null) {
+                    hasNext = false;
+                } else {
+                    String ruletarget = (String) props.get(rulename + "-target");
+                    rules.put(rule, ruletarget);
+                }
+                i++;
+            }
+        } catch (Exception e) {
+            if (log.isErrorEnabled())
+                log.error("Error loading rules from content " + content, e);
+        }
+    }
+
+    /**
+     * Apply the rules on a source content
+     * @param text text on which to apply the rules
+     * @param context  XWiki content allowing to acces the rules from the wiki page if needed
+     * @return
+     */
+    public String applyRules(String text, XWikiContext context) {
+        XWikiDocument filterDoc = null;
+        try {
+            filterDoc = context.getWiki().getDocument(rulesPage, context);
+            if (!filterDoc.getVersion().equals(rulesPageVersion)) {
+                initRules(filterDoc.getContent());
+                rulesPageVersion = filterDoc.getVersion();
+            }
+        } catch (Exception e) {
+            if (log.isErrorEnabled())
+                log.error("Error initialiazing rules for rules page " + rulesPage);
+        }
+
+        Set ruleSet = rules.keySet();
+        Iterator it = ruleSet.iterator();
+        while (it.hasNext()) {
+            String rule = (String) it.next();
+            String targettext = applyRule(rule, (String) rules.get(rule), text);
+            if (targettext!=null) {
+                return targettext;
+            }
+        }
+        return text;
+    }
+}
Index: src/main/java/com/xpn/xwiki/web/XWikiDefaultURLFactory.java
===================================================================
--- src/main/java/com/xpn/xwiki/web/XWikiDefaultURLFactory.java	(revision 3062)
+++ src/main/java/com/xpn/xwiki/web/XWikiDefaultURLFactory.java	(working copy)
@@ -24,10 +24,55 @@
 package com.xpn.xwiki.web;
 
 import com.xpn.xwiki.XWikiContext;
+import com.xpn.xwiki.XWikiException;
+import com.xpn.xwiki.pdf.impl.PdfURLFactory;
+import com.xpn.xwiki.xmlrpc.XWikiXMLRPCURLFactory;
 
 import java.net.URL;
+import java.util.HashMap;
+import java.util.SortedMap;
+import java.util.Map;
+import java.io.IOException;
 
 public abstract class XWikiDefaultURLFactory implements XWikiURLFactory {
+    protected Map rulesPages;
+    protected Map rulesMatchers = new HashMap();
+
+    public void initRules(XWikiContext context) {
+        rulesPages = new HashMap();
+        addRulesPage(XWikiContext.MODE_XMLRPC, "xmlrpc", context);
+        addRulesPage(XWikiContext.MODE_SERVLET, "servlet", context);
+        addRulesPage(XWikiContext.MODE_PORTLET, "portlet", context);
+        addRulesPage(XWikiContext.MODE_PDF, "pdf", context);
+        addRulesPage(XWikiContext.MODE_GWT, "gwt", context);
+        addRulesPage(XWikiContext.MODE_GWT_DEBUG, "gwtdebug", context);
+    }
+
+    private void addRulesPage(int mode, String name, XWikiContext context) {
+        String smode = "" + mode;
+        String rulesPage = context.getWiki().Param("xwiki.rewrite.outbound." + name, "");
+        if ((rulesPage!=null)&&(!rulesPage.equals("")))
+         rulesPages.put(smode, rulesPage);
+    }
+
+    private RulesMatcher getRulesMatcher(int mode, XWikiContext context) {
+        // We need to make sure the list of rules pages has been loaded
+        if (rulesPages==null)
+         initRules(context);
+
+        String smode = "" + mode;
+        RulesMatcher matcher = (RulesMatcher) rulesMatchers.get(smode);
+        if (matcher==null) {
+            String page = (String) rulesPages.get(smode);
+            // We need to load the rules
+            if (page!=null) {
+                matcher = new RulesMatcher(page);
+                rulesMatchers.put(smode, matcher);
+            }
+        }
+        return matcher;
+    }
+    
     public URL createURL(String web, String name, XWikiContext context) {
         return createURL(web, name, "view", null, null, context);
     }
@@ -66,6 +111,14 @@
     }
 
     public String getURL(URL url, XWikiContext context) {
-        return url.toString();
+        return filterURL(url.toString(), context);
     }
+
+    public String filterURL(String url, XWikiContext context) {
+        RulesMatcher matcher = getRulesMatcher(context.getMode(), context);
+        if (matcher!=null) {
+            return matcher.applyRules(url, context);
+        }
+        return url;
+    }
 }
Index: src/main/java/com/xpn/xwiki/web/XWikiServletURLFactory.java
===================================================================
--- src/main/java/com/xpn/xwiki/web/XWikiServletURLFactory.java	(revision 3062)
+++ src/main/java/com/xpn/xwiki/web/XWikiServletURLFactory.java	(working copy)
@@ -343,7 +343,7 @@
 
             String surl = url.toString();
             if (!surl.startsWith(serverURL.toString()))
-                return surl;
+                return filterURL(surl, context);
             else {
                 StringBuffer sbuf = new StringBuffer(url.getPath());
                 String querystring = url.getQuery();
@@ -358,7 +358,7 @@
                     sbuf.append("#");
                     sbuf.append(anchor);
                 }
-                return sbuf.toString();
+                return filterURL(sbuf.toString(), context);
             }
         } catch (Exception e) {
             e.printStackTrace();
Index: src/main/java/com/xpn/xwiki/xmlrpc/XWikiXMLRPCURLFactory.java
===================================================================
--- src/main/java/com/xpn/xwiki/xmlrpc/XWikiXMLRPCURLFactory.java	(revision 3062)
+++ src/main/java/com/xpn/xwiki/xmlrpc/XWikiXMLRPCURLFactory.java	(working copy)
@@ -30,12 +30,8 @@
 
 public class XWikiXMLRPCURLFactory extends XWikiServletURLFactory
 {
-    public XWikiXMLRPCURLFactory()
-    {
-    }
-
     public String getURL(URL url, XWikiContext context)
     {
-        return url.toString();
+        return filterURL(url.toString(), context);
     }
 }
Index: src/main/java/com/xpn/xwiki/XWiki.java
===================================================================
--- src/main/java/com/xpn/xwiki/XWiki.java	(revision 3062)
+++ src/main/java/com/xpn/xwiki/XWiki.java	(working copy)
@@ -3740,7 +3740,7 @@
     private String fixDecodedURI(XWikiRequest request, String uri)
     {
         String decodedURI = uri;
-        if (!request.getCharacterEncoding().equals("ISO-8859-1")) {
+        if ((request.getCharacterEncoding()!=null)&&!request.getCharacterEncoding().equals("ISO-8859-1")) {
             try {
                 byte[] urib = uri.getBytes("ISO-8859-1");
                 decodedURI = new String(urib, getConfig().getProperty("xwiki.encoding", "UTF-8"));
Index: src/test/java/com/xpn/xwiki/web/ReWriteInboundTest.java
===================================================================
--- src/test/java/com/xpn/xwiki/web/ReWriteInboundTest.java	(revision 0)
+++ src/test/java/com/xpn/xwiki/web/ReWriteInboundTest.java	(revision 0)
@@ -0,0 +1,113 @@
+package com.xpn.xwiki.web;
+
+import org.jmock.cglib.MockObjectTestCase;
+import org.jmock.Mock;
+import com.xpn.xwiki.XWikiContext;
+import com.xpn.xwiki.XWikiConfig;
+import com.xpn.xwiki.XWiki;
+import com.xpn.xwiki.doc.XWikiDocument;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.*;
+import java.util.Date;
+import java.io.IOException;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: ldubost
+ * Date: 2 mai 2007
+ * Time: 22:39:48
+ * To change this template use File | Settings | File Templates.
+ */
+public class ReWriteInboundTest extends MockObjectTestCase {
+
+    private XWikiContext context;
+    private Mock mockXWiki;
+    private Mock mockServletRequest;
+    private Mock mockServletResponse;
+    private Mock mockFilterConfig;
+    private Mock mockFilterChain;
+    private Mock mockEngineContext;
+    private Mock mockServletContext;
+    private Mock mockRequestDispatcher;
+    private ReWriteFilter filter;
+
+     protected void setUp()
+    {
+        this.mockEngineContext = mock(XWikiEngineContext.class);
+        this.context = createXWikiContext();
+        this.filter = new ReWriteFilter();
+        this.mockServletRequest = mock(HttpServletRequest.class);
+        this.mockServletResponse = mock(HttpServletResponse.class);
+        this.mockFilterConfig = mock(FilterConfig.class);
+        this.mockFilterChain = mock(FilterChain.class);
+        this.mockServletContext = mock(ServletContext.class);
+        this.mockRequestDispatcher = mock(RequestDispatcher.class);
+    }
+
+    public void prepareFilterTest(String rules) {
+        this.mockXWiki.stubs().method("getXWikiPreference").will(returnValue(null));
+//        this.mockXWiki.stubs().method("Param").will(returnValue(null));
+        this.mockXWiki.stubs().method("Param").with(eq("xwiki.rewrite.inbound"),eq("")).will(returnValue("XWiki.ReWriteRulesInbound"));
+        this.mockXWiki.stubs().method("getDocument").with(eq("XWiki.ReWriteRulesInbound"), ANYTHING)
+            .will(returnValue(createDocument(111111L, "XWiki.ReWriteRulesInbound", rules, false)));
+        this.mockXWiki.stubs().method("setDatabase");
+        this.mockXWiki.stubs().method("isVirtual").will(returnValue(false));
+        this.mockFilterConfig.stubs().method("getInitParameter").will(returnValue(null));
+        this.mockFilterConfig.stubs().method("getServletContext").will(returnValue(mockServletContext.proxy()));
+        this.mockServletContext.stubs().method("getAttribute").will(returnValue(mockXWiki.proxy()));
+    }
+
+    public void testFilterMatch() throws ServletException, IOException {
+        String rules = "rule1=^/xwiki/test/([a-zA-Z0-9\\-]+)/(.*)$\n" +
+                       "rule1-target=/xwiki/bin/view/Space/Test?param1=$1&param2=$2";
+        prepareFilterTest(rules);
+        this.mockServletRequest.stubs().method("getRequestURI").will(returnValue("/xwiki/test/ABC/DEF"));
+        this.mockServletRequest.expects(once()).method("getRequestDispatcher").with(eq("/xwiki/bin/view/Space/Test?param1=ABC&param2=DEF")).will(returnValue(mockRequestDispatcher.proxy()));
+        this.mockRequestDispatcher.expects(once()).method("forward");
+        this.filter.init((FilterConfig) mockFilterConfig.proxy());
+        this.filter.doFilter((HttpServletRequest)mockServletRequest.proxy(),(HttpServletResponse)mockServletResponse.proxy(),(FilterChain)mockFilterChain.proxy());
+    }
+
+    public void testFitlerNoMatch() throws ServletException, IOException {
+        String rules = "rule1=^/xwiki/test2/([a-zA-Z0-9\\-]+)/(.*)$\n" +
+                       "rule1-target=/xwiki/bin/view/Space/Test?param1=$1&param2=$2";
+        prepareFilterTest(rules);
+        this.mockServletRequest.stubs().method("getRequestURI").will(returnValue("/xwiki/test/ABC/DEF"));
+        this.mockFilterChain.expects(once()).method("doFilter");
+        this.filter.init((FilterConfig) mockFilterConfig.proxy());
+        this.filter.doFilter((HttpServletRequest)mockServletRequest.proxy(),(HttpServletResponse)mockServletResponse.proxy(),(FilterChain)mockFilterChain.proxy());
+    }
+
+    private XWikiDocument createDocument(long id, String name, String content, boolean isNew)
+    {
+        return (XWikiDocument) createMockDocument(id, name, content, isNew).proxy();
+    }
+
+    private Mock createMockDocument(long id, String name, String content, boolean isNew)
+    {
+        Mock mockDocument = mock(XWikiDocument.class);
+        XWikiDocument document = (XWikiDocument) mockDocument.proxy();
+        mockDocument.stubs().method("getTranslatedDocument").will(returnValue(document));
+        mockDocument.stubs().method("isNew").will(returnValue(isNew));
+        mockDocument.stubs().method("getId").will(returnValue(new Long(id)));
+        mockDocument.stubs().method("getDate").will(returnValue(new Date()));
+        mockDocument.stubs().method("getContent").will(returnValue(content));
+        mockDocument.stubs().method("getFullName").will(returnValue(name));
+        mockDocument.stubs().method("getVersion").will(returnValue("1.1"));
+        return mockDocument;
+    }
+
+    private XWikiContext createXWikiContext()
+    {
+        XWikiContext context = new XWikiContext();
+        XWikiConfig config = new XWikiConfig();
+        this.mockXWiki = mock(XWiki.class,
+            new Class[]{XWikiConfig.class, XWikiContext.class}, new Object[]{config, context});
+        context.setWiki((XWiki) this.mockXWiki.proxy());
+        context.setEngineContext((XWikiEngineContext) this.mockEngineContext.proxy());
+        return context;
+    }
+
+}
Index: src/test/java/com/xpn/xwiki/web/ReWriteOutboundTest.java
===================================================================
--- src/test/java/com/xpn/xwiki/web/ReWriteOutboundTest.java	(revision 0)
+++ src/test/java/com/xpn/xwiki/web/ReWriteOutboundTest.java	(revision 0)
@@ -0,0 +1,115 @@
+package com.xpn.xwiki.web;
+
+import org.jmock.cglib.MockObjectTestCase;
+import org.jmock.Mock;
+import com.xpn.xwiki.XWikiContext;
+import com.xpn.xwiki.XWikiConfig;
+import com.xpn.xwiki.XWiki;
+import com.xpn.xwiki.doc.XWikiDocument;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.*;
+import java.io.IOException;
+import java.util.Date;
+import java.net.URL;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: ldubost
+ * Date: 2 mai 2007
+ * Time: 22:39:48
+ * To change this template use File | Settings | File Templates.
+ */
+public class ReWriteOutboundTest extends MockObjectTestCase {
+
+    private XWikiContext context;
+    private Mock mockXWiki;
+    // private Mock mockServletRequest;
+    // private Mock mockServletResponse;
+    private Mock mockFilterConfig;
+    // private Mock mockFilterChain;
+    // private Mock mockEngineContext;
+    // private Mock mockServletContext;
+    // private Mock mockRequestDispatcher;
+
+     protected void setUp()
+    {
+        // this.mockEngineContext = mock(XWikiEngineContext.class);
+        this.context = createXWikiContext();
+        // this.mockServletRequest = mock(HttpServletRequest.class);
+        // this.mockServletResponse = mock(HttpServletResponse.class);
+        this.mockFilterConfig = mock(FilterConfig.class);
+        // this.mockFilterChain = mock(FilterChain.class);
+        // this.mockServletContext = mock(ServletContext.class);
+        // this.mockRequestDispatcher = mock(RequestDispatcher.class);
+    }
+
+    public void prepareFilterTest(String rules) {
+        this.mockXWiki.stubs().method("getXWikiPreference").will(returnValue(null));
+        this.mockXWiki.stubs().method("Param").will(returnValue(null));
+        this.mockXWiki.stubs().method("Param").with(eq("xwiki.rewrite.outbound.servlet"),eq("")).will(returnValue("XWiki.ReWriteRulesOutbound"));
+        this.mockXWiki.stubs().method("getDocument").with(eq("XWiki.ReWriteRulesOutbound"), ANYTHING)
+            .will(returnValue(createDocument(111111L, "XWiki.ReWriteRulesOutbound", rules, false)));
+        this.mockXWiki.stubs().method("showViewAction").will(returnValue(true));
+        this.mockXWiki.stubs().method("useDefaultWeb").will(returnValue(false));
+        this.mockXWiki.stubs().method("useDefaultAction").will(returnValue(false));
+        this.mockXWiki.stubs().method("getDefaultPage").will(returnValue("WebHome"));
+        this.mockXWiki.stubs().method("getEncoding").will(returnValue(null));
+            // this.mockXWiki.stubs().method("setDatabase");
+        // this.mockXWiki.stubs().method("isVirtual").will(returnValue(false));
+        // this.mockFilterConfig.stubs().method("getInitParameter").will(returnValue(null));
+        // this.mockFilterConfig.stubs().method("getServletContext").will(returnValue(mockServletContext.proxy()));
+        //this.mockServletContext.stubs().method("getAttribute").will(returnValue(mockXWiki.proxy()));
+    }
+
+    public void testURLFactoryGetURL() throws ServletException, IOException {
+        String rules = "rule1=^/xwiki/bin/view/Main/Test\\\\?id=(.+)\n" +
+                "rule1-target=/xwiki/test/$1";
+        prepareFilterTest(rules);
+        XWikiServletURLFactory urlf = new XWikiServletURLFactory(new URL("http://toto.com"), "xwiki/", "bin/");
+        String newurl = urlf.getURL(new URL("http://toto.com/xwiki/bin/view/Main/Test?id=12"), context);
+        assertEquals("URL should have been transformed", "/xwiki/test/12", newurl);
+    }
+
+    public void testURLFactoryCreateAndGetURL() throws ServletException, IOException {
+        String rules = "rule1=^/xwiki/bin/view/Main/Test\\\\?id=(.+)\n" +
+                "rule1-target=/xwiki/test/$1";
+        prepareFilterTest(rules);
+        XWikiServletURLFactory urlf = new XWikiServletURLFactory(new URL("http://toto.com"), "xwiki/", "bin/");
+        URL newurl = urlf.createURL("Main", "Test", "view", "id=12", "", context);
+        String snewurl = urlf.getURL(newurl, context);
+        assertEquals("URL should have been transformed", "/xwiki/test/12", snewurl);
+    }
+
+    private XWikiDocument createDocument(long id, String name, String content, boolean isNew)
+    {
+        return (XWikiDocument) createMockDocument(id, name, content, isNew).proxy();
+    }
+
+    private Mock createMockDocument(long id, String name, String content, boolean isNew)
+    {
+        Mock mockDocument = mock(XWikiDocument.class);
+        XWikiDocument document = (XWikiDocument) mockDocument.proxy();
+        mockDocument.stubs().method("getTranslatedDocument").will(returnValue(document));
+        mockDocument.stubs().method("isNew").will(returnValue(isNew));
+        mockDocument.stubs().method("getId").will(returnValue(new Long(id)));
+        mockDocument.stubs().method("getDate").will(returnValue(new Date()));
+        mockDocument.stubs().method("getContent").will(returnValue(content));
+        mockDocument.stubs().method("getFullName").will(returnValue(name));
+        mockDocument.stubs().method("getVersion").will(returnValue("1.1"));
+        return mockDocument;
+    }
+
+    private XWikiContext createXWikiContext()
+    {
+        XWikiContext context = new XWikiContext();
+        XWikiConfig config = new XWikiConfig();
+        this.mockXWiki = mock(XWiki.class,
+            new Class[]{XWikiConfig.class, XWikiContext.class}, new Object[]{config, context});
+        context.setWiki((XWiki) this.mockXWiki.proxy());
+        context.setMode(XWikiContext.MODE_SERVLET);
+        return context;
+    }
+
+}
Index: src/test/java/com/xpn/xwiki/web/RulesMatcherTest.java
===================================================================
--- src/test/java/com/xpn/xwiki/web/RulesMatcherTest.java	(revision 0)
+++ src/test/java/com/xpn/xwiki/web/RulesMatcherTest.java	(revision 0)
@@ -0,0 +1,89 @@
+package com.xpn.xwiki.web;
+
+import junit.framework.TestCase;
+import org.jmock.cglib.MockObjectTestCase;
+import org.jmock.Mock;
+import com.xpn.xwiki.XWikiContext;
+import com.xpn.xwiki.XWikiConfig;
+import com.xpn.xwiki.XWiki;
+import com.xpn.xwiki.doc.XWikiDocument;
+
+import java.util.Date;
+
+/**
+ * Text of the Rules Matcher
+ */
+public class RulesMatcherTest extends MockObjectTestCase {
+
+    private XWikiContext context;
+    private Mock mockXWiki;
+
+    protected void setUp()
+    {
+        this.context = createXWikiContext();
+        this.mockXWiki.stubs().method("getXWikiPreference").will(returnValue(null));
+        this.mockXWiki.stubs().method("Param").will(returnValue(null));
+    }
+
+    private XWikiContext createXWikiContext()
+    {
+        XWikiContext context = new XWikiContext();
+        XWikiConfig config = new XWikiConfig();
+        this.mockXWiki = mock(XWiki.class,
+                new Class[]{XWikiConfig.class, XWikiContext.class}, new Object[]{config, context});
+        context.setWiki((XWiki) this.mockXWiki.proxy());
+        return context;
+    }
+
+    private XWikiDocument createDocument(long id, String name, String content, boolean isNew)
+    {
+        return (XWikiDocument) createMockDocument(id, name, content, isNew).proxy();
+    }
+
+    private Mock createMockDocument(long id, String name, String content, boolean isNew)
+    {
+        Mock mockDocument = mock(XWikiDocument.class);
+        XWikiDocument document = (XWikiDocument) mockDocument.proxy();
+        mockDocument.stubs().method("getTranslatedDocument").will(returnValue(document));
+        mockDocument.stubs().method("isNew").will(returnValue(isNew));
+        mockDocument.stubs().method("getId").will(returnValue(new Long(id)));
+        mockDocument.stubs().method("getDate").will(returnValue(new Date()));
+        mockDocument.stubs().method("getContent").will(returnValue(content));
+        mockDocument.stubs().method("getFullName").will(returnValue(name));
+        mockDocument.stubs().method("getVersion").will(returnValue("1.1"));
+        return mockDocument;
+    }
+
+    /**
+     * Test matching and transforming a url
+     */
+    public void testRules1() {
+        String rules = "rule1=^/xwiki/test/([a-zA-Z0-9\\-]+)/(.*)$\n" +
+                       "rule1-target=/xwiki/bin/view/Space/Test?param1=$1&param2=$2";
+
+        this.mockXWiki.stubs().method("getDocument").with(eq("XWiki.Rules"), ANYTHING)
+            .will(returnValue(createDocument(111111L, "XWiki.Rules", rules, false)));
+
+        RulesMatcher rulesMatcher = new RulesMatcher("XWiki.Rules");
+        String newurl = rulesMatcher.applyRules("/xwiki/test/ABC/DEF", context);
+        assertEquals("URL should have been transformed", "/xwiki/bin/view/Space/Test?param1=ABC&param2=DEF", newurl);
+    }
+
+    /**
+     * Test matching and transforming a url
+     */
+    public void testRules2() {
+        String rules = "rule1=^/xwiki/bin/view/Main/Test\\\\?id=(.+)\n" +
+                "rule1-target=/xwiki/test/$1";
+
+        this.mockXWiki.stubs().method("getDocument").with(eq("XWiki.Rules"), ANYTHING)
+            .will(returnValue(createDocument(111111L, "XWiki.Rules", rules, false)));
+
+        RulesMatcher rulesMatcher = new RulesMatcher("XWiki.Rules");
+        String newurl = rulesMatcher.applyRules("/xwiki/bin/view/Main/Test?id=12", context);
+        assertEquals("URL should have been transformed", "/xwiki/test/12", newurl);
+    }
+
+
+
+}
