[gatein-commits] gatein SVN: r4941 - in portal/branches/navcontroller: component/web/controller/src/main/java/org/exoplatform/web and 10 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Thu Nov 4 07:22:11 EDT 2010


Author: julien_viet
Date: 2010-11-04 07:22:09 -0400 (Thu, 04 Nov 2010)
New Revision: 4941

Added:
   portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/metadata/PathParamDescriptor.java
   portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/EncodingMode.java
   portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/PatternParamDef.java
   portal/branches/navcontroller/webui/portal/src/main/java/org/exoplatform/portal/url/PortalURLRenderContext.java
Modified:
   portal/branches/navcontroller/component/web/controller/src/main/java/gatein_router_1_0.xsd
   portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/ControllerContext.java
   portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/QualifiedName.java
   portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/metadata/DescriptorBuilder.java
   portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/metadata/RouteDescriptor.java
   portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/PatternRoute.java
   portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/RenderContext.java
   portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/Route.java
   portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/SimpleRenderContext.java
   portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestBuildRoute.java
   portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestDescriptorBuilder.java
   portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestLegacyPortal.java
   portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestMatch.java
   portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestPortalConfiguration.java
   portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestRender.java
   portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/router.xml
   portal/branches/navcontroller/portlet/exoadmin/src/main/webapp/groovy/admintoolbar/webui/component/UIUserToolBarGroupPortlet.gtmpl
   portal/branches/navcontroller/web/portal/src/main/webapp/WEB-INF/conf/default-router.xml
   portal/branches/navcontroller/web/portal/src/main/webapp/WEB-INF/conf/proto-router-1.xml
   portal/branches/navcontroller/web/portal/src/main/webapp/groovy/webui/core/UISitemapTree.gtmpl
   portal/branches/navcontroller/webui/portal/src/main/java/org/exoplatform/portal/application/PortalRequestContext.java
   portal/branches/navcontroller/webui/portal/src/main/java/org/exoplatform/portal/url/PortalURL.java
   portal/branches/navcontroller/webui/portal/src/main/java/org/exoplatform/portal/webui/workspace/UIPortalApplication.java
Log:
improve encoding of char in request path and url path


Modified: portal/branches/navcontroller/component/web/controller/src/main/java/gatein_router_1_0.xsd
===================================================================
--- portal/branches/navcontroller/component/web/controller/src/main/java/gatein_router_1_0.xsd	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/component/web/controller/src/main/java/gatein_router_1_0.xsd	2010-11-04 11:22:09 UTC (rev 4941)
@@ -39,6 +39,7 @@
   <xs:complexType name="routeType">
     <xs:sequence>
       <xs:element name="param" type="paramType" minOccurs="0" maxOccurs="unbounded"/>
+      <xs:element name="path-param" type="pathParamType" minOccurs="0" maxOccurs="unbounded"/>
       <xs:element name="request-param" type="requestParamType" minOccurs="0" maxOccurs="unbounded"/>
       <xs:element name="route" type="routeType" minOccurs="0" maxOccurs="unbounded"/>
     </xs:sequence>
@@ -50,6 +51,19 @@
     <xs:attribute name="value" type="xs:string" use="required"/>
   </xs:complexType>
 
+  <xs:complexType name="pathParamType">
+    <xs:attribute name="name" type="xs:string" use="required"/>
+    <xs:attribute name="pattern" type="xs:string" use="optional"/>
+    <xs:attribute name="encoding" use="optional">
+      <xs:simpleType>
+        <xs:restriction base="xs:string">
+          <xs:enumeration value="default-form"/>
+          <xs:enumeration value="preserve-path"/>
+        </xs:restriction>
+      </xs:simpleType>
+    </xs:attribute>
+  </xs:complexType>
+
   <xs:complexType name="requestParamType">
     <xs:attribute name="name" type="xs:string" use="required"/>
     <xs:attribute name="matchName" type="xs:string" use="required"/>

Modified: portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/ControllerContext.java
===================================================================
--- portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/ControllerContext.java	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/ControllerContext.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -49,6 +49,9 @@
    /** . */
    private SimpleRenderContext renderContext;
 
+   /** . */
+   private final String contextName;
+
    public ControllerContext(
       WebAppController controller,
       HttpServletRequest request,
@@ -60,6 +63,7 @@
       this.response = response;
       this.parameters = parameters;
       this.renderContext = null;
+      this.contextName = request.getContextPath().substring(1);
    }
 
    public WebAppController getController()
@@ -84,9 +88,12 @@
 
    public void renderURL(Map<QualifiedName, String> parameters, RenderContext renderContext)
    {
-      renderContext.appendPath(request.getContextPath());
+      renderContext.appendPath('/', false);
 
       //
+      renderContext.appendPath(contextName, true);
+
+      //
       controller.router.render(parameters, renderContext);
    }
 
@@ -102,9 +109,12 @@
       }
 
       //
-      renderContext.appendPath(request.getContextPath());
+      renderContext.appendPath('/', false);
 
       //
+      renderContext.appendPath(contextName, true);
+
+      //
       controller.router.render(parameters, renderContext);
 
       //

Modified: portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/QualifiedName.java
===================================================================
--- portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/QualifiedName.java	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/QualifiedName.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -33,13 +33,10 @@
    {
       if (qname.length() > 0)
       {
-         if (qname.charAt(0) == '{')
+         int index = qname.indexOf(':');
+         if (index > -1)
          {
-            int index = qname.indexOf('}', 1);
-            if (index != -1)
-            {
-               return new QualifiedName(qname.substring(1, index), qname.substring(index + 1));
-            }
+            return new QualifiedName(qname.substring(0, index), qname.substring(index + 1));
          }
       }
       return new QualifiedName(qname);
@@ -101,7 +98,7 @@
       }
       else
       {
-         return "{" + qualifier + "}" + name;
+         return qualifier + ":" + name;
       }
    }
 

Modified: portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/metadata/DescriptorBuilder.java
===================================================================
--- portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/metadata/DescriptorBuilder.java	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/metadata/DescriptorBuilder.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -20,6 +20,7 @@
 package org.exoplatform.web.controller.metadata;
 
 import org.exoplatform.web.controller.QualifiedName;
+import org.exoplatform.web.controller.router.EncodingMode;
 
 import javax.xml.namespace.QName;
 import javax.xml.stream.XMLStreamConstants;
@@ -43,10 +44,11 @@
    /** . */
    private static final QName requestParamQN = new QName("http://www.gatein.org/xml/ns/gatein_router_1_0", "request-param");
 
+   /** . */
+   private static final QName pathParamQN = new QName("http://www.gatein.org/xml/ns/gatein_router_1_0", "path-param");
+
    public RouterDescriptor build(XMLStreamReader reader) throws Exception
    {
-      System.out.println("reader = " + reader);
-      System.out.println("reader = " + reader.getClass().getName());
       RouterDescriptor routerDesc = new RouterDescriptor();
 
       //
@@ -103,6 +105,14 @@
                String optional = reader.getAttributeValue(null, "required");
                routeDesc.addRequestParam(QualifiedName.parse(name), matchName, matchValue, "true".equals(optional));
             }
