Author: julien_viet
Date: 2011-09-16 08:28:21 -0400 (Fri, 16 Sep 2011)
New Revision: 7454
Added:
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/BitStack.java
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/Regex.java
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/RegexFactory.java
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/RenderContext.java
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/performance/
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/performance/ControllerRendererDriver.java
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/performance/NullAppendable.java
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/performance/Standalone.java
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/router/JRegexFactory.java
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/router/RegexTestCase.java
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestBitStack.java
portal/trunk/component/web/controller/src/test/resources/
portal/trunk/component/web/controller/src/test/resources/org/
portal/trunk/component/web/controller/src/test/resources/org/exoplatform/
portal/trunk/component/web/controller/src/test/resources/org/exoplatform/web/
portal/trunk/component/web/controller/src/test/resources/org/exoplatform/web/controller/
portal/trunk/component/web/controller/src/test/resources/org/exoplatform/web/controller/performance/
portal/trunk/component/web/controller/src/test/resources/org/exoplatform/web/controller/performance/controller.xml
Modified:
portal/trunk/component/web/controller/pom.xml
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/ControllerContext.java
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/QualifiedName.java
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/metadata/ControllerDescriptor.java
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/PathParam.java
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/PatternBuilder.java
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/PatternRoute.java
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/RequestParam.java
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/Route.java
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/RouteEscaper.java
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/Router.java
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestBuildRoute.java
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestPatternBuilder.java
Log:
GTNPORTAL-2106 : Navigation controller renderer performance improvements
Modified: portal/trunk/component/web/controller/pom.xml
===================================================================
--- portal/trunk/component/web/controller/pom.xml 2011-09-16 11:25:56 UTC (rev 7453)
+++ portal/trunk/component/web/controller/pom.xml 2011-09-16 12:28:21 UTC (rev 7454)
@@ -31,6 +31,11 @@
<description>The GateIn web controller takes care of managing portal requests and
delegate the processing to
the appropriate subsystem.</description>
+ <properties>
+ <japex.runIterations>100000</japex.runIterations>
+ <japex.numberOfThreads>1</japex.numberOfThreads>
+ </properties>
+
<dependencies>
<dependency>
<groupId>org.exoplatform.kernel</groupId>
@@ -44,6 +49,7 @@
<groupId>org.exoplatform.portal</groupId>
<artifactId>exo.portal.component.portal</artifactId>
</dependency>
+
<!-- Used only for pretty printing, need to find a better solution than this
-->
<!--
<dependency>
@@ -67,5 +73,104 @@
<groupId>org.staxnav</groupId>
<artifactId>staxnav.core</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>net.sourceforge.jregex</groupId>
+ <artifactId>jregex</artifactId>
+ <version>1.2_01</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.japex</groupId>
+ <artifactId>japex</artifactId>
+ <version>1.2.3</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
</dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.sun.japex</groupId>
+ <artifactId>japex-maven-plugin</artifactId>
+ <version>1.2.3</version>
+ <executions>
+ <execution>
+ <id>japex</id>
+ <goals>
+ <goal>japex</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <japexConfig>
+ <testSuite name="ParsingPerformance"
xmlns="http://www.sun.com/japex/testSuite">
+ <param name="japex.namedClassPath"
value="maven.test.classpath"/>
+ <param name="japex.resultUnit" value="ms"/>
+ <param name="japex.warmupIterations"
value="10000"/>
+ <param name="japex.runIterations"
value="${japex.runIterations}"/>
+ <param name="japex.numberOfThreads"
value="${japex.numberOfThreads}"/>
+ <driver name="JavaUtilRegex">
+ <param name="japex.driverClass"
value="org.exoplatform.web.controller.performance.ControllerRendererDriver"/>
+ <param name="description" value="Controller performance
with the java.util.regex package"/>
+ <param name="regex" value="java"/>
+ </driver>
+ <driver name="JRegex">
+ <param name="japex.driverClass"
value="org.exoplatform.web.controller.performance.ControllerRendererDriver"/>
+ <param name="description" value="Controller performance
with the jregex package"/>
+ <param name="regex" value="jregex"/>
+ </driver>
+ <testCase name="classic">
+ <param name="parameters" value="{ 'gtn:handler'
: 'portal', 'gtn:sitetype' : 'portal' , 'gtn:sitename' :
'classic', 'gtn:path' : 'page' }"/>
+ </testCase>
+ <testCase name="fr/classic">
+ <param name="parameters" value="{ 'gtn:handler'
: 'portal', 'gtn:lang' : 'fr', 'gtn:sitetype' :
'portal' , 'gtn:sitename' : 'classic', 'gtn:path' :
'page' }"/>
+ </testCase>
+ <testCase name="group">
+ <param name="parameters" value="{ 'gtn:handler'
: 'portal', 'gtn:sitetype' : 'group' , 'gtn:sitename' :
'/platform/administrator', 'gtn:path' : 'page' }"/>
+ </testCase>
+ <testCase name="user">
+ <param name="parameters" value="{ 'gtn:handler'
: 'portal', 'gtn:sitetype' : 'user' , 'gtn:sitename' :
'root', 'gtn:path' : 'page' }"/>
+ </testCase>
+ </testSuite>
+ </japexConfig>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+
+ <profile>
+ <id>japex</id>
+ <properties>
+ <japex.runIterations>1000000</japex.runIterations>
+ <japex.numberOfThreads>4</japex.numberOfThreads>
+ </properties>
+ </profile>
+ <profile>
+ <!-- A never ending test used to profile the rendering execution -->
+ <id>standalone</id>
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/Standalone.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+ </profile>
+ </profiles>
</project>
Modified:
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/ControllerContext.java
===================================================================
---
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/ControllerContext.java 2011-09-16
11:25:56 UTC (rev 7453)
+++
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/ControllerContext.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -20,6 +20,7 @@
package org.exoplatform.web;
import org.exoplatform.web.controller.QualifiedName;
+import org.exoplatform.web.controller.router.RenderContext;
import org.exoplatform.web.controller.router.Router;
import org.exoplatform.web.controller.router.URIWriter;
@@ -53,6 +54,9 @@
/** . */
private final String contextName;
+ /** . */
+ private final RenderContext renderContext;
+
public ControllerContext(
WebAppController controller,
Router router,
@@ -66,6 +70,7 @@
this.parameters = parameters;
this.contextName = request.getContextPath().substring(1);
this.router = router;
+ this.renderContext = new RenderContext();
}
public WebAppController getController()
@@ -88,14 +93,11 @@
return parameters.get(parameter);
}
- public void renderURL(Map<QualifiedName, String> parameters, URIWriter
renderContext) throws IOException
+ public void renderURL(Map<QualifiedName, String> parameters, URIWriter
uriWriter) throws IOException
{
- renderContext.append('/');
-
- //
- renderContext.appendSegment(contextName);
-
- //
- router.render(parameters, renderContext);
+ renderContext.reset(parameters);
+ uriWriter.append('/');
+ uriWriter.appendSegment(contextName);
+ router.render(renderContext, uriWriter);
}
}
Modified:
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/QualifiedName.java
===================================================================
---
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/QualifiedName.java 2011-09-16
11:25:56 UTC (rev 7453)
+++
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/QualifiedName.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -92,6 +92,9 @@
/** The name. */
private final String name;
+ /** The cached hash code. */
+ private int hashCode;
+
private QualifiedName(String name) throws NullPointerException,
IllegalArgumentException
{
this("", name);
@@ -119,6 +122,7 @@
//
this.qualifier = qualifier;
this.name = name;
+ this.hashCode = qualifier.hashCode() ^ name.hashCode();
}
/**
@@ -161,7 +165,7 @@
@Override
public int hashCode()
{
- return qualifier.hashCode() ^ name.hashCode();
+ return hashCode;
}
@Override
Modified:
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/metadata/ControllerDescriptor.java
===================================================================
---
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/metadata/ControllerDescriptor.java 2011-09-16
11:25:56 UTC (rev 7453)
+++
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/metadata/ControllerDescriptor.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -19,6 +19,7 @@
package org.exoplatform.web.controller.metadata;
+import org.exoplatform.web.controller.router.RegexFactory;
import org.exoplatform.web.controller.router.RouterConfigException;
import org.exoplatform.web.controller.router.Router;
@@ -94,4 +95,9 @@
{
return new Router(this);
}
+
+ public Router build(RegexFactory regexFactory) throws RouterConfigException
+ {
+ return new Router(this, regexFactory);
+ }
}
Added:
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/BitStack.java
===================================================================
---
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/BitStack.java
(rev 0)
+++
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/BitStack.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2011 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;
+
+/**
+ * A bit stack optimized for speed.
+ *
+ * @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a>
+ */
+class BitStack
+{
+
+ private static class Frame
+ {
+
+ /** . */
+ private Frame previous;
+
+ /** . */
+ private Frame next;
+
+ /** . */
+ private long bits;
+
+ /** . */
+ private int cardinality;
+
+ private Frame()
+ {
+ this(0, 0);
+ }
+
+ private Frame(long bits, int cardinality)
+ {
+ this.previous = null;
+ this.next = null;
+ this.bits = bits;
+ this.cardinality = cardinality;
+ }
+ }
+
+ /** . */
+ private Frame head;
+
+ /** . */
+ private Frame current;
+
+ /** . */
+ private int depth;
+
+ /** . */
+ private int size;
+
+ BitStack()
+ {
+ this.current = null;
+ this.depth = 0;
+ this.size = 0;
+ }
+
+ void init(int size)
+ {
+ if (depth > 0)
+ {
+ throw new IllegalStateException();
+ }
+ if (size < 0)
+ {
+ throw new IllegalArgumentException();
+ }
+ this.size = size;
+ }
+
+ void reset()
+ {
+ if (depth > 0)
+ {
+ throw new IllegalStateException();
+ }
+ this.size = 0;
+ }
+
+ void push()
+ {
+ if (current == null)
+ {
+ if (head == null)
+ {
+ head = new Frame();
+ }
+ current = head;
+ depth++;
+ }
+ else
+ {
+ if (current.next == null)
+ {
+ Frame next = new Frame(current.bits, current.cardinality);
+ current.next = next;
+ next.previous = current;
+ current = next;
+ depth++;
+ }
+ else
+ {
+ Frame next = current.next;
+ next.bits = current.bits;
+ next.cardinality = current.cardinality;
+ current = next;
+ depth++;
+ }
+ }
+ }
+
+ void pop()
+ {
+ if (depth == 0)
+ {
+ throw new IllegalStateException();
+ }
+ current = current.previous;
+ depth--;
+ }
+
+ int getDepth()
+ {
+ return depth;
+ }
+
+ void set(int index)
+ {
+ if (index > 63)
+ {
+ throw new IllegalArgumentException("Index " + index + " > 63
not allowed");
+ }
+ if (depth < 1)
+ {
+ throw new IllegalStateException();
+ }
+ if (index > size)
+ {
+ throw new IllegalArgumentException();
+ }
+ long pre = current.bits;
+ current.bits |= 1L << index;
+ if (current.bits != pre)
+ {
+ current.cardinality++;
+ }
+ }
+
+ boolean get(int index)
+ {
+ if (index > 63)
+ {
+ throw new IllegalArgumentException("Index " + index + " > 63
not allowed");
+ }
+ if (depth < 1)
+ {
+ throw new IllegalStateException();
+ }
+ if (index > size)
+ {
+ throw new IllegalArgumentException();
+ }
+ return (current.bits & (1L << index)) != 0;
+ }
+
+ boolean isEmpty()
+ {
+ if (depth < 1)
+ {
+ throw new IllegalStateException();
+ }
+ return current.cardinality == size;
+ }
+}
Modified:
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/PathParam.java
===================================================================
---
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/PathParam.java 2011-09-16
11:25:56 UTC (rev 7453)
+++
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/PathParam.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -27,7 +27,6 @@
import org.exoplatform.web.controller.regexp.SyntaxException;
import java.io.IOException;
-import java.util.regex.Pattern;
/**
* @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a>
@@ -36,12 +35,12 @@
class PathParam extends Param
{
- static PathParam create(QualifiedName name)
+ static PathParam create(QualifiedName name, Router router)
{
- return create(new PathParamDescriptor(name));
+ return create(new PathParamDescriptor(name), router);
}
- static PathParam create(PathParamDescriptor descriptor)
+ static PathParam create(PathParamDescriptor descriptor, Router router)
{
if (descriptor == null)
{
@@ -111,7 +110,7 @@
descriptor.getQualifiedName(),
encodingMode,
routingRegex.toString(),
- renderingRegex.toString());
+ router.compile(renderingRegex.toString()));
}
/** . */
@@ -121,13 +120,13 @@
final String routingRegex;
/** . */
- final Pattern renderingPattern;
+ final Regex renderingPattern;
PathParam(
QualifiedName name,
EncodingMode encodingMode,
String routingRegex,
- String renderingRegex)
+ Regex renderingRegex)
{
super(name);
@@ -140,7 +139,7 @@
//
this.encodingMode = encodingMode;
this.routingRegex = routingRegex;
- this.renderingPattern = Pattern.compile(renderingRegex);
+ this.renderingPattern = renderingRegex;
}
@Override
Modified:
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/PatternBuilder.java
===================================================================
---
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/PatternBuilder.java 2011-09-16
11:25:56 UTC (rev 7453)
+++
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/PatternBuilder.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -21,8 +21,6 @@
import org.exoplatform.web.controller.regexp.Literal;
-import java.util.regex.Pattern;
-
/**
* @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a>
* @version $Revision$
@@ -33,6 +31,11 @@
/** . */
private final StringBuilder buffer = new StringBuilder();
+ /** . */
+ PatternBuilder()
+ {
+ }
+
public PatternBuilder expr(CharSequence s)
{
if (s == null)
@@ -93,8 +96,8 @@
return literal(Character.toString(c));
}
- public Pattern build()
+ public String build()
{
- return Pattern.compile(buffer.toString());
+ return buffer.toString();
}
}
Modified:
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/PatternRoute.java
===================================================================
---
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/PatternRoute.java 2011-09-16
11:25:56 UTC (rev 7453)
+++
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/PatternRoute.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -20,7 +20,6 @@
package org.exoplatform.web.controller.router;
import java.util.List;
-import java.util.regex.Pattern;
/**
* @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a>
@@ -30,7 +29,7 @@
{
/** . */
- final Pattern pattern;
+ final Regex pattern;
/** . */
final PathParam[] params;
@@ -43,7 +42,7 @@
PatternRoute(
Router router,
- Pattern pattern,
+ Regex pattern,
List<PathParam> params,
List<String> chunks)
{
Added:
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/Regex.java
===================================================================
---
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/Regex.java
(rev 0)
+++
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/Regex.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2011 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;
+
+/** @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a> */
+public abstract class Regex
+{
+
+ /** . */
+ public static final Match[] NO_MATCHES = new Match[0];
+
+ /** . */
+ public static final Match NULL_MATCH = new Match(-1, -1, null);
+
+ /** An index set by the router to do matcher reuse easily, the regex implementation
should not care about it. */
+ int index = -1;
+
+ public abstract String getPattern();
+
+ public abstract Matcher matcher();
+
+ public abstract static class Matcher
+ {
+
+ public abstract boolean matches(CharSequence s);
+
+ public abstract Match[] find(CharSequence s);
+
+ }
+
+ public static class Match
+ {
+
+ /** . */
+ private final int start;
+
+ /** . */
+ private final int end;
+
+ /** . */
+ private final String value;
+
+ protected Match(int start, int end, String value)
+ {
+ this.start = start;
+ this.end = end;
+ this.value = value;
+ }
+
+ public int getStart()
+ {
+ return start;
+ }
+
+ public int getEnd()
+ {
+ return end;
+ }
+
+ public String getValue()
+ {
+ return value;
+ }
+ }
+
+ public static class Java extends Regex
+ {
+
+ /** . */
+ private final java.util.regex.Pattern pattern;
+
+ public Java(String regex)
+ {
+ this.pattern = java.util.regex.Pattern.compile(regex);
+ }
+
+ public Matcher matcher()
+ {
+ return new Matcher()
+ {
+
+ /** . */
+ private java.util.regex.Matcher impl;
+
+ private java.util.regex.Matcher get(CharSequence s)
+ {
+ if (impl == null)
+ {
+ impl = pattern.matcher(s);
+ }
+ else
+ {
+ impl.reset(s);
+ }
+ return impl;
+ }
+
+ @Override
+ public boolean matches(CharSequence s)
+ {
+ return get(s).matches();
+ }
+
+ @Override
+ public Match[] find(CharSequence s)
+ {
+ java.util.regex.Matcher matcher = get(s);
+ if (matcher.find())
+ {
+ Match[] matches = new Match[1 + matcher.groupCount()];
+ for (int i = 0;i <= matcher.groupCount();i++)
+ {
+ if (matcher.group() != null)
+ {
+ matches[i] = new Match(matcher.start(i), matcher.end(i),
matcher.group(i));
+ }
+ else
+ {
+ matches[i] = NULL_MATCH;
+ }
+ }
+ return matches;
+ }
+ else
+ {
+ return NO_MATCHES;
+ }
+ }
+ };
+ }
+
+ @Override
+ public String getPattern()
+ {
+ return pattern.pattern();
+ }
+ }
+}
Added:
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/RegexFactory.java
===================================================================
---
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/RegexFactory.java
(rev 0)
+++
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/RegexFactory.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011 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;
+
+/** @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a> */
+public abstract class RegexFactory implements Cloneable
+{
+
+ public static RegexFactory JAVA = new RegexFactory()
+ {
+ @Override
+ public Regex compile(String pattern)
+ {
+ return new Regex.Java(pattern);
+ }
+
+ @Override
+ public String getName()
+ {
+ return "java";
+ }
+ };
+
+ protected RegexFactory()
+ {
+ }
+
+ public abstract Regex compile(String pattern);
+
+ public abstract String getName();
+}
Added:
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/RenderContext.java
===================================================================
---
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/RenderContext.java
(rev 0)
+++
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/RenderContext.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2011 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 org.exoplatform.web.controller.QualifiedName;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The render context used to compute the rendering of a parameter map.
+ *
+ * @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a>
+ */
+public class RenderContext
+{
+
+ class Parameter
+ {
+
+ /** . */
+ private String value;
+
+ /** . */
+ private final int index;
+
+ private Parameter(String value, int index)
+ {
+ this.value = value;
+ this.index = index;
+ }
+
+ public String getValue()
+ {
+ return value;
+ }
+
+ public void remove()
+ {
+ if (stack.getDepth() < 1)
+ {
+ throw new IllegalStateException();
+ }
+ stack.set(index);
+ }
+ }
+
+ /** . */
+ private final Map<QualifiedName, Parameter> parameters;
+
+ /** . */
+ private BitStack stack = new BitStack();
+
+ /** . */
+ Regex.Matcher[] matchers;
+
+ public RenderContext(Map<QualifiedName, String> map)
+ {
+ this();
+
+ //
+ reset(map);
+ }
+
+ public RenderContext()
+ {
+ this.parameters = new HashMap<QualifiedName, Parameter>();
+ this.stack = new BitStack();
+ this.matchers = null;
+ }
+
+ Regex.Matcher matcher(Regex regex)
+ {
+ Regex.Matcher matcher = matchers[regex.index];
+ if (matcher == null)
+ {
+ matcher = matchers[regex.index] = regex.matcher();
+ }
+ return matcher;
+ }
+
+ /**
+ * Reuse the context with new parameters.
+ *
+ * @param map the map
+ */
+ public void reset(Map<QualifiedName, String> map)
+ {
+ this.parameters.clear();
+ this.stack.reset();
+
+ //
+ for (Map.Entry<QualifiedName, String> entry : map.entrySet())
+ {
+ addParameter(entry.getKey(), entry.getValue());
+ }
+ }
+
+ void addParameter(QualifiedName name, String value)
+ {
+ if (stack.getDepth() > 0)
+ {
+ throw new IllegalStateException();
+ }
+ if (name == null)
+ {
+ throw new NullPointerException();
+ }
+ if (value == null)
+ {
+ throw new NullPointerException();
+ }
+ Parameter parameter = parameters.get(name);
+ if (parameter == null)
+ {
+ parameter = new Parameter(value, parameters.size());
+ parameters.put(name, parameter);
+ }
+ else
+ {
+ parameter.value = value;
+ }
+ }
+
+ Parameter getParameter(QualifiedName name)
+ {
+ Parameter entry = parameters.get(name);
+ if (stack.getDepth() == 0 || (entry != null && !stack.get(entry.index)))
+ {
+ return entry;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ String getParameterValue(QualifiedName name)
+ {
+ Parameter entry = getParameter(name);
+ return entry != null ? entry.value : null;
+ }
+
+ boolean isEmpty()
+ {
+ return stack.getDepth() ==0 || stack.isEmpty();
+ }
+
+ void enter()
+ {
+ if (stack.getDepth() == 0)
+ {
+ stack.init(parameters.size());
+ }
+ stack.push();
+ }
+
+ void leave()
+ {
+ stack.pop();
+ }
+}
Modified:
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/RequestParam.java
===================================================================
---
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/RequestParam.java 2011-09-16
11:25:56 UTC (rev 7453)
+++
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/RequestParam.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -22,8 +22,6 @@
import org.exoplatform.web.controller.QualifiedName;
import org.exoplatform.web.controller.metadata.RequestParamDescriptor;
-import java.util.regex.Pattern;
-
/**
* @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a>
* @version $Revision$
@@ -31,7 +29,7 @@
class RequestParam extends Param
{
- static RequestParam create(RequestParamDescriptor descriptor)
+ static RequestParam create(RequestParamDescriptor descriptor, Router router)
{
if (descriptor == null)
{
@@ -39,7 +37,7 @@
}
//
- Pattern matchValue = null;
+ Regex matchValue = null;
if (descriptor.getValue() != null)
{
PatternBuilder matchValueBuilder = new PatternBuilder();
@@ -53,7 +51,7 @@
matchValueBuilder.literal(descriptor.getValue());
}
matchValueBuilder.expr("$");
- matchValue = matchValueBuilder.build();
+ matchValue = router.compile(matchValueBuilder.build());
}
//
@@ -72,7 +70,7 @@
final String matchName;
/** . */
- final Pattern matchPattern;
+ final Regex matchPattern;
/** . */
final ControlMode controlMode;
@@ -80,7 +78,7 @@
/** . */
final ValueMapping valueMapping;
- RequestParam(QualifiedName name, String matchName, Pattern matchPattern, ControlMode
controlMode, ValueMapping valueMapping)
+ RequestParam(QualifiedName name, String matchName, Regex matchPattern, ControlMode
controlMode, ValueMapping valueMapping)
{
super(name);
@@ -108,6 +106,6 @@
boolean matchValue(String value)
{
- return matchPattern == null || matchPattern.matcher(value).matches();
+ return matchPattern == null || matchPattern.matcher().matches(value);
}
}
Modified:
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/Route.java
===================================================================
---
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/Route.java 2011-09-16
11:25:56 UTC (rev 7453)
+++
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/Route.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -42,7 +42,6 @@
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
-import java.util.regex.Matcher;
/**
* The implementation of the routing algorithm.
@@ -88,7 +87,7 @@
}
//
- for (RouteParam routeParam : routeParams.values())
+ for (RouteParam routeParam : routeParamArray)
{
writer.writeStartElement("route-param");
writer.writeAttribute("qname", routeParam.name.getValue());
@@ -97,14 +96,14 @@
}
//
- for (RequestParam requestParam : requestParams.values())
+ for (RequestParam requestParam : requestParamArray)
{
writer.writeStartElement("request-param");
writer.writeAttribute("qname", requestParam.name.getValue());
writer.writeAttribute("name", requestParam.matchName);
if (requestParam.matchPattern != null)
{
- writer.writeAttribute("value",
requestParam.matchPattern.pattern());
+ writer.writeAttribute("value",
requestParam.matchPattern.getPattern());
}
writer.writeEndElement();
}
@@ -155,6 +154,12 @@
private static final Route[] EMPTY_ROUTE_ARRAY = new Route[0];
/** . */
+ private static final RouteParam[] EMPTY_ROUTE_PARAM_ARRAY = new RouteParam[0];
+
+ /** . */
+ private static final RequestParam[] EMPTY_REQUEST_PARAM_ARRAY = new RequestParam[0];
+
+ /** . */
private final Router router;
/** . */
@@ -167,19 +172,27 @@
private Route[] children;
/** . */
- private final Map<QualifiedName, RouteParam> routeParams;
+ private Map<QualifiedName, RouteParam> routeParamMap;
/** . */
- private final Map<String, RequestParam> requestParams;
+ private RouteParam[] routeParamArray;
+ /** . */
+ private Map<String, RequestParam> requestParamMap;
+
+ /** . */
+ private RequestParam[] requestParamArray;
+
Route(Router router)
{
this.router = router;
this.parent = null;
this.terminal = true;
this.children = EMPTY_ROUTE_ARRAY;
- this.routeParams = new HashMap<QualifiedName, RouteParam>();
- this.requestParams = new HashMap<String, RequestParam>();
+ this.routeParamMap = Collections.emptyMap();
+ this.routeParamArray = EMPTY_ROUTE_PARAM_ARRAY;
+ this.requestParamMap = Collections.emptyMap();
+ this.requestParamArray = EMPTY_REQUEST_PARAM_ARRAY;
}
final boolean isTerminal()
@@ -191,27 +204,27 @@
* Ok, so this is not the fastest way to do it, but for now it's OK, it's what
is needed, we'll find
* a way to optimize it later with some precompilation.
*/
- final void render(Map<QualifiedName, String> blah, URIWriter writer) throws
IOException
+ final void render(RenderContext context, URIWriter writer) throws IOException
{
- Route r = find(blah);
+ Route r = find(context);
// We found a route we need to render it now
if (r != null)
{
// Append path first
- r.renderPath(blah, writer, false);
+ r.renderPath(context, writer, false);
// Append query parameters after
- r.renderQueryString(blah, writer);
+ r.renderQueryString(context, writer);
}
}
- private boolean renderPath(Map<QualifiedName, String> blah, URIWriter writer,
boolean hasChildren) throws IOException
+ private boolean renderPath(RenderContext context, URIWriter writer, boolean
hasChildren) throws IOException
{
boolean endWithSlash;
if (parent != null)
{
- endWithSlash = parent.renderPath(blah, writer, true);
+ endWithSlash = parent.renderPath(context, writer, true);
}
else
{
@@ -251,7 +264,7 @@
//
PathParam def = pr.params[i];
- String value = blah.get(def.name);
+ String value = context.getParameterValue(def.name);
count += value.length();
// Write value
@@ -303,57 +316,58 @@
return endWithSlash;
}
- private void renderQueryString(Map<QualifiedName, String> blah, URIWriter
writer) throws IOException
+ private void renderQueryString(RenderContext context, URIWriter writer) throws
IOException
{
if (parent != null)
{
- parent.renderQueryString(blah, writer);
+ parent.renderQueryString(context, writer);
}
//
- if (requestParams.size() > 0)
+ for (RequestParam requestParamDef : requestParamArray)
{
- for (RequestParam requestParamDef : requestParams.values())
+ String s = context.getParameterValue(requestParamDef.name);
+ switch (requestParamDef.valueMapping)
{
- String s = blah.get(requestParamDef.name);
- switch (requestParamDef.valueMapping)
- {
- case CANONICAL:
- break;
- case NEVER_EMPTY:
- if (s != null && s.length() == 0)
- {
- s = null;
- }
- break;
- case NEVER_NULL:
- if (s == null)
- {
- s = "";
- }
- break;
- }
- if (s != null)
- {
- writer.appendQueryParameter(requestParamDef.matchName, s);
- }
+ case CANONICAL:
+ break;
+ case NEVER_EMPTY:
+ if (s != null && s.length() == 0)
+ {
+ s = null;
+ }
+ break;
+ case NEVER_NULL:
+ if (s == null)
+ {
+ s = "";
+ }
+ break;
}
+ if (s != null)
+ {
+ writer.appendQueryParameter(requestParamDef.matchName, s);
+ }
}
}
- final Route find(Map<QualifiedName, String> blah)
+ final Route find(RenderContext context)
{
+ context.enter();
+ Route route = _find(context);
+ context.leave();
+ return route;
+ }
- // Remove what is matched
- Map<QualifiedName, String> abc = new HashMap<QualifiedName,
String>(blah);
-
+ private Route _find(RenderContext context)
+ {
// Match first the static parameteters
- for (RouteParam param : routeParams.values())
+ for (RouteParam param : routeParamArray)
{
- String value = blah.get(param.name);
- if (param.value.equals(value))
+ RenderContext.Parameter entry = context.getParameter(param.name);
+ if (entry != null && param.value.equals(entry.getValue()))
{
- abc.remove(param.name);
+ entry.remove();
}
else
{
@@ -362,36 +376,33 @@
}
// Match any request parameter
- if (requestParams.size() > 0)
+ for (RequestParam requestParamDef : requestParamArray)
{
- for (RequestParam requestParamDef : requestParams.values())
+ RenderContext.Parameter entry = context.getParameter(requestParamDef.name);
+ boolean matched = false;
+ if (entry != null)
{
- String a = blah.get(requestParamDef.name);
- boolean matched = false;
- if (a != null)
+ if (requestParamDef.matchPattern == null ||
context.matcher(requestParamDef.matchPattern).matches(entry.getValue()))
{
- if (requestParamDef.matchValue(a))
- {
- matched = true;
- }
+ matched = true;
}
- if (matched)
+ }
+ if (matched)
+ {
+ entry.remove();
+ }
+ else
+ {
+ switch (requestParamDef.controlMode)
{
- abc.remove(requestParamDef.name);
+ case OPTIONAL:
+ // Do nothing
+ break;
+ case REQUIRED:
+ return null;
+ default:
+ throw new AssertionError();
}
- else
- {
- switch (requestParamDef.controlMode)
- {
- case OPTIONAL:
- // Do nothing
- break;
- case REQUIRED:
- return null;
- default:
- throw new AssertionError();
- }
- }
}
}
@@ -402,17 +413,17 @@
for (int i = 0;i < prt.params.length;i++)
{
PathParam param = prt.params[i];
- String s = blah.get(param.name);
+ RenderContext.Parameter s = context.getParameter(param.name);
boolean matched = false;
if (s != null)
{
switch (param.encodingMode)
{
case FORM:
- matched = param.renderingPattern.matcher(s).matches();
+ matched =
context.matcher(param.renderingPattern).matches(s.getValue());
break;
case PRESERVE_PATH:
- matched = param.renderingPattern.matcher(s).matches();
+ matched =
context.matcher(param.renderingPattern).matches(s.getValue());
break;
default:
throw new AssertionError();
@@ -420,7 +431,7 @@
}
if (matched)
{
- abc.remove(param.name);
+ s.remove();
}
else
{
@@ -430,7 +441,7 @@
}
//
- if (abc.isEmpty() && terminal)
+ if (context.isEmpty() && terminal)
{
return this;
}
@@ -438,7 +449,7 @@
//
for (Route route : children)
{
- Route a = route.find(abc);
+ Route a = route.find(context);
if (a != null)
{
return a;
@@ -526,16 +537,13 @@
}
parameters.putAll(frame.matches);
}
- if (frame.route.routeParams.size() > 0)
+ for (RouteParam param : frame.route.routeParamArray)
{
if (parameters == null)
{
parameters = new HashMap<QualifiedName, String>();
}
- for (RouteParam param : frame.route.routeParams.values())
- {
- parameters.put(param.name, param.value);
- }
+ parameters.put(param.name, param.value);
}
}
return parameters != null ? parameters : Collections.<QualifiedName,
String>emptyMap();
@@ -622,58 +630,55 @@
boolean matched = true;
// We enter a frame
- if (current.route.requestParams.size() > 0)
+ for (RequestParam requestParamDef : current.route.requestParamArray)
{
- for (RequestParam requestParamDef : current.route.requestParams.values())
+ String value = null;
+ String[] values = requestParams.get(requestParamDef.matchName);
+ if (values != null && values.length > 0 && values[0] !=
null)
{
- String value = null;
- String[] values = requestParams.get(requestParamDef.matchName);
- if (values != null && values.length > 0 && values[0]
!= null)
+ value = values[0];
+ }
+ if (value == null)
+ {
+ switch (requestParamDef.controlMode)
{
- value = values[0];
+ case OPTIONAL:
+ // Do nothing
+ break;
+ case REQUIRED:
+ matched = false;
+ break;
}
- if (value == null)
- {
- switch (requestParamDef.controlMode)
+ }
+ else if (!requestParamDef.matchValue(value))
+ {
+ matched = false;
+ break;
+ }
+ switch (requestParamDef.valueMapping)
+ {
+ case CANONICAL:
+ break;
+ case NEVER_EMPTY:
+ if (value != null && value.length() == 0)
{
- case OPTIONAL:
- // Do nothing
- break;
- case REQUIRED:
- matched = false;
- break;
+ value = null;
}
- }
- else if (!requestParamDef.matchValue(value))
- {
- matched = false;
break;
- }
- switch (requestParamDef.valueMapping)
- {
- case CANONICAL:
- break;
- case NEVER_EMPTY:
- if (value != null && value.length() == 0)
- {
- value = null;
- }
- break;
- case NEVER_NULL:
- if (value == null)
- {
- value = "";
- }
- break;
- }
- if (value != null)
- {
- if (current.matches == null)
+ case NEVER_NULL:
+ if (value == null)
{
- current.matches = new HashMap<QualifiedName, String>();
+ value = "";
}
- current.matches.put(requestParamDef.name, value);
+ break;
+ }
+ if (value != null)
+ {
+ if (current.matches == null)
+ {
+ current.matches = new HashMap<QualifiedName, String>();
}
+ current.matches.put(requestParamDef.name, value);
}
}
@@ -774,13 +779,13 @@
PatternRoute patternRoute = (PatternRoute)child;
//
- Matcher matcher =
patternRoute.pattern.matcher(current.path.getValue());
+ Regex.Match[] matches =
patternRoute.pattern.matcher().find(current.path.getValue());
// We match
- if (matcher.find())
+ if (matches.length > 0)
{
// Build next controller context
- int nextPos = matcher.end();
+ int nextPos = matches[0].getEnd();
Path nextPath;
if (current.path.length() == nextPos)
{
@@ -802,22 +807,19 @@
// JULIEN : this can be done lazily
// Append parameters
- int group = 1;
for (int i = 0;i < patternRoute.params.length;i++)
{
PathParam param = patternRoute.params[i];
+ Regex.Match match = matches[1 + i];
//
- int end = matcher.end(group);
-
- //
- if (end != -1)
+ if (match.getEnd() != -1)
{
String value;
if (param.encodingMode == EncodingMode.FORM)
{
StringBuilder sb = new StringBuilder();
- for (int from = matcher.start(group);from < end;from++)
+ for (int from = match.getStart();from <
match.getEnd();from++)
{
char c = current.path.charAt(from);
if (c == child.router.separatorEscape &&
current.path.getRawLength(from) == 1)
@@ -830,7 +832,7 @@
}
else
{
- value = matcher.group(group);
+ value = match.getValue();
}
if (next.matches == null)
{
@@ -842,9 +844,6 @@
{
// We have an optional match
}
-
- //
- group++;
}
}
else
@@ -1034,7 +1033,7 @@
//
for (RequestParamDescriptor requestParamDesc : descriptor.getRequestParams())
{
- route.add(RequestParam.create(requestParamDesc));
+ route.add(RequestParam.create(requestParamDesc, router));
}
//
@@ -1054,7 +1053,12 @@
{
throw new MalformedRouteException("Duplicate parameter " +
param.name);
}
- routeParams.put(param.name, param);
+ if (routeParamArray.length == 0)
+ {
+ routeParamMap = new HashMap<QualifiedName, RouteParam>();
+ }
+ routeParamMap.put(param.name, param);
+ routeParamArray = Tools.appendTo(routeParamArray, param);
return this;
}
@@ -1065,7 +1069,12 @@
{
throw new MalformedRouteException("Duplicate parameter " +
param.name);
}
- requestParams.put(param.matchName, param);
+ if (requestParamArray.length == 0)
+ {
+ requestParamMap = new HashMap<String, RequestParam>();
+ }
+ requestParamMap.put(param.matchName, param);
+ requestParamArray = Tools.appendTo(requestParamArray, param);
return this;
}
@@ -1151,11 +1160,11 @@
PathParam param;
if (parameterDescriptor != null)
{
- param = PathParam.create(parameterDescriptor);
+ param = PathParam.create(parameterDescriptor, router);
}
else
{
- param = PathParam.create(parameterQName);
+ param = PathParam.create(parameterQName, router);
}
// Append routing regex to the route regex
@@ -1177,7 +1186,7 @@
//
chunks.add(path.substring(previous, pos));
- PatternRoute route = new PatternRoute(router, builder.build(),
parameterPatterns, chunks);
+ PatternRoute route = new PatternRoute(router,
router.compile(builder.build()), parameterPatterns, chunks);
// Wire
add(route);
@@ -1204,31 +1213,30 @@
private Param getParam(QualifiedName name)
{
- if (routeParams.containsKey(name))
+ Param param = routeParamMap.get(name);
+ if (param == null)
{
- return routeParams.get(name);
- }
- else
- {
- for (RequestParam param : requestParams.values())
+ for (RequestParam requestParam : requestParamArray)
{
- if (param.name.equals(name))
+ if (requestParam.name.equals(name))
{
- return param;
+ param = requestParam;
+ break;
}
}
- }
- if (this instanceof PatternRoute)
- {
- for (PathParam param : ((PatternRoute)this).params)
+ if (param == null && this instanceof PatternRoute)
{
- if (param.name.equals(name))
+ for (PathParam pathParam : ((PatternRoute)this).params)
{
- return param;
+ if (pathParam.name.equals(name))
+ {
+ param = pathParam;
+ break;
+ }
}
}
}
- return null;
+ return param;
}
private Param findParam(QualifiedName name)
@@ -1243,14 +1251,11 @@
private void findParams(List<Param> params)
{
- for (RouteParam param : routeParams.values())
+ Collections.addAll(params, routeParamArray);
+ for (RequestParam param : requestParamArray)
{
params.add(param);
}
- for (RequestParam param : requestParams.values())
- {
- params.add(param);
- }
if (this instanceof PatternRoute)
{
Collections.addAll(params, ((PatternRoute)this).params);
Modified:
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/RouteEscaper.java
===================================================================
---
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/RouteEscaper.java 2011-09-16
11:25:56 UTC (rev 7453)
+++
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/RouteEscaper.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -19,6 +19,7 @@
package org.exoplatform.web.controller.router;
+import org.exoplatform.web.controller.regexp.GroupType;
import org.exoplatform.web.controller.regexp.RENode;
/**
@@ -89,12 +90,10 @@
else if (expr instanceof RENode.Group)
{
RENode.Group group = (RENode.Group)expr;
-/*
if (group.getType() == GroupType.CAPTURING_GROUP)
{
group.setType(GroupType.NON_CAPTURING_GROUP);
}
-*/
visit(group.getDisjunction());
}
else if (expr instanceof RENode.Any)
@@ -108,9 +107,9 @@
RENode.CharacterClass characterClass = (RENode.CharacterClass)expr;
RENode.CharacterClassExpr ccExpr = characterClass.getExpr();
ccExpr = ccExpr.replace(src, dst);
- RENode.CharacterClassExpr.And ccRepl = new RENode.CharacterClassExpr.And(null,
new RENode.CharacterClassExpr.Not(new RENode.CharacterClassExpr.Char('/')));
- ccExpr.replaceBy(ccRepl);
- ccRepl.setLeft(ccExpr);
+// RENode.CharacterClassExpr.And ccRepl = new RENode.CharacterClassExpr.And(null,
new RENode.CharacterClassExpr.Not(new RENode.CharacterClassExpr.Char('/')));
+// ccExpr.replaceBy(ccRepl);
+// ccRepl.setLeft(ccExpr);
}
}
}
Modified:
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/Router.java
===================================================================
---
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/Router.java 2011-09-16
11:25:56 UTC (rev 7453)
+++
portal/trunk/component/web/controller/src/main/java/org/exoplatform/web/controller/router/Router.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -24,12 +24,16 @@
import org.exoplatform.web.controller.metadata.ControllerDescriptor;
import org.exoplatform.web.url.MimeType;
import org.gatein.common.io.UndeclaredIOException;
+import org.gatein.common.util.Tools;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* The router takes care of mapping a request to a a map.
@@ -62,6 +66,9 @@
escapeSet = bs;
}
+ /** . */
+ private final RegexFactory regexFactory;
+
/** The root route. */
final Route root;
@@ -74,8 +81,16 @@
/** . */
final char separatorEscapeNible2;
+ /** . */
+ private Regex[] regexes;
+
public Router(ControllerDescriptor metaData) throws RouterConfigException
{
+ this(metaData, RegexFactory.JAVA);
+ }
+
+ public Router(ControllerDescriptor metaData, RegexFactory regexFactory) throws
RouterConfigException
+ {
char separtorEscape = metaData.getSeparatorEscape();
//
@@ -91,33 +106,59 @@
separatorEscapeNible2 = s.charAt(1);
//
+ this.regexFactory = regexFactory;
this.root = new Route(this);
this.separatorEscape = separtorEscape;
+ this.regexes = new Regex[0];
//
for (RouteDescriptor routeMetaData : metaData.getRoutes())
{
- addRoute(routeMetaData);
+ root.append(routeMetaData);
}
}
- public void addRoute(RouteDescriptor routeMetaData) throws RouterConfigException
+ Regex compile(String pattern)
{
- root.append(routeMetaData);
+ for (Regex regex : regexes)
+ {
+ if (regex.getPattern().equals(pattern))
+ {
+ return regex;
+ }
+ }
+ Regex regex = regexFactory.compile(pattern);
+ regex.index = regexes.length;
+ regexes = Tools.appendTo(regexes, regex);
+ return regex;
}
public void render(Map<QualifiedName, String> parameters, URIWriter writer)
throws IOException
{
- root.render(parameters, writer);
+ render(new RenderContext(parameters), writer);
}
public String render(Map<QualifiedName, String> parameters)
{
+ return render(new RenderContext(parameters));
+ }
+
+ public void render(RenderContext context, URIWriter writer) throws IOException
+ {
+ if (context.matchers == null)
+ {
+ context.matchers = new Regex.Matcher[regexes.length];
+ }
+ root.render(context, writer);
+ }
+
+ public String render(RenderContext context)
+ {
try
{
StringBuilder sb = new StringBuilder();
URIWriter renderContext = new URIWriter(sb, MimeType.PLAIN);
- render(parameters, renderContext);
+ render(context, renderContext);
return sb.toString();
}
catch (IOException e)
Added:
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/performance/ControllerRendererDriver.java
===================================================================
---
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/performance/ControllerRendererDriver.java
(rev 0)
+++
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/performance/ControllerRendererDriver.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -0,0 +1,137 @@
+/**
+ * Copyright (C) 2009 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.performance;
+
+import com.sun.japex.JapexDriverBase;
+import com.sun.japex.TestCase;
+import org.exoplatform.web.controller.QualifiedName;
+import org.exoplatform.web.controller.metadata.ControllerDescriptor;
+import org.exoplatform.web.controller.metadata.DescriptorBuilder;
+import org.exoplatform.web.controller.router.JRegexFactory;
+import org.exoplatform.web.controller.router.RegexFactory;
+import org.exoplatform.web.controller.router.RenderContext;
+import org.exoplatform.web.controller.router.Router;
+import org.exoplatform.web.controller.router.URIWriter;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/** @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a> */
+public class ControllerRendererDriver extends JapexDriverBase
+{
+
+ /** . */
+ private RegexFactory regexFactory;
+
+ /** . */
+ private Router router;
+
+ /** . */
+ private RenderContext input;
+
+ /** . */
+ private URIWriter writer;
+
+ @Override
+ public void initializeDriver()
+ {
+ String regexFactoryName = getParam("regex");
+ if (regexFactoryName.equals("jregex")) {
+ regexFactory = JRegexFactory.INSTANCE;
+ } else if (regexFactoryName.equals("java")) {
+ regexFactory = RegexFactory.JAVA;
+ }
+
+ //
+ this.regexFactory = regexFactory;
+ }
+
+ @Override
+ public void prepare(TestCase testCase)
+ {
+ try
+ {
+ URL url =
ControllerRendererDriver.class.getResource("controller.xml");
+ DescriptorBuilder builder = new DescriptorBuilder();
+ ControllerDescriptor descriptor = builder.build(url.openStream());
+ Router router = descriptor.build(regexFactory);
+
+ //
+ Map<QualifiedName, String> input = new HashMap<QualifiedName,
String>();
+ String parameters = testCase.getParam("parameters");
+ JSONObject o = new JSONObject(parameters);
+ for (Iterator<String> i = o.keys();i.hasNext();)
+ {
+ String key = i.next();
+ String value = (String)o.get(key);
+ input.put(QualifiedName.parse(key), value);
+ }
+
+ //
+ if (router.render(input) == null)
+ {
+ throw new Exception("Could not render " + input);
+ }
+
+ //
+ this.router = router;
+ this.input = new RenderContext(input);
+ this.writer = new URIWriter(NullAppendable.INSTANCE);
+ }
+ catch (Exception e)
+ {
+ AssertionError afe = new AssertionError("Could not load controller
configuration");
+ afe.initCause(e);
+ throw afe;
+ }
+ }
+
+ @Override
+ public void run(TestCase testCase)
+ {
+ try
+ {
+ router.render(input, writer);
+ writer.reset(NullAppendable.INSTANCE);
+ }
+ catch (IOException e)
+ {
+ AssertionError err = new AssertionError("Unexpected IOException");
+ err.initCause(e);
+ throw err;
+ }
+ }
+
+ @Override
+ public void finish(TestCase testCase)
+ {
+ this.router = null;
+ this.input = null;
+ this.writer = null;
+ }
+
+ @Override
+ public void terminateDriver()
+ {
+ }
+}
Added:
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/performance/NullAppendable.java
===================================================================
---
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/performance/NullAppendable.java
(rev 0)
+++
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/performance/NullAppendable.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -0,0 +1,52 @@
+/*
+ * 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.performance;
+
+import java.io.IOException;
+
+/**
+ * @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a>
+ * @version $Revision$
+ */
+public class NullAppendable implements Appendable
+{
+
+ /** . */
+ public static final NullAppendable INSTANCE = new NullAppendable();
+
+ private NullAppendable()
+ {
+ }
+
+ public Appendable append(CharSequence csq) throws IOException
+ {
+ return this;
+ }
+
+ public Appendable append(CharSequence csq, int start, int end) throws IOException
+ {
+ return this;
+ }
+
+ public Appendable append(char c) throws IOException
+ {
+ return this;
+ }
+}
Added:
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/performance/Standalone.java
===================================================================
---
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/performance/Standalone.java
(rev 0)
+++
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/performance/Standalone.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -0,0 +1,76 @@
+package org.exoplatform.web.controller.performance;
+
+import junit.framework.TestCase;
+import org.exoplatform.web.controller.QualifiedName;
+import org.exoplatform.web.controller.metadata.ControllerDescriptor;
+import org.exoplatform.web.controller.metadata.DescriptorBuilder;
+import org.exoplatform.web.controller.router.RegexFactory;
+import org.exoplatform.web.controller.router.RenderContext;
+import org.exoplatform.web.controller.router.Router;
+import org.exoplatform.web.controller.router.URIWriter;
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+/** @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a> */
+public class Standalone extends TestCase
+{
+
+ /** . */
+ private static final QualifiedName HANDLER =
QualifiedName.parse("gtn:handler");
+
+ /** . */
+ private static final QualifiedName LANG = QualifiedName.parse("gtn:lang");
+
+ /** . */
+ private static final QualifiedName SITETYPE =
QualifiedName.parse("gtn:sitetype");
+
+ /** . */
+ private static final QualifiedName SITENAME =
QualifiedName.parse("gtn:sitename");
+
+ /** . */
+ private static final QualifiedName PATH = QualifiedName.parse("gtn:path");
+
+ /** . */
+ private static final QualifiedName COMPONENT_ID =
QualifiedName.parse("gtn:componentid");
+
+ /** . */
+ private static final QualifiedName ACTION =
QualifiedName.parse("gtn:action");
+
+ /** . */
+ private static final QualifiedName OBJECT_ID =
QualifiedName.parse("gtn:objectid");
+
+ public void testFoo() throws Exception
+ {
+
+ URL url = ControllerRendererDriver.class.getResource("controller.xml");
+ DescriptorBuilder builder = new DescriptorBuilder();
+ ControllerDescriptor descriptor = builder.build(url.openStream());
+ Router router = descriptor.build(RegexFactory.JAVA);
+
+ //
+ Map<QualifiedName, String> map = new HashMap<QualifiedName, String>();
+ map.put(HANDLER, "portal");
+ map.put(SITETYPE, "portal");
+ map.put(SITENAME, "classic");
+ map.put(PATH, "page");
+
+ //
+ RenderContext context = new RenderContext(map);
+
+ //
+ URIWriter writer = new URIWriter(NullAppendable.INSTANCE);
+
+ //
+ String s = router.render(map);
+ assertNotNull(s);
+
+ //
+ while (true)
+ {
+ writer.reset(NullAppendable.INSTANCE);
+ router.render(context, writer);
+ }
+ }
+}
Added:
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/router/JRegexFactory.java
===================================================================
---
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/router/JRegexFactory.java
(rev 0)
+++
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/router/JRegexFactory.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2011 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;
+
+/**
+ * @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a>
+ */
+public class JRegexFactory extends RegexFactory
+{
+
+ /** . */
+ public static final RegexFactory INSTANCE = new JRegexFactory();
+
+ private JRegexFactory()
+ {
+ }
+
+ @Override
+ public Regex compile(String pattern)
+ {
+ return new JRegex(pattern);
+ }
+
+ @Override
+ public String getName()
+ {
+ return "jregex";
+ }
+
+ public static class JRegex extends Regex
+ {
+
+ /** . */
+ private final jregex.Pattern pattern;
+
+ public JRegex(String regex)
+ {
+ this.pattern = new jregex.Pattern(regex);
+ }
+
+ public Matcher matcher()
+ {
+ return new Matcher()
+ {
+
+ /** . */
+ private jregex.Matcher impl;
+
+ private jregex.Matcher get(CharSequence seq)
+ {
+ String s = seq.toString();
+ if (impl == null)
+ {
+ impl = pattern.matcher(s);
+ }
+ else
+ {
+ impl.setTarget(s);
+ }
+ return impl;
+ }
+
+ @Override
+ public boolean matches(CharSequence s)
+ {
+ return get(s).matches();
+ }
+
+ @Override
+ public Match[] find(CharSequence s)
+ {
+ jregex.Matcher matcher = get(s);
+ if (matcher.find())
+ {
+ Match[] matches = new Match[matcher.groupCount()];
+ for (int i = 0;i < matcher.groupCount();i++)
+ {
+ if (matcher.isCaptured(i))
+ {
+ matches[i] = new Match(matcher.start(i), matcher.end(i),
matcher.group(i));
+ }
+ else
+ {
+ matches[i] = NULL_MATCH;
+ }
+ }
+ return matches;
+ }
+ else
+ {
+ return NO_MATCHES;
+ }
+ }
+ };
+ }
+
+ @Override
+ public String getPattern()
+ {
+ return pattern.toString();
+ }
+ }
+}
Added:
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/router/RegexTestCase.java
===================================================================
---
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/router/RegexTestCase.java
(rev 0)
+++
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/router/RegexTestCase.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2011 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 junit.framework.TestCase;
+
+/** @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a> */
+public class RegexTestCase extends TestCase
+{
+
+ public void testLiteral()
+ {
+ Regex regex = JRegexFactory.INSTANCE.compile("abc");
+ Regex.Match[] matches = regex.matcher().find("abc");
+ assertEquals(1, matches.length);
+ assertEquals(0, matches[0].getStart());
+ assertEquals(3, matches[0].getEnd());
+ assertEquals("abc", matches[0].getValue());
+ }
+
+ public void testSimpleGroup1()
+ {
+ Regex regex = JRegexFactory.INSTANCE.compile("(abc)");
+ Regex.Match[] matches = regex.matcher().find("abc");
+ assertEquals(2, matches.length);
+ assertEquals(0, matches[0].getStart());
+ assertEquals(3, matches[0].getEnd());
+ assertEquals("abc", matches[0].getValue());
+ assertEquals(0, matches[1].getStart());
+ assertEquals(3, matches[1].getEnd());
+ assertEquals("abc", matches[1].getValue());
+ }
+
+ public void testSimpleGroup2()
+ {
+ Regex regex = JRegexFactory.INSTANCE.compile("a(b)c");
+ Regex.Match[] matches = regex.matcher().find("abc");
+ assertEquals(2, matches.length);
+ assertEquals(0, matches[0].getStart());
+ assertEquals(3, matches[0].getEnd());
+ assertEquals("abc", matches[0].getValue());
+ assertEquals(1, matches[1].getStart());
+ assertEquals(2, matches[1].getEnd());
+ assertEquals("b", matches[1].getValue());
+ }
+
+ public void testNonCapturingGroup()
+ {
+ Regex regex = JRegexFactory.INSTANCE.compile("a(?:b)c");
+ Regex.Match[] matches = regex.matcher().find("abc");
+ assertEquals(1, matches.length);
+ assertEquals(0, matches[0].getStart());
+ assertEquals(3, matches[0].getEnd());
+ assertEquals("abc", matches[0].getValue());
+ }
+}
Added:
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestBitStack.java
===================================================================
---
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestBitStack.java
(rev 0)
+++
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestBitStack.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2011 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 junit.framework.TestCase;
+
+/**
+ * @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a>
+ */
+public class TestBitStack extends TestCase
+{
+
+ public void testSimple()
+ {
+ BitStack bs = new BitStack();
+ assertEquals(0, bs.getDepth());
+ bs.init(2);
+ bs.push();
+ assertEquals(1, bs.getDepth());
+ bs.set(1);
+ assertFalse(bs.isEmpty());
+ bs.push();
+ assertEquals(2, bs.getDepth());
+ bs.set(0);
+ assertTrue(bs.isEmpty());
+ bs.pop();
+ assertEquals(1, bs.getDepth());
+ assertFalse(bs.isEmpty());
+ bs.pop();
+ assertEquals(0, bs.getDepth());
+ }
+
+ public void testReuse()
+ {
+ BitStack bs = new BitStack();
+ bs.init(2);
+ bs.push();
+ bs.set(0);
+ bs.push();
+ bs.set(1);
+ assertTrue(bs.isEmpty());
+ bs.pop();
+ bs.push();
+ assertFalse(bs.isEmpty());
+ }
+
+ public void testState()
+ {
+ BitStack bs = new BitStack();
+ try
+ {
+ bs.set(0);
+ fail();
+ }
+ catch (IllegalStateException e)
+ {
+ }
+ try
+ {
+ bs.pop();
+ fail();
+ }
+ catch (IllegalStateException e)
+ {
+ }
+ }
+
+}
Modified:
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestBuildRoute.java
===================================================================
---
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestBuildRoute.java 2011-09-16
11:25:56 UTC (rev 7453)
+++
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestBuildRoute.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -38,10 +38,10 @@
assertEquals(0, router.root.getSegmentNames().size());
assertEquals(1, router.root.getPatternSize());
PatternRoute patternRoute = router.root.getPattern(0);
- assertEquals("^/([^/]+)(?:(?<=^/)|(?=/)|$)",
patternRoute.pattern.toString());
+ assertEquals("^/([^/]+)(?:(?<=^/)|(?=/)|$)",
patternRoute.pattern.getPattern());
assertEquals(1, patternRoute.params.length);
assertEquals(Names.A, patternRoute.params[0].name);
- assertEquals("^.+$",
patternRoute.params[0].renderingPattern.toString());
+ assertEquals("^.+$",
patternRoute.params[0].renderingPattern.getPattern());
assertEquals(EncodingMode.FORM, patternRoute.params[0].encodingMode);
assertEquals(2, patternRoute.chunks.length);
assertEquals("", patternRoute.chunks[0]);
@@ -56,10 +56,10 @@
assertEquals(0, router.root.getSegmentNames().size());
assertEquals(1, router.root.getPatternSize());
PatternRoute patternRoute = router.root.getPattern(0);
- assertEquals("^/([^/]+)(?:(?<=^/)|(?=/)|$)",
patternRoute.pattern.toString());
+ assertEquals("^/([^/]+)(?:(?<=^/)|(?=/)|$)",
patternRoute.pattern.getPattern());
assertEquals(1, patternRoute.params.length);
assertEquals(Names.Q_A, patternRoute.params[0].name);
- assertEquals("^.+$",
patternRoute.params[0].renderingPattern.toString());
+ assertEquals("^.+$",
patternRoute.params[0].renderingPattern.getPattern());
assertEquals(EncodingMode.FORM, patternRoute.params[0].encodingMode);
assertEquals(2, patternRoute.chunks.length);
assertEquals("", patternRoute.chunks[0]);
@@ -74,10 +74,10 @@
assertEquals(0, router.root.getSegmentNames().size());
assertEquals(1, router.root.getPatternSize());
PatternRoute patternRoute = router.root.getPattern(0);
- assertEquals("^/([^/]*)(?:(?<=^/)|(?=/)|$)",
patternRoute.pattern.toString());
+ assertEquals("^/([^/]*)(?:(?<=^/)|(?=/)|$)",
patternRoute.pattern.getPattern());
assertEquals(1, patternRoute.params.length);
assertEquals(Names.A, patternRoute.params[0].name);
- assertEquals("^.*$",
patternRoute.params[0].renderingPattern.toString());
+ assertEquals("^.*$",
patternRoute.params[0].renderingPattern.getPattern());
assertEquals(EncodingMode.FORM, patternRoute.params[0].encodingMode);
assertEquals(2, patternRoute.chunks.length);
assertEquals("", patternRoute.chunks[0]);
Modified:
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestPatternBuilder.java
===================================================================
---
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestPatternBuilder.java 2011-09-16
11:25:56 UTC (rev 7453)
+++
portal/trunk/component/web/controller/src/test/java/org/exoplatform/web/controller/router/TestPatternBuilder.java 2011-09-16
12:28:21 UTC (rev 7454)
@@ -21,8 +21,6 @@
import junit.framework.TestCase;
-import java.util.regex.Pattern;
-
/**
* @author <a href="mailto:julien.viet@exoplatform.com">Julien
Viet</a>
* @version $Revision$
@@ -51,7 +49,7 @@
pb.expr("^");
pb.literal(c);
pb.expr("$");
- Pattern pattern = pb.build();
- assertTrue(pattern.matcher(Character.toString(c)).matches());
+ Regex pattern = RegexFactory.JAVA.compile(pb.build());
+ assertTrue(pattern.matcher().matches(Character.toString(c)));
}
}
Added:
portal/trunk/component/web/controller/src/test/resources/org/exoplatform/web/controller/performance/controller.xml
===================================================================
---
portal/trunk/component/web/controller/src/test/resources/org/exoplatform/web/controller/performance/controller.xml
(rev 0)
+++
portal/trunk/component/web/controller/src/test/resources/org/exoplatform/web/controller/performance/controller.xml 2011-09-16
12:28:21 UTC (rev 7454)
@@ -0,0 +1,138 @@
+<!--
+ ~ Copyright (C) 2011 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.
+ -->
+
+<controller
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
xsi:schemaLocation="http://www.gatein.org/xml/ns/gatein_controller_1_0
http://www.gatein.org/xml/ns/gatein_controller_1_0"
+
xmlns="http://www.gatein.org/xml/ns/gatein_controller_1_0"
+ separator-escape=":">
+
+ <route path="/upload">
+ <route-param qname="gtn:handler">
+ <value>upload</value>
+ </route-param>
+ </route>
+
+ <route path="/download">
+ <route-param qname="gtn:handler">
+ <value>download</value>
+ </route-param>
+ </route>
+
+ <!-- The legacy route -->
+ <route path="/public">
+ <route path="/">
+ <route-param qname="gtn:handler">
+ <value>default</value>
+ </route-param>
+ </route>
+ <route path="/{gtn:sitename}/{gtn:path}">
+ <route-param qname="gtn:handler">
+ <value>legacy</value>
+ </route-param>
+ <path-param qname="gtn:path" encoding="preserve-path">
+ <pattern>.*</pattern>
+ </path-param>
+ </route>
+ </route>
+ <route path="/private">
+ <route path="/">
+ <route-param qname="gtn:handler">
+ <value>default</value>
+ </route-param>
+ </route>
+ <route path="/{gtn:sitename}/{gtn:path}">
+ <route-param qname="gtn:handler">
+ <value>legacy</value>
+ </route-param>
+ <path-param qname="gtn:path" encoding="preserve-path">
+ <pattern>.*</pattern>
+ </path-param>
+ </route>
+ </route>
+
+ <route path="/{gtn:path}">
+ <route-param qname="gtn:handler">
+ <value>staticResource</value>
+ </route-param>
+ <path-param qname="gtn:path" encoding="preserve-path">
+ <pattern>.*\.(jpg|png|gif|ico|css)</pattern>
+ </path-param>
+ </route>
+
+ <route path="/">
+
+ <!-- The portal handler -->
+ <route-param qname="gtn:handler">
+ <value>portal</value>
+ </route-param>
+
+ <!-- Webui parameters -->
+ <request-param qname="gtn:componentid"
name="portal:componentId"/>
+ <request-param qname="gtn:action" name="portal:action"/>
+ <request-param qname="gtn:objectid" name="objectId"/>
+
+ <!-- The group access -->
+ <route path="/groups/{gtn:sitename}/{gtn:path}">
+ <request-param qname="gtn:lang" name="lang"
value-mapping="never-empty">
+ <pattern>([A-Za-z]{2}(-[A-Za-z]{2})?)?</pattern>
+ </request-param>
+ <route-param qname="gtn:sitetype">
+ <value>group</value>
+ </route-param>
+ <path-param qname="gtn:path" encoding="preserve-path">
+ <pattern>.*</pattern>
+ </path-param>
+ </route>
+
+ <!-- The user access -->
+ <route path="/users/{gtn:sitename}/{gtn:path}">
+ <request-param qname="gtn:lang" name="lang"
value-mapping="never-empty">
+ <pattern>([A-Za-z]{2}(-[A-Za-z]{2})?)?</pattern>
+ </request-param>
+ <route-param qname="gtn:sitetype">
+ <value>user</value>
+ </route-param>
+ <path-param qname="gtn:path" encoding="preserve-path">
+ <pattern>.*</pattern>
+ </path-param>
+ </route>
+
+ <!-- The portal access -->
+ <route path="/{gtn:lang}/{gtn:sitename}/{gtn:path}">
+ <route-param qname="gtn:sitetype">
+ <value>portal</value>
+ </route-param>
+ <path-param qname="gtn:lang" encoding="preserve-path">
+ <pattern>([A-Za-z]{2}(-[A-Za-z]{2})?)?</pattern>
+ </path-param>
+ <path-param qname="gtn:path" encoding="preserve-path">
+ <pattern>.*</pattern>
+ </path-param>
+ </route>
+
+ </route>
+
+ <!-- Default handler -->
+ <route path="/">
+ <route-param qname="gtn:handler">
+ <value>default</value>
+ </route-param>
+ </route>
+</controller>