+            else if (pathParamQN.equals(reader.getName()))
+            {
+               String name = reader.getAttributeValue(null, "name");
+               String pattern = reader.getAttributeValue(null, "pattern");
+               String encoded = reader.getAttributeValue(null, "encoding");
+               EncodingMode encodingMode = "preserve-path".equals(encoded) ? EncodingMode.PRESERVE_PATH : EncodingMode.DEFAULT_FORM;
+               routeDesc.addPathParam(QualifiedName.parse(name), pattern, encodingMode);
+            }
             else if (routeQN.equals(reader.getName()))
             {
                build(reader, routeDesc.getChildren());

Added: portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/metadata/PathParamDescriptor.java
===================================================================
--- portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/metadata/PathParamDescriptor.java	                        (rev 0)
+++ portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/metadata/PathParamDescriptor.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.exoplatform.web.controller.metadata;
+
+import org.exoplatform.web.controller.QualifiedName;
+import org.exoplatform.web.controller.router.EncodingMode;
+
+/**
+ * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
+ * @version $Revision$
+ */
+public class PathParamDescriptor
+{
+
+   /** . */
+   private final QualifiedName name;
+
+   /** . */
+   private final String pattern;
+
+   /** . */
+   private final EncodingMode encodingMode;
+
+   public PathParamDescriptor(QualifiedName name, String pattern, EncodingMode encodingMode)
+   {
+      if (name == null)
+      {
+         throw new NullPointerException("No null name accepted");
+      }
+      if (pattern == null)
+      {
+         throw new NullPointerException("No null pattern accepted");
+      }
+
+      //
+      this.name = name;
+      this.pattern = pattern;
+      this.encodingMode = encodingMode;
+   }
+
+   public QualifiedName getName()
+   {
+      return name;
+   }
+
+   public String getPattern()
+   {
+      return pattern;
+   }
+
+   public EncodingMode getEncodingMode()
+   {
+      return encodingMode;
+   }
+}

Modified: portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/metadata/RouteDescriptor.java
===================================================================
--- portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/metadata/RouteDescriptor.java	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/metadata/RouteDescriptor.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -20,6 +20,7 @@
 package org.exoplatform.web.controller.metadata;
 
 import org.exoplatform.web.controller.QualifiedName;
+import org.exoplatform.web.controller.router.EncodingMode;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -42,6 +43,9 @@
    private final Map<QualifiedName, String> params;
 
    /** . */
+   private final Map<QualifiedName, PathParamDescriptor> pathParams;
+
+   /** . */
    private final Map<String, RequestParamDescriptor> requestParams;
 
    /** . */
@@ -51,6 +55,7 @@
    {
       this.path = path;
       this.params = new HashMap<QualifiedName, String>();
+      this.pathParams = new HashMap<QualifiedName, PathParamDescriptor>();
       this.requestParams = new HashMap<String, RequestParamDescriptor>();
       this.children = new ArrayList<RouteDescriptor>();
    }
@@ -87,11 +92,27 @@
       return this;
    }
 
+   public RouteDescriptor addPathParam(QualifiedName name, String pattern, EncodingMode encodingMode)
+   {
+      return addRequestParam(new PathParamDescriptor(name, pattern, encodingMode));
+   }
+
+   public RouteDescriptor addRequestParam(PathParamDescriptor requestParam)
+   {
+      pathParams.put(requestParam.getName(), requestParam);
+      return this;
+   }
+
    public Map<String, RequestParamDescriptor> getRequestParams()
    {
       return requestParams;
    }
 
+   public Map<QualifiedName, PathParamDescriptor> getPathParams()
+   {
+      return pathParams;
+   }
+
    public RouteDescriptor addRoute(RouteDescriptor child)
    {
       children.add(child);

Added: portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/EncodingMode.java
===================================================================
--- portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/EncodingMode.java	                        (rev 0)
+++ portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/EncodingMode.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.exoplatform.web.controller.router;
+
+/**
+ * Specifies how a string value should be encoded in an URL.
+ *
+ * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
+ * @version $Revision$
+ */
+public enum EncodingMode
+{
+
+   /**
+    * DEFAULT_FORM encodes the whole string with the <code>x-www-form-urlencoded</code> also known as
+    * <i>default form</i>. For instance the string /a/b is encoded to %2Fa%2Fb.
+    */
+   DEFAULT_FORM,
+
+   /**
+    * PRESERVE_PATH encodes the whole string like the {@link #DEFAULT_FORM} but preserve the path separators. For
+    * instance the string /a b is enocded to /a+b
+    */
+   PRESERVE_PATH
+
+}

Added: portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/PatternParamDef.java
===================================================================
--- portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/PatternParamDef.java	                        (rev 0)
+++ portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/PatternParamDef.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.exoplatform.web.controller.router;
+
+import java.util.regex.Pattern;
+
+/**
+ * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
+ * @version $Revision$
+ */
+class PatternParamDef
+{
+
+   /** . */
+   final EncodingMode encodingMode;
+
+   /** . */
+   final Pattern pattern;
+
+   PatternParamDef(EncodingMode encodingMode, Pattern pattern)
+   {
+      this.encodingMode = encodingMode;
+      this.pattern = pattern;
+   }
+}

Modified: portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/PatternRoute.java
===================================================================
--- portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/PatternRoute.java	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/PatternRoute.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -38,7 +38,7 @@
    final List<QualifiedName> parameterNames;
 
    /** . */
-   final List<Pattern> parameterPatterns;
+   final List<PatternParamDef> parameterPatterns;
 
    /** . */
    final List<String> chunks;
@@ -46,7 +46,7 @@
    PatternRoute(
       Pattern pattern,
       List<QualifiedName> parameterNames,
-      List<Pattern> parameterPatterns,
+      List<PatternParamDef> parameterPatterns,
       List<String> chunks)
    {
       if (chunks.size() != parameterNames.size() + 1)

Modified: portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/RenderContext.java
===================================================================
--- portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/RenderContext.java	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/RenderContext.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -34,14 +34,14 @@
     *
     * @param c the char to append
     */
-   void appendPath(char c);
+   void appendPath(char c, boolean escape);
 
    /**
     * Append a string to the path.
     *
     * @param s the string to append.
     */
-   void appendPath(String s);
+   void appendPath(String s, boolean escape);
 
    /**
     * Append a query parameter to the parameter set. Note that the query parameters are ordered

Modified: portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/Route.java
===================================================================
--- portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/Route.java	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/Route.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -20,6 +20,7 @@
 package org.exoplatform.web.controller.router;
 
 import org.exoplatform.web.controller.QualifiedName;
+import org.exoplatform.web.controller.metadata.PathParamDescriptor;
 import org.exoplatform.web.controller.metadata.RequestParamDescriptor;
 import org.exoplatform.web.controller.metadata.RouteDescriptor;
 
@@ -42,6 +43,9 @@
 class Route
 {
 
+   /** Julien : make that configurable. */
+   private static final char slashEscape = '~';
+
    /** . */
    private Route parent;
 
@@ -107,28 +111,48 @@
       if (this instanceof SegmentRoute)
       {
          SegmentRoute sr = (SegmentRoute)this;
-         renderContext.appendPath('/');
-         renderContext.appendPath(sr.name);
+         renderContext.appendPath('/', false);
+         renderContext.appendPath(sr.name, true);
       }
       else if (this instanceof PatternRoute)
       {
          PatternRoute pr = (PatternRoute)this;
-         renderContext.appendPath('/');
+         renderContext.appendPath('/', false);
          int i = 0;
          while (i < pr.parameterNames.size())
          {
-            renderContext.appendPath(pr.chunks.get(i));
+            renderContext.appendPath(pr.chunks.get(i), true);
             String value = blah.get(pr.parameterNames.get(i));
-            renderContext.appendPath(value);
+            PatternParamDef def = pr.parameterPatterns.get(i);
+
+            //
+            int from = 0;
+            while (true)
+            {
+               int to = value.indexOf('/', from);
+               if (to == -1)
+               {
+                  break;
+               }
+               else
+               {
+                  renderContext.appendPath(value.substring(from, to), true);
+                  renderContext.appendPath(def.encodingMode == EncodingMode.PRESERVE_PATH ? '/' : slashEscape, false);
+                  from = to +1;
+               }
+            }
+            renderContext.appendPath(value.substring(from), false);
+
+            //
             i++;
          }
-         renderContext.appendPath(pr.chunks.get(i));
+         renderContext.appendPath(pr.chunks.get(i), false);
       }
       else
       {
          if (!hasChildren)
          {
-            renderContext.appendPath("/");
+            renderContext.appendPath('/', false);
          }
       }
    }
@@ -182,9 +206,31 @@
          for (int i = 0;i < prt.parameterNames.size();i++)
          {
             QualifiedName qd = prt.parameterNames.get(i);
+            PatternParamDef ppd = prt.parameterPatterns.get(i);
             String s = blah.get(qd);
-            if (s != null && prt.parameterPatterns.get(i).matcher(s).matches())
+            boolean matched = false;
+            if (s != null)
             {
+               switch (ppd.encodingMode)
+               {
+                  case DEFAULT_FORM:
+
+                     // JULIEN
+                     // TEMPORARY WORD AROUND
+                     // FIX ME
+                     s = s.replace('/', '~');
+
+                     matched = ppd.pattern.matcher(s).matches();
+                     break;
+                  case PRESERVE_PATH:
+                     matched = ppd.pattern.matcher(s).matches();
+                     break;
+                  default:
+                     throw new AssertionError();
+               }
+            }
+            if (matched)
+            {
                abc.remove(qd);
             }
             else
@@ -226,6 +272,7 @@
    }
 
    /**
+    *
     * @param path the path
     * @param requestParams the query parameters
     * @return null or the parameters when it matches
@@ -344,9 +391,15 @@
                   {
                      // Append parameters
                      int group = 1;
-                     for (QualifiedName parameterName : route.parameterNames)
+                     for (int i = 0;i < route.parameterNames.size();i++)
                      {
-                        response.put(parameterName, matcher.group(group++));
+                        QualifiedName parameterName = route.parameterNames.get(i);
+                        String value = matcher.group(group++);
+                        if (route.parameterPatterns.get(i).encodingMode == EncodingMode.DEFAULT_FORM)
+                        {
+                           value = value.replace(slashEscape, '/');
+                        }
+                        response.put(parameterName, value);
                      }
 
                      //
@@ -387,9 +440,6 @@
       return ret;
    }
 
-   /** . */
-   private static final Pattern PARAMETER_REGEX = Pattern.compile("^(?:\\{([^\\}]*)\\})?(.*)$");
-
    final <R extends Route> R add(R route)
    {
       if (route.parent != null)
@@ -454,7 +504,7 @@
 
    final Route append(RouteDescriptor descriptor)
    {
-      Route route = append(descriptor.getPath());
+      Route route = append(descriptor.getPathParams(), descriptor.getPath());
 
       //
       route.terminal = true;
@@ -476,10 +526,11 @@
    }
 
    final Route append(
+      Map<QualifiedName, PathParamDescriptor> pathParamDescriptors,
       String path,
       Map<QualifiedName, String> parameters)
    {
-      Route route = append(path);
+      Route route = append(pathParamDescriptors, path);
       route.terminal = true;
       route.routeParameters.putAll(parameters);
       return route;
@@ -488,10 +539,11 @@
    /**
     * Append a path, creates the necessary routes and returns the last route added.
     *
+    * @param pathParamDescriptors the path param descriptors
     * @param path the path to append
     * @return the last route added
     */
-   private Route append(String path)
+   private Route append(Map<QualifiedName, PathParamDescriptor> pathParamDescriptors, String path)
    {
       int pos = path.length();
       int level = 0;
@@ -548,48 +600,33 @@
             PatternBuilder builder = new PatternBuilder();
             builder.expr("^");
             List<String> chunks = new ArrayList<String>();
-            List<Pattern> parameterPatterns = new ArrayList<Pattern>();
+            List<PatternParamDef> parameterPatterns = new ArrayList<PatternParamDef>();
             int previous = 0;
             for (int i = 0;i < start.size();i++)
             {
                builder.litteral(path, previous, start.get(i));
                chunks.add(path.substring(previous, start.get(i)));
-               String parameterDef = path.substring(start.get(i) + 1, end.get(i));
-               int colon = parameterDef.indexOf(':');
-               String regex;
-               String parameterName;
-               if (colon == -1)
-               {
-                  regex = "[^/]+";
-                  parameterName = parameterDef;
-               }
-               else
-               {
-                  regex = parameterDef.substring(colon + 1);
-                  parameterName = parameterDef.substring(0, colon);
-               }
+               String parameterName = path.substring(start.get(i) + 1, end.get(i));
 
                //
-               QualifiedName parameterQName;
-               Matcher parameterMatcher = PARAMETER_REGEX.matcher(parameterName);
-               if (parameterMatcher.matches())
+               QualifiedName parameterQName = QualifiedName.parse(parameterName);
+
+               // Now get path param metadata
+               PathParamDescriptor parameterDescriptor = pathParamDescriptors.get(parameterQName);
+               String regex = "[^/]+";
+               EncodingMode encodingMode = EncodingMode.DEFAULT_FORM;
+               if (parameterDescriptor != null)
                {
-                  String qualifier = parameterMatcher.group(1);
-                  String name = parameterMatcher.group(2);
-                  parameterQName = new QualifiedName(qualifier == null ? "" : qualifier, name);
+                  regex = parameterDescriptor.getPattern();
+                  encodingMode = parameterDescriptor.getEncodingMode();
                }
-               else
-               {
-                  throw new AssertionError();
-               }
 
-
                //
                builder.expr("(");
                builder.expr(regex);
                builder.expr(")");
                parameterNames.add(parameterQName);
-               parameterPatterns.add(Pattern.compile("^" + regex + "$"));
+               parameterPatterns.add(new PatternParamDef(encodingMode, Pattern.compile("^" + regex + "$")));
                previous = end.get(i) + 1;
             }
             builder.litteral(path, previous, pos);
@@ -614,7 +651,7 @@
       //
       if (pos < path.length())
       {
-         return next.append(path.substring(pos + 1));
+         return next.append(pathParamDescriptors, path.substring(pos + 1));
       }
       else
       {

Modified: portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/SimpleRenderContext.java
===================================================================
--- portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/SimpleRenderContext.java	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/component/web/controller/src/main/java/org/exoplatform/web/controller/router/SimpleRenderContext.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -19,6 +19,8 @@
 
 package org.exoplatform.web.controller.router;
 
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -72,24 +74,34 @@
       }
    }
 
-   public void appendPath(char c)
+   public void appendPath(char c, boolean escape)
    {
-      if (sb == null)
-      {
-         sb = new StringBuilder();
-      }
-      sb.append(c);
+      appendPath(String.valueOf(c), escape);
    }
 
-   public void appendPath(String s)
+   public void appendPath(String s, boolean escape)
    {
+      //To change body of implemented methods use File | Settings | File Templates.
       if (sb == null)
       {
          sb = new StringBuilder();
       }
-      sb.append(s);
+      if (escape)
+      {
+         try
+         {
+            sb.append(URLEncoder.encode(s, "UTF-8"));
+         }
+         catch (UnsupportedEncodingException e)
+         {
+            throw new AssertionError(e);
+         }
+      }
+      else
+      {
+         sb.append(s);
+      }
    }
-
    public void appendQueryParameter(String parameterName, String paramaterValue)
    {
       if (queryParams == EMPTY)
@@ -98,5 +110,4 @@
       }
       queryParams.put(parameterName, paramaterValue);
    }
-
 }

Modified: portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestBuildRoute.java
===================================================================
--- portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestBuildRoute.java	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestBuildRoute.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -76,7 +76,8 @@
          assertEquals("^([^/]+)", patternRoute.pattern.toString());
          assertEquals(Collections.singletonList(new QualifiedName("a")), patternRoute.parameterNames);
          assertEquals(1, patternRoute.parameterPatterns.size());
-         assertEquals("^[^/]+$", patternRoute.parameterPatterns.get(0).toString());
+         assertEquals("^[^/]+$", patternRoute.parameterPatterns.get(0).pattern.toString());
+         assertEquals(EncodingMode.DEFAULT_FORM, patternRoute.parameterPatterns.get(0).encodingMode);
          assertEquals(2, patternRoute.chunks.size());
          assertEquals("", patternRoute.chunks.get(0));
          assertEquals("", patternRoute.chunks.get(1));
@@ -85,7 +86,7 @@
 
    public void testQualifiedParameterSegment()
    {
-      String[] paths = {"/{{q}a}","{{q}a}"};
+      String[] paths = {"/{q:a}","{q:a}"};
       for (String path : paths)
       {
          RouterDescriptor routerMD = new RouterDescriptor();
@@ -99,7 +100,8 @@
          assertEquals("^([^/]+)", patternRoute.pattern.toString());
          assertEquals(Collections.singletonList(new QualifiedName("q", "a")), patternRoute.parameterNames);
          assertEquals(1, patternRoute.parameterPatterns.size());
-         assertEquals("^[^/]+$", patternRoute.parameterPatterns.get(0).toString());
+         assertEquals("^[^/]+$", patternRoute.parameterPatterns.get(0).pattern.toString());
+         assertEquals(EncodingMode.DEFAULT_FORM, patternRoute.parameterPatterns.get(0).encodingMode);
          assertEquals(2, patternRoute.chunks.size());
          assertEquals("", patternRoute.chunks.get(0));
          assertEquals("", patternRoute.chunks.get(1));
@@ -108,11 +110,11 @@
 
    public void testPatternSegment()
    {
-      String[] paths = {"/{a:.*}","{a:.*}"};
+      String[] paths = {"/{a}","{a}"};
       for (String path : paths)
       {
          RouterDescriptor routerMD = new RouterDescriptor();
-         routerMD.addRoute(new RouteDescriptor(path));
+         routerMD.addRoute(new RouteDescriptor(path).addPathParam(QualifiedName.parse("a"), ".*", EncodingMode.DEFAULT_FORM));
          Router router = new Router(routerMD);
 
          //
@@ -122,7 +124,8 @@
          assertEquals("^(.*)", patternRoute.pattern.toString());
          assertEquals(Collections.singletonList(new QualifiedName("a")), patternRoute.parameterNames);
          assertEquals(1, patternRoute.parameterPatterns.size());
-         assertEquals("^.*$", patternRoute.parameterPatterns.get(0).toString());
+         assertEquals("^.*$", patternRoute.parameterPatterns.get(0).pattern.toString());
+         assertEquals(EncodingMode.DEFAULT_FORM, patternRoute.parameterPatterns.get(0).encodingMode);
          assertEquals(2, patternRoute.chunks.size());
          assertEquals("", patternRoute.chunks.get(0));
          assertEquals("", patternRoute.chunks.get(1));

Modified: portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestDescriptorBuilder.java
===================================================================
--- portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestDescriptorBuilder.java	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestDescriptorBuilder.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -53,14 +53,22 @@
       //
       assertTrue(i.hasNext());
       RouteDescriptor route1 = i.next();
-      assertEquals("/public/{{gtn}sitetype}/{{gtn}sitename}{{gtn}path:.*}", route1.getPath());
+      assertEquals("/public/{gtn:sitetype}/{gtn:sitename}{gtn:path}", route1.getPath());
       assertEquals(Collections.singletonMap(WebAppController.HANDLER_PARAM, "portal"), route1.getParams());
+      assertEquals(Collections.singleton(QualifiedName.parse("gtn:path")), route1.getPathParams().keySet());
+      assertEquals(QualifiedName.parse("gtn:path"), route1.getPathParams().get(QualifiedName.parse("gtn:path")).getName());
+      assertEquals(".*", route1.getPathParams().get(QualifiedName.parse("gtn:path")).getPattern());
+      assertEquals(EncodingMode.DEFAULT_FORM, route1.getPathParams().get(QualifiedName.parse("gtn:path")).getEncodingMode());
 
       //
       assertTrue(i.hasNext());
       RouteDescriptor route2 = i.next();
-      assertEquals("/private/{{gtn}sitetype}/{{gtn}sitename}{{gtn}path:.*}", route2.getPath());
+      assertEquals("/private/{gtn:sitetype}/{gtn:sitename}{gtn:path}", route2.getPath());
       assertEquals(Collections.singletonMap(WebAppController.HANDLER_PARAM, "portal"), route2.getParams());
+      assertEquals(Collections.singleton(QualifiedName.parse("gtn:path")), route2.getPathParams().keySet());
+      assertEquals(QualifiedName.parse("gtn:path"), route2.getPathParams().get(QualifiedName.parse("gtn:path")).getName());
+      assertEquals(".*", route2.getPathParams().get(QualifiedName.parse("gtn:path")).getPattern());
+      assertEquals(EncodingMode.PRESERVE_PATH, route2.getPathParams().get(QualifiedName.parse("gtn:path")).getEncodingMode());
 
       //
       assertTrue(i.hasNext());

Modified: portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestLegacyPortal.java
===================================================================
--- portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestLegacyPortal.java	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestLegacyPortal.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -44,14 +44,14 @@
       RouterDescriptor routerMD = new RouterDescriptor();
 
       RouteDescriptor portal = new RouteDescriptor("/").
-         addParam(QualifiedName.parse("{gtn}handler"), "portal").
-         addRequestParam(QualifiedName.parse("{gtn}componentid"), "portal:componentId", null, false).
-         addRequestParam(QualifiedName.parse("{gtn}action"), "portal:action", null, false).
-         addRequestParam(QualifiedName.parse("{gtn}objectid"), "portal:objectId", null, false).
-         addRoute(new RouteDescriptor("/public/{{gtn}sitename}{{gtn}path:.*}").
-            addParam(QualifiedName.parse("{gtn}access"), "public")).
-         addRoute(new RouteDescriptor("/private/{{gtn}sitename}{{gtn}path:.*}").
-            addParam(QualifiedName.parse("{gtn}access"), "private"));
+         addParam(QualifiedName.parse("gtn:handler"), "portal").
+         addRequestParam(QualifiedName.parse("gtn:componentid"), "portal:componentId", null, false).
+         addRequestParam(QualifiedName.parse("gtn:action"), "portal:action", null, false).
+         addRequestParam(QualifiedName.parse("gtn:objectid"), "portal:objectId", null, false).
+         addRoute(new RouteDescriptor("/public/{gtn:sitename}{gtn:path}").
+            addParam(QualifiedName.parse("gtn:access"), "public")).addPathParam(QualifiedName.parse("gtn:path"), ".*", EncodingMode.PRESERVE_PATH).
+         addRoute(new RouteDescriptor("/private/{gtn:sitename}{gtn:path}").addPathParam(QualifiedName.parse("gtn:path"), ".*", EncodingMode.PRESERVE_PATH).
+            addParam(QualifiedName.parse("gtn:access"), "private"));
 
       //
       routerMD.addRoute(portal);

Modified: portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestMatch.java
===================================================================
--- portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestMatch.java	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestMatch.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -42,14 +42,8 @@
 
       //
       assertNull(router.route(""));
-
-      //
       assertEquals(Collections.<QualifiedName, String>emptyMap(), router.route("/"));
-
-      //
       assertNull(router.route("/a"));
-
-      //
       assertNull(router.route("a"));
    }
 
@@ -61,29 +55,13 @@
 
       //
       assertEquals(Collections.<QualifiedName, String>emptyMap(), router.route("/a"));
-
-      //
       assertNull(router.route("a"));
-
-      //
       assertNull(router.route("a/"));
-
-      //
       assertEquals(Collections.<QualifiedName, String>emptyMap(), router.route("/a/"));
-
-      //
       assertNull(router.route(""));
-
-      //
       assertNull(router.route("/"));
-
-      //
       assertNull(router.route("/b"));
-
-      //
       assertNull(router.route("b"));
-
-      //
       assertNull(router.route("/a/b"));
    }
 
@@ -95,29 +73,13 @@
 
       //
       assertNull(router.route("a/b"));
-
-      //
       assertEquals(Collections.<QualifiedName, String>emptyMap(), router.route("/a/b"));
-
-      //
       assertEquals(Collections.<QualifiedName, String>emptyMap(), router.route("/a/b/"));
-
-      //
       assertNull(router.route("a/b/"));
-
-      //
       assertNull(router.route(""));
-
-      //
       assertNull(router.route("/"));
-
-      //
       assertNull(router.route("/b"));
-
-      //
       assertNull(router.route("b"));
-
-      //
       assertNull(router.route("/a/b/c"));
    }
 
@@ -126,7 +88,9 @@
       RouterDescriptor routerMD = new RouterDescriptor();
       routerMD.addRoute(new RouteDescriptor("/{p}"));
       Router router = new Router(routerMD);
-      assertEquals(Collections.singletonMap(new QualifiedName("p"), "a"), router.route(("/a")));
+
+      //
+      assertEquals(Collections.singletonMap(new QualifiedName("p"), "a"), router.route("/a"));
    }
 
    public void testParameterPropagationToDescendants() throws Exception
@@ -135,44 +99,44 @@
       routerMD.addRoute(new RouteDescriptor("/").addParam("p", "a"));
       routerMD.addRoute(new RouteDescriptor("/a"));
       Router router = new Router(routerMD);
-      assertEquals(Collections.singletonMap(new QualifiedName("p"), "a"), router.route(("/a")));
+
+      //
+      assertEquals(Collections.singletonMap(new QualifiedName("p"), "a"), router.route("/a"));
    }
 
    public void testWildcardPattern() throws Exception
    {
       RouterDescriptor routerMD = new RouterDescriptor();
-      routerMD.addRoute(new RouteDescriptor("/{p:.*}"));
+      routerMD.addRoute(new RouteDescriptor("/{p}").addPathParam(QualifiedName.parse("p"), ".*", EncodingMode.PRESERVE_PATH));
       Router router = new Router(routerMD);
 
       //
       assertEquals(Collections.singletonMap(new QualifiedName("p"), ""), router.route("/"));
-
-      //
       assertEquals(Collections.singletonMap(new QualifiedName("p"), "a"), router.route("/a"));
+      assertNull(router.route("a"));
+      assertEquals(Collections.singletonMap(new QualifiedName("p"), "a/b"), router.route("/a/b"));
+   }
 
-      //
-      assertNull(router.route(("a")));
+   public void testDefaultForm() throws Exception
+   {
+      RouterDescriptor routerMD = new RouterDescriptor();
+      routerMD.addRoute(new RouteDescriptor("/{p}").addPathParam(QualifiedName.parse("p"), "[^/]+", EncodingMode.DEFAULT_FORM));
+      Router router = new Router(routerMD);
 
       //
-      assertEquals(Collections.singletonMap(new QualifiedName("p"), "a/b"), router.route("/a/b"));
+      assertEquals(Collections.singletonMap(new QualifiedName("p"), "/"), router.route("/~"));
    }
 
    public void testSimplePattern() throws Exception
    {
       RouterDescriptor routerMD = new RouterDescriptor();
-      routerMD.addRoute(new RouteDescriptor("/{p:a}"));
+      routerMD.addRoute(new RouteDescriptor("/{p}").addPathParam(QualifiedName.parse("p"), "a", EncodingMode.DEFAULT_FORM));
       Router router = new Router(routerMD);
 
       //
       assertEquals(Collections.singletonMap(new QualifiedName("p"), "a"), router.route("/a"));
-
-      //
       assertNull(router.route("a"));
-
-      //
       assertNull(router.route("/ab"));
-
-      //
       assertNull(router.route("ab"));
    }
 
@@ -180,19 +144,13 @@
    {
       RouterDescriptor routerMD = new RouterDescriptor();
       routerMD.addRoute(new RouteDescriptor("/a"));
-      routerMD.addRoute(new RouteDescriptor("/{p:a}/b"));
+      routerMD.addRoute(new RouteDescriptor("/{p}/b").addPathParam(QualifiedName.parse("p"), "a", EncodingMode.DEFAULT_FORM));
       Router router = new Router(routerMD);
 
       //
-      assertNull(router.route(("a")));
-
-      //
+      assertNull(router.route("a"));
       assertEquals(Collections.<QualifiedName, String>emptyMap(), router.route("/a"));
-
-      //
       assertEquals(Collections.<QualifiedName, String>emptyMap(), router.route("/a/"));
-
-      //
       assertEquals(Collections.singletonMap(new QualifiedName("p"), "a"), router.route("/a/b"));
    }
 

Modified: portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestPortalConfiguration.java
===================================================================
--- portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestPortalConfiguration.java	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestPortalConfiguration.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -43,24 +43,28 @@
       RouterDescriptor routerMD = new RouterDescriptor();
 
       //
-      RouteDescriptor portalRouteMD = new RouteDescriptor("/private/{{gtn}sitetype}/{{gtn}sitename}{{gtn}path:.*}");
+      RouteDescriptor portalRouteMD = new RouteDescriptor("/private/{gtn:sitetype}/{gtn:sitename}{gtn:path}");
       portalRouteMD.addParam(new QualifiedName("gtn", "controller"), "site");
       portalRouteMD.addRequestParam(new QualifiedName("gtn", "componentid"), "portal:componentId", null, false);
+      portalRouteMD.addPathParam(new QualifiedName("gtn", "path"), ".*", EncodingMode.PRESERVE_PATH);
       routerMD.addRoute(portalRouteMD);
 
       //
-      RouteDescriptor portalRouteMD2 = new RouteDescriptor("/private/{{gtn}sitetype}/{{gtn}sitename}{{gtn}path:.*}");
+      RouteDescriptor portalRouteMD2 = new RouteDescriptor("/private/{gtn:sitetype}/{gtn:sitename}{gtn:path}");
       portalRouteMD2.addParam(new QualifiedName("gtn", "controller"), "site");
+      portalRouteMD2.addPathParam(new QualifiedName("gtn", "path"), ".*", EncodingMode.PRESERVE_PATH);
       routerMD.addRoute(portalRouteMD2);
 
       //
-      RouteDescriptor groupRouteMD = new RouteDescriptor("/groups/{{gtn}sitetype}/{{gtn}sitename}{{gtn}path:.*}");
-      portalRouteMD.addParam(new QualifiedName("gtn", "controller"), "site");
+      RouteDescriptor groupRouteMD = new RouteDescriptor("/groups/{gtn:sitetype}/{gtn:sitename}{gtn:path}");
+      groupRouteMD.addParam(new QualifiedName("gtn", "controller"), "site");
+      groupRouteMD.addPathParam(new QualifiedName("gtn", "path"), ".*", EncodingMode.PRESERVE_PATH);
       routerMD.addRoute(groupRouteMD);
 
       //
-      RouteDescriptor userRouteMD = new RouteDescriptor("/users/{{gtn}sitetype}/{{gtn}sitename}{{gtn}path:.*}");
-      portalRouteMD.addParam(new QualifiedName("gtn", "controller"), "site");
+      RouteDescriptor userRouteMD = new RouteDescriptor("/users/{gtn:sitetype}/{gtn:sitename}{gtn:path}");
+      userRouteMD.addParam(new QualifiedName("gtn", "controller"), "site");
+      userRouteMD.addPathParam(new QualifiedName("gtn", "path"), ".*", EncodingMode.PRESERVE_PATH);
       routerMD.addRoute(userRouteMD);
 
       //

Modified: portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestRender.java
===================================================================
--- portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestRender.java	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestRender.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -62,7 +62,7 @@
       assertEquals("/a/b", router.render(Collections.<QualifiedName, String>emptyMap()));
    }
 
-   public void testParameter() throws Exception
+   public void testPathParam() throws Exception
    {
       RouterDescriptor routerMD = new RouterDescriptor();
       routerMD.addRoute(new RouteDescriptor("/{p}"));
@@ -73,40 +73,74 @@
       assertNull(router.render(Collections.<QualifiedName, String>emptyMap()));
    }
 
-   public void testWildcardPattern() throws Exception
+   public void testSimplePatternPathParam() throws Exception
    {
       RouterDescriptor routerMD = new RouterDescriptor();
-      routerMD.addRoute(new RouteDescriptor("/{p:.*}"));
+      routerMD.addRoute(new RouteDescriptor("/{p}").addPathParam(QualifiedName.parse("p"), "a", EncodingMode.DEFAULT_FORM));
       Router router = new Router(routerMD);
 
       //
-      assertEquals("/", router.render(Collections.singletonMap(new QualifiedName("p"), "")));
+      assertEquals("/a", router.render(Collections.singletonMap(new QualifiedName("p"), "a")));
+      assertNull(router.render(Collections.singletonMap(new QualifiedName("p"), "ab")));
+   }
 
+   public void testWildcardPathParam() throws Exception
+   {
+      RouterDescriptor routerMD = new RouterDescriptor();
+      routerMD.addRoute(new RouteDescriptor("/{p}").addPathParam(QualifiedName.parse("p"), ".*", EncodingMode.PRESERVE_PATH));
+      Router router = new Router(routerMD);
+
       //
+      assertEquals("/", router.render(Collections.singletonMap(new QualifiedName("p"), "")));
       assertEquals("/a", router.render(Collections.singletonMap(new QualifiedName("p"), "a")));
+      assertEquals("/a/b", router.render(Collections.singletonMap(new QualifiedName("p"), "a/b")));
+   }
 
+   public void testFoo() throws Exception
+   {
+      RouterDescriptor routerMD = new RouterDescriptor();
+      routerMD.addRoute(new RouteDescriptor("/{p}").addPathParam(QualifiedName.parse("p"), "[^/]*", EncodingMode.PRESERVE_PATH));
+      Router router = new Router(routerMD);
+
       //
-      assertEquals("/a/b", router.render(Collections.singletonMap(new QualifiedName("p"), "a/b")));
+      assertEquals(null, router.render(Collections.singletonMap(new QualifiedName("p"), "/")));
    }
 
-   public void testSimplePattern() throws Exception
+   public void testBar() throws Exception
    {
       RouterDescriptor routerMD = new RouterDescriptor();
-      routerMD.addRoute(new RouteDescriptor("/{p:a}"));
+      routerMD.addRoute(new RouteDescriptor("/{p}").addPathParam(QualifiedName.parse("p"), "[^/]*", EncodingMode.DEFAULT_FORM));
       Router router = new Router(routerMD);
 
       //
-      assertEquals("/a", router.render(Collections.singletonMap(new QualifiedName("p"), "a")));
+      assertEquals("/~", router.render(Collections.singletonMap(new QualifiedName("p"), "/")));
+   }
 
+   public void testWildcardParamPathPreservePathEncoding() throws Exception
+   {
+      RouterDescriptor routerMD = new RouterDescriptor();
+      routerMD.addRoute(new RouteDescriptor("/{p}").addPathParam(QualifiedName.parse("p"), ".*", EncodingMode.PRESERVE_PATH));
+      Router router = new Router(routerMD);
+
       //
-      assertNull(router.render(Collections.singletonMap(new QualifiedName("p"), "ab")));
+      assertEquals("//", router.render(Collections.singletonMap(new QualifiedName("p"), "/")));
    }
 
+   public void testWildcardParamPathDefaultFormEncoded() throws Exception
+   {
+      RouterDescriptor routerMD = new RouterDescriptor();
+      routerMD.addRoute(new RouteDescriptor("/{p}").addPathParam(QualifiedName.parse("p"), ".*", EncodingMode.DEFAULT_FORM));
+      Router router = new Router(routerMD);
+
+      //
+      assertEquals("/~", router.render(Collections.singletonMap(new QualifiedName("p"), "/")));
+   }
+
    public void testPrecedence() throws Exception
    {
       RouterDescriptor routerMD = new RouterDescriptor();
       routerMD.addRoute(new RouteDescriptor("/a"));
-      routerMD.addRoute(new RouteDescriptor("/{p:a}/b"));
+      routerMD.addRoute(new RouteDescriptor("/{p}/b").addPathParam(QualifiedName.parse("p"), "a", EncodingMode.DEFAULT_FORM));
       Router router = new Router(routerMD);
 
       //

Modified: portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/router.xml
===================================================================
--- portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/router.xml	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/component/web/controller/src/test/java/org/exoplatform/web/controller/router/router.xml	2010-11-04 11:22:09 UTC (rev 4941)
@@ -3,20 +3,22 @@
     xsi:schemaLocation="http://www.gatein.org/xml/ns/gatein_router_1_0 http://www.gatein.org/xml/ns/gatein_router_1_0"
     xmlns="http://www.gatein.org/xml/ns/gatein_router_1_0">
 
-  <route path="/public/{{gtn}sitetype}/{{gtn}sitename}{{gtn}path:.*}">
-    <param name="{gtn}handler" value="portal"/>
+  <route path="/public/{gtn:sitetype}/{gtn:sitename}{gtn:path}">
+    <param name="gtn:handler" value="portal"/>
+    <path-param name="gtn:path" pattern=".*"/>
   </route>
 
-  <route path="/private/{{gtn}sitetype}/{{gtn}sitename}{{gtn}path:.*}">
-    <param name="{gtn}handler" value="portal"/>
+  <route path="/private/{gtn:sitetype}/{gtn:sitename}{gtn:path}">
+    <param name="gtn:handler" value="portal"/>
+    <path-param name="gtn:path" pattern=".*" encoding="preserve-path"/>
   </route>
 
   <route path="/upload">
-    <param name="{gtn}handler" value="upload"/>
+    <param name="gtn:handler" value="upload"/>
   </route>
 
   <route path="/download">
-    <param name="{gtn}handler" value="download"/>
+    <param name="gtn:handler" value="download"/>
   </route>
 
   <route path="/a">

Modified: portal/branches/navcontroller/portlet/exoadmin/src/main/webapp/groovy/admintoolbar/webui/component/UIUserToolBarGroupPortlet.gtmpl
===================================================================
--- portal/branches/navcontroller/portlet/exoadmin/src/main/webapp/groovy/admintoolbar/webui/component/UIUserToolBarGroupPortlet.gtmpl	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/portlet/exoadmin/src/main/webapp/groovy/admintoolbar/webui/component/UIUserToolBarGroupPortlet.gtmpl	2010-11-04 11:22:09 UTC (rev 4941)
@@ -48,7 +48,7 @@
     boolean hasChild = (node.getChildren() != null && node.getChildren().size() > 0);
     String clazz = "";
     if(hasChild) clazz = "ArrowIcon";
-    String actionLink = nodeURL.setResource(new NavigationResource(navigation.getOwnerType(), navigation.getOwnerId().replaceAll("/", "_"), node)).toString();
+    String actionLink = nodeURL.setResource(new NavigationResource(navigation.getOwnerType(), navigation.getOwnerId(), node)).toString();
     String icon = node.getIcon();
     if(icon == null) icon = "DefaultPageIcon";
     boolean toolong = (node.resolvedLabel.length() > 60);

Modified: portal/branches/navcontroller/web/portal/src/main/webapp/WEB-INF/conf/default-router.xml
===================================================================
--- portal/branches/navcontroller/web/portal/src/main/webapp/WEB-INF/conf/default-router.xml	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/web/portal/src/main/webapp/WEB-INF/conf/default-router.xml	2010-11-04 11:22:09 UTC (rev 4941)
@@ -6,40 +6,42 @@
   <route path="/">
 
     <!-- Use the portal handler -->
-    <param name="{gtn}handler" value="portal"/>
+    <param name="gtn:handler" value="portal"/>
 
     <!-- Webui parameters -->
-    <request-param name="{gtn}componentid" matchName="portal:componentId" required="false"/>
-    <request-param name="{gtn}action" matchName="portal:action" required="false"/>
-    <request-param name="{gtn}objectid" matchName="objectId" required="false"/>
+    <request-param name="gtn:componentid" matchName="portal:componentId" required="false"/>
+    <request-param name="gtn:action" matchName="portal:action" required="false"/>
+    <request-param name="gtn:objectid" matchName="objectId" required="false"/>
 
     <!-- Map the sitemap navigation on the /foo path -->
 <!--
     <route path="/foo">
-      <param name="{gtn}access" value="public"/>
-      <param name="{gtn}sitename" value="classic"/>
-      <param name="{gtn}path" value="/sitemap"/>
+      <param name="gtn:access" value="public"/>
+      <param name="gtn:sitename" value="classic"/>
+      <param name="gtn:path" value="/sitemap"/>
     </route>
 -->
 
     <!-- The public access -->
-    <route path="/public/{{gtn}sitetype}/{{gtn}sitename}{{gtn}path:.*}">
-      <param name="{gtn}access" value="public"/>
+    <route path="/public/{gtn:sitetype}/{gtn:sitename}{gtn:path}">
+      <param name="gtn:access" value="public"/>
+      <path-param name="gtn:path" pattern=".*" encoding="preserve-path"/>
     </route>
 
     <!-- The private access -->
-    <route path="/private/{{gtn}sitetype}/{{gtn}sitename}{{gtn}path:.*}">
-      <param name="{gtn}access" value="private"/>
+    <route path="/private/{gtn:sitetype}/{gtn:sitename}{gtn:path}">
+      <param name="gtn:access" value="private"/>
+      <path-param name="gtn:path" pattern=".*" encoding="preserve-path"/>
     </route>
 
   </route>
 
   <route path="/upload">
-    <param name="{gtn}handler" value="upload"/>
+    <param name="gtn:handler" value="upload"/>
   </route>
 
   <route path="/download">
-    <param name="{gtn}handler" value="download"/>
+    <param name="gtn:handler" value="download"/>
   </route>
 
 </router>
\ No newline at end of file

Modified: portal/branches/navcontroller/web/portal/src/main/webapp/WEB-INF/conf/proto-router-1.xml
===================================================================
--- portal/branches/navcontroller/web/portal/src/main/webapp/WEB-INF/conf/proto-router-1.xml	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/web/portal/src/main/webapp/WEB-INF/conf/proto-router-1.xml	2010-11-04 11:22:09 UTC (rev 4941)
@@ -8,31 +8,33 @@
   <route path="/">
 
     <!-- Use the portal handler -->
-    <param name="{gtn}handler" value="portal"/>
+    <param name="gtn:handler" value="portal"/>
 
     <!-- Webui parameters -->
-    <request-param name="{gtn}componentid" matchName="portal:componentId" required="false"/>
-    <request-param name="{gtn}action" matchName="portal:action" required="false"/>
-    <request-param name="{gtn}objectid" matchName="objectId" required="false"/>
+    <request-param name="gtn:componentid" matchName="portal:componentId" required="false"/>
+    <request-param name="gtn:action" matchName="portal:action" required="false"/>
+    <request-param name="gtn:objectid" matchName="objectId" required="false"/>
 
     <!-- The public access -->
-    <route path="/public/{{gtn}sitename}{{gtn}path:.*}.html">
-      <param name="{gtn}access" value="public"/>
+    <route path="/public/{gtn:sitename}{gtn:path}.html">
+      <param name="gtn:access" value="public"/>
+      <path-param name="gtn:path" pattern=".*" encoding="preserve-path"/>
     </route>
 
     <!-- The private access -->
-    <route path="/private/{{gtn}sitename}{{gtn}path:.*}.html">
-      <param name="{gtn}access" value="private"/>
+    <route path="/private/{gtn:sitename}{gtn:path}.html">
+      <param name="gtn:access" value="private"/>
+      <path-param name="gtn:path" pattern=".*" encoding="preserve-path"/>
     </route>
 
   </route>
 
   <route path="/upload">
-    <param name="{gtn}handler" value="upload"/>
+    <param name="gtn:handler" value="upload"/>
   </route>
 
   <route path="/download">
-    <param name="{gtn}handler" value="download"/>
+    <param name="gtn:handler" value="download"/>
   </route>
 
 </router>
\ No newline at end of file

Modified: portal/branches/navcontroller/web/portal/src/main/webapp/groovy/webui/core/UISitemapTree.gtmpl
===================================================================
--- portal/branches/navcontroller/web/portal/src/main/webapp/groovy/webui/core/UISitemapTree.gtmpl	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/web/portal/src/main/webapp/groovy/webui/core/UISitemapTree.gtmpl	2010-11-04 11:22:09 UTC (rev 4941)
@@ -37,7 +37,7 @@
 			actionExpand = uicomponent.event("ExpandNode", nav.getId() + "::" + node.getUri());				
 			def actionCollapse = "ajaxAsyncGetRequest('" + uicomponent.url("CollapseNode",nav.getId() + "::" + node.getUri()) + "', true)";	
 
-      String actionLink = nodeURL.setResource(new NavigationResource(nav.getOwnerType(), nav.getOwnerId().replaceAll("/", "_"), node)).toString();
+      String actionLink = nodeURL.setResource(new NavigationResource(nav.getOwnerType(), nav.getOwnerId(), node)).toString();
 			
 			lastNode = '';
 			

Modified: portal/branches/navcontroller/webui/portal/src/main/java/org/exoplatform/portal/application/PortalRequestContext.java
===================================================================
--- portal/branches/navcontroller/webui/portal/src/main/java/org/exoplatform/portal/application/PortalRequestContext.java	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/webui/portal/src/main/java/org/exoplatform/portal/application/PortalRequestContext.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -239,7 +239,7 @@
 */
       //
       this.siteType = requestSiteType;
-      this.siteName = requestSiteName.replaceAll("_", "/");
+      this.siteName = requestSiteName;
       this.nodePath_ = requestPath;
       this.access = access;
 
@@ -273,7 +273,7 @@
    @Override
    public <R, L extends ResourceLocator<R>> ControllerURL<R, L> newURL(ResourceType<R, L> resourceType, L locator)
    {
-      return new PortalURL<R, L>(controllerContext, locator, false, siteType, siteName.replaceAll("/", "_"), access);
+      return new PortalURL<R, L>(controllerContext, locator, false, siteType, siteName, access);
    }
 
    public ControllerContext getControllerContext()

Modified: portal/branches/navcontroller/webui/portal/src/main/java/org/exoplatform/portal/url/PortalURL.java
===================================================================
--- portal/branches/navcontroller/webui/portal/src/main/java/org/exoplatform/portal/url/PortalURL.java	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/webui/portal/src/main/java/org/exoplatform/portal/url/PortalURL.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -19,17 +19,13 @@
 
 package org.exoplatform.portal.url;
 
-import org.exoplatform.Constants;
 import org.exoplatform.portal.application.PortalRequestHandler;
 import org.exoplatform.web.ControllerContext;
 import org.exoplatform.web.WebAppController;
 import org.exoplatform.web.controller.QualifiedName;
-import org.exoplatform.web.controller.router.SimpleRenderContext;
 import org.exoplatform.web.url.ControllerURL;
-import org.exoplatform.web.url.MimeType;
 import org.exoplatform.web.url.ResourceLocator;
 
-import java.util.EnumMap;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -41,15 +37,6 @@
 {
 
    /** . */
-   private static final Map<MimeType, String> AMP_MAP = new EnumMap<MimeType, String>(MimeType.class);
-
-   static
-   {
-      AMP_MAP.put(MimeType.XHTML, "&amp;");
-      AMP_MAP.put(MimeType.PLAIN, "&");
-   }
-
-   /** . */
    private final ControllerContext controllerContext;
 
    /** . */
@@ -62,11 +49,8 @@
    private final String siteName;
 
    /** . */
-   private StringBuilder buffer;
+   private PortalURLRenderContext renderContext;
 
-   /** . */
-   private SimpleRenderContext renderContext;
-
    public PortalURL(ControllerContext requestContext, L locator, Boolean ajax, String siteType, String siteName, String access)
    {
       super(locator, ajax);
@@ -86,11 +70,9 @@
 
    public String toString()
    {
-      //
       if (renderContext == null)
       {
-         buffer = new StringBuilder();
-         renderContext = new SimpleRenderContext(buffer);
+         renderContext = new PortalURLRenderContext(new StringBuilder());
       }
       else
       {
@@ -103,15 +85,20 @@
          throw new IllegalStateException("No resource set on portal URL");
       }
 
+      // Configure mime type
+      renderContext.setMimeType(mimeType);
+
       //
       if (ajax)
       {
-         buffer.append("javascript:");
+         renderContext.append("javascript:", false);
          if (confirm != null && confirm.length() > 0)
          {
-            buffer.append("if(confirm('").append(confirm.replaceAll("'", "\\\\'")).append("'))");
+            renderContext.append("if(confirm('", false);
+            renderContext.append(confirm.replaceAll("'", "\\\\'"), false);
+            renderContext.append("'))", false);
          }
-         buffer.append("ajaxGet('");
+         renderContext.append("ajaxGet('", false);
       }
       else
       {
@@ -142,54 +129,32 @@
          }
       }
 
-      //
+      // Render url via controller
       controllerContext.renderURL(parameters, renderContext);
 
-      //
-      MimeType mt = mimeType;
-      if (mt == null)
-      {
-         mt = MimeType.XHTML;
-      }
-      String amp = AMP_MAP.get(mt);
-
-      //
-      boolean questionMarkDone = false;
-      Map<String, String> queryParams = renderContext.getQueryParams();
-      if (queryParams.size() > 0)
-      {
-         for (Map.Entry<String, String> entry : queryParams.entrySet())
-         {
-            buffer.append(questionMarkDone ? amp : "?");
-            buffer.append(entry.getKey());
-            buffer.append('=');
-            buffer.append(entry.getValue());
-            questionMarkDone = true;
-         }
-      }
-
       // Now append generic query parameters
       for (Map.Entry<String, String[]> entry : getQueryParameters().entrySet())
       {
          for (String value : entry.getValue())
          {
-            buffer.append(questionMarkDone ? amp : "?");
-            buffer.append(entry.getKey());
-            buffer.append("=");
-            buffer.append(value);
-            questionMarkDone = true;
+            renderContext.appendQueryParameter(entry.getKey(), value);
          }
       }
 
       //
       if (ajax)
       {
-         buffer.append(questionMarkDone ? amp : "?");
-         buffer.append("ajaxRequest=true");
-         buffer.append("')");
+         renderContext.appendQueryParameter("ajaxRequest", "true");
+         renderContext.flush();
+         renderContext.append("')", false);
       }
+      else
+      {
+         renderContext.flush();
+      }
 
       //
-      return buffer.toString();
+      String s = renderContext.toString();
+      return s;
    }
 }

Added: portal/branches/navcontroller/webui/portal/src/main/java/org/exoplatform/portal/url/PortalURLRenderContext.java
===================================================================
--- portal/branches/navcontroller/webui/portal/src/main/java/org/exoplatform/portal/url/PortalURLRenderContext.java	                        (rev 0)
+++ portal/branches/navcontroller/webui/portal/src/main/java/org/exoplatform/portal/url/PortalURLRenderContext.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.exoplatform.portal.url;
+
+import org.exoplatform.commons.utils.CharEncoder;
+import org.exoplatform.commons.utils.CharsetCharEncoder;
+import org.exoplatform.web.controller.router.RenderContext;
+import org.exoplatform.web.url.MimeType;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:julien.viet at exoplatform.com">Julien Viet</a>
+ * @version $Revision$
+ */
+class PortalURLRenderContext implements RenderContext
+{
+
+   /** . */
+   private static final Map<MimeType, String> AMP_MAP = new EnumMap<MimeType, String>(MimeType.class);
+
+   static
+   {
+      AMP_MAP.put(MimeType.XHTML, "&amp;");
+      AMP_MAP.put(MimeType.PLAIN, "&");
+   }
+
+   /** . */
+   private static final char[] ALPHABET = "0123456789ABCDEF".toCharArray();
+
+   /** . */
+   private static final List<String[]> EMPTY = Collections.emptyList();
+
+   /** . */
+   private static final CharEncoder encoder = CharsetCharEncoder.getUTF8();
+
+   /** . */
+   private StringBuilder buffer;
+
+   /** . */
+   private List<String[]> queryParams;
+
+   /** . */
+   private MimeType mimeType;
+
+
+   PortalURLRenderContext(StringBuilder buffer)
+   {
+      this.buffer = buffer;
+      this.queryParams = EMPTY;
+   }
+
+   public MimeType getMimeType()
+   {
+      return mimeType;
+   }
+
+   public void setMimeType(MimeType mimeType)
+   {
+      this.mimeType = mimeType;
+   }
+
+   public void appendSlash()
+   {
+      append('/', false);
+   }
+
+   public void appendPath(char c)
+   {
+      append(c, true);
+   }
+
+   public void appendPath(String s)
+   {
+      append(s, true);
+   }
+
+   public void appendQueryParameter(String parameterName, String paramaterValue)
+   {
+      if (parameterName == null)
+      {
+         throw new NullPointerException("No null parameter name accepted");
+      }
+      if (paramaterValue == null)
+      {
+         throw new NullPointerException("No null parameter value accepted");
+      }
+
+      //
+      if (queryParams == EMPTY)
+      {
+         queryParams = new ArrayList<String[]>();
+      }
+
+      //
+      queryParams.add(new String[]{parameterName,paramaterValue});
+   }
+
+   void reset()
+   {
+      buffer.setLength(0);
+      queryParams.clear();
+   }
+
+   /**
+    * Finish to write to the buffer.
+    */
+   void flush()
+   {
+      MimeType mt = mimeType;
+      if (mt == null)
+      {
+         mt = MimeType.XHTML;
+      }
+      String amp = AMP_MAP.get(mt);
+
+      //
+      boolean questionMarkDone = false;
+      if (queryParams.size() > 0)
+      {
+         for (String[] pair : queryParams)
+         {
+            append(questionMarkDone ? amp : "?", false);
+            append(pair[0], true);
+            append('=', false);
+            append(pair[1], true);
+            questionMarkDone = true;
+         }
+      }
+   }
+
+   public void appendPath(char c, boolean escape)
+   {
+      append(c, escape);
+   }
+
+   public void appendPath(String s, boolean escape)
+   {
+      append(s, escape);
+   }
+
+   /**
+    * Append a string to the underlying buffer.
+    *
+    * @param s the string to append
+    * @param encode true if the char should be pplication/x-www-form-urlencoded encoded
+    */
+   void append(String s, boolean encode)
+   {
+      for (int i = 0;i < s.length();i++)
+      {
+         append(s.charAt(i), encode);
+      }
+   }
+
+   /**
+    * Append a char to the underlying buffer.
+    *
+    * @param c the char to append
+    * @param encode true if the char should be pplication/x-www-form-urlencoded encoded
+    */
+   void append(char c, boolean encode)
+   {
+      if (!encode || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c >= '0' && c <= '9' || c == '.' || c == '-' || c == '*' || c == '_')
+      {
+         buffer.append(c);
+      }
+      else if (c == ' ')
+      {
+         buffer.append('+');
+      }
+      else
+      {
+         byte[] bytes = encoder.encode(c);
+         buffer.append('%');
+         for (byte b : bytes)
+         {
+            buffer.append(ALPHABET[(b & 0xF0) >> 4]);
+            buffer.append(ALPHABET[b & 0xF]);
+         }
+      }
+   }
+
+   @Override
+   public String toString()
+   {
+      return buffer.toString();
+   }
+}

Modified: portal/branches/navcontroller/webui/portal/src/main/java/org/exoplatform/portal/webui/workspace/UIPortalApplication.java
===================================================================
--- portal/branches/navcontroller/webui/portal/src/main/java/org/exoplatform/portal/webui/workspace/UIPortalApplication.java	2010-11-04 09:19:18 UTC (rev 4940)
+++ portal/branches/navcontroller/webui/portal/src/main/java/org/exoplatform/portal/webui/workspace/UIPortalApplication.java	2010-11-04 11:22:09 UTC (rev 4941)
@@ -544,7 +544,7 @@
                ControllerURL<NavigationResource, NavigationLocator> nodeURL =
                   pcontext.createURL(org.exoplatform.portal.url.navigation.NavigationLocator.TYPE);
                nodeURL.setResource(new NavigationResource(getCurrentSite().getOwnerType(), getCurrentSite()
-                  .getOwner().replaceAll("/", "_"), getCurrentSite().getSelectedNode()));
+                  .getOwner(), getCurrentSite().getSelectedNode()));
                pcontext.sendRedirect(nodeURL.toString());
                return;
             }



More information about the gatein-commits mailing list