blob: abaccd34f76bd8a67f926e48fc4ddf0a28476c7f [file] [log] [blame]
<!DOCTYPE html>
<!--
| Generated by Apache Maven Doxia Site Renderer 2.0.0 from src/site/xdoc/howto/url-mapper-howto.xml at 10 Sep 2025
| Rendered using Apache Maven Fluido Skin 2.1.0
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="generator" content="Apache Maven Doxia Site Renderer 2.0.0" />
<title>URL Mapper Howto – Apache Turbine</title>
<link rel="stylesheet" href="../css/apache-maven-fluido-2.1.0.min.css" />
<link rel="stylesheet" href="../css/site.css" />
<link rel="stylesheet" href="../css/print.css" media="print" />
<script src="../js/apache-maven-fluido-2.1.0.min.js"></script>
<link rel="icon" type="image/png" sizes="48x48" href="https://apache.org/favicons/favicon.ico">
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<style>.github-fork-ribbon:before { background-color: orange; }</style>
</head>
<body>
<a class="github-fork-ribbon right-top" href="https://github.com/apache/turbine-build" data-ribbon="Fork me on GitHub">Fork me on GitHub</a>
<div class="container-fluid container-fluid-top">
<header>
<div id="banner">
<div class="pull-left"><div id="bannerLeft"><h1><a href="https://turbine.apache.org/"><img src="https://www.apache.org/img/feather_glyph_notm.png" style="width: 50px;" /> The Apache Turbine project</a></h1></div></div>
<div class="pull-right"><div id="bannerRight"><h1><a href="https://turbine.apache.org/"><img src="https://turbine.apache.org/images/logo.gif" alt="Apache Turbine" /></a></h1></div></div>
<div class="clear"><hr/></div>
</div>
<div id="breadcrumbs">
<ul class="breadcrumb">
<li id="publishDate">Last Published: 01 Apr 2025<span class="divider">|</span>
</li>
<li id="projectVersion">Version: 7.1-SNAPSHOT</li>
<li class="pull-right"><span class="divider">|</span>
<a href="https://turbine.apache.org/fulcrum/">Fulcrum</a></li>
<li class="pull-right"><span class="divider">|</span>
<a href="https://turbine.apache.org/">Turbine</a></li>
<li class="pull-right"><a href="https://www.apache.org">Apache</a></li>
</ul>
</div>
</header>
<div class="row-fluid">
<header id="leftColumn" class="span2">
<nav class="well sidebar-nav">
<ul class="nav nav-list">
<li class="nav-header">General Information</li>
<li><a href="../index.html">Overview</a></li>
<li><a href="../features.html">Features</a></li>
<li><a href="../fsd.html">Specification</a></li>
<li><a href="../getting-started.html">Getting Started</a></li>
<li><a href="../how-to-build.html">Howto Build Turbine</a></li>
<li><a href="../changes-report.html">Changes</a></li>
<li class="nav-header">Documentation</li>
<li><a href="../services/index.html"><span class="icon-chevron-right"></span>Services</a></li>
<li><a href="../howto/index.html"><span class="icon-chevron-down"></span>Howtos</a>
<ul class="nav nav-list">
<li><a href="../howto/action-event-howto.html">Action Events Howto</a></li>
<li><a href="../howto/annotations.html">Annotations Howto</a></li>
<li><a href="../howto/configuration-howto.html">Configuration Howto</a></li>
<li><a href="../howto/extend-user-howto.html">Extend User Howto</a></li>
<li><a href="../howto/hibernate-howto.html">Hibernate OM Howto</a></li>
<li><a href="../howto/intake-howto.html">Intake Howto</a></li>
<li><a href="../howto/jsp-howto.html">JSP Howto</a></li>
<li><a href="../howto/migrate-from-2_1-howto.html">Migrating from 2.1 to 2.2</a></li>
<li><a href="../howto/migrate-from-2_2-howto.html">Migrating from 2.2 to 2.3</a></li>
<li><a href="../howto/migrate-from-2_3-howto.html">Migrating from 2.3 to 4.0</a></li>
<li><a href="../howto/migrate-from-4_0-howto.html">Migrating from 4.0 to 5.0</a></li>
<li><a href="../howto/pullmodel-howto.html">Pull Model Howto</a></li>
<li><a href="../howto/python-howto.html">Python Howto</a></li>
<li><a href="../howto/security-howto.html">Security Howto</a></li>
<li><a href="../howto/services-howto.html">Services Howto</a></li>
<li class="active"><a>URL Mapper Howto</a></li>
<li><a href="../howto/url-rewriting-howto.html">URL Rewriting Howto</a></li>
<li><a href="../howto/context-howto.html">Velocity Context Howto</a></li>
<li><a href="../howto/velocity-site-howto.html">Velocity Site Howto</a></li>
<li><a href="../howto/velocityonlylayout-howto.html">VelocityOnlyLayout Howto</a></li>
</ul></li>
<li><a href="https://cwiki.apache.org/confluence/display/TURBINE">Wiki</a></li>
<li><a href="../apidocs/index.html">JavaDocs</a></li>
<li class="nav-header">Development</li>
<li><a href="../proposals.html">Proposals</a></li>
<li><a href="../how-to-help.html">How To Help</a></li>
<li><a href="../todo.html">Todo</a></li>
<li class="nav-header">Project Documentation</li>
<li><a href="../project-info.html"><span class="icon-chevron-right"></span>Project Information</a></li>
<li><a href="../project-reports.html"><span class="icon-chevron-right"></span>Project Reports</a></li>
<li class="nav-header">Apache</li>
<li><a href="https://www.apache.org/">Apache Website</a></li>
<li><a href="https://www.apache.org/licenses/">License</a></li>
<li><a href="https://www.apache.org/foundation/how-it-works.html">How the ASF works</a></li>
<li><a href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li>
<li><a href="https://www.apache.org/foundation/thanks.html">Thanks</a></li>
<li><a href="https://www.apache.org/security/">Security</a></li>
</ul>
</nav>
<div class="well sidebar-nav">
<form id="search-form" action="https://www.google.com/search" method="get" >
<input value="http://turbine.apache.org/turbine/turbine-7-0" name="sitesearch" type="hidden" />
<input class="search-query" name="q" id="query" type="text" placeholder="Search with Google..." />
</form>
<div id="poweredBy">
<div class="clear"></div>
<div class="clear"></div>
<a href="https://maven.apache.org/" class="builtBy" target="_blank"><img class="builtBy" alt="Built by Maven" src="../images/logos/maven-feather.png" /></a>
</div>
</div>
</header>
<main id="bodyColumn" class="span10">
<section><a id="Introduction"></a>
<h1>Introduction</h1>
<p>
Unaltered Turbine URLs may look like this:
<code>http://www.foo.com:8080/CONTEXT/servlet/MAPPING/template/Foo.vm</code>.<br />
But you want shorter URLs? Maybe this URL would suit you better:
<code>http://www.foo.com:8080/CONTEXT/servlet/beautiful/world</code>
</p>
This HOWTO describes, how you can control the pathinfo or query part of a url (behind the webapproot and the context) and the context with a mapping (routing) file
defined in xml, json or yaml format to become more simplified or beautiful!
</section>
<section><a id="Turbine_URLMapper_Configuration"></a>
<h1>Turbine URLMapper Configuration</h1>
<p>
You need to
</p>
<ul>
<li>register the URL Mapper service in turbine configuration (TR.properties) </li>
<li>register the valve in the pipeline (turbine-classic-pipeline.xml)</li>
</ul>
<p>Consider the following example configuration:
MappedTemplateLink is for now optional, you can add it as a separate tool or just replace the existing TemplateLink.
</p>
<pre class="prettyprint"><code>
# -------------------------------------------------------------------
#
# U R L M A P P E R S E R V I C E
#
# -------------------------------------------------------------------
# required
services.URLMapperService.classname=org.apache.turbine.services.urlmapper.TurbineURLMapperService
# configFile is required here! xml, json and yml supported as extension.
services.URLMapperService.configFile = /conf/turbine-url-mapping.xml
# new mapper (optional)
tool.request.mlink=org.apache.turbine.services.urlmapper.MappedTemplateLink
# tool.request.jlink= org.apache.turbine.services.pull.tools.TemplateLink
</code></pre>
<p>To resolve a provided / mapped URL add the valve into pipeline (pipeline.default.descriptor = /conf/turbine-classic-pipeline.xml).
</p>
<pre class="prettyprint"><code>
&lt;valves&gt;
&lt;valve&gt;org.apache.turbine.services.urlmapper.URLMapperValve&lt;/valve&gt;
...
</code></pre>
<p>This will check if the provided URL matches any pattern, resolves it given in the path or implicitly as defined in
the URLMapperService's configfile.</p>
</section>
<section><a id="Define_your_patterns"></a>
<h1>Define your patterns</h1>
<p>The URL Mapping Mechanism uses a well defined pattern format.
The pattern format scheme is defined as follows, e.g. in JSON:</p>
<pre class="prettyprint"><code>
&quot;pattern&quot;: &quot;/(?&lt;webAppRoot&gt;[.\\-\\w]+)/(?&lt;contextPath&gt;\\w+)/(?&lt;resolvableParam&gt;\\w+)/beautifulname&quot;
</code></pre>
<p>That is <strong>resolvableParam</strong> is just a specific parameter name or key, which should be resolved after the context slash and before the next URL part, which starts with &quot;/beatifulname&quot;.
It has to be set like this</p>
<pre class="prettyprint"><code>
/(?&lt;resolvableParam&gt;\\w+)
</code></pre>
Technically this isa non matching named group, with the group name <strong>resolvableParam</strong> and
in this case a sequence of alphabetical characters with minimal length of 1.
The same is true for the predefined <strong>webAppRoot</strong> and <strong>contextPath</strong>.
<p>Another condition to be met, is that the parameter name must follow the &quot;Java Named Group pattern characters restriction&quot;:</p>
<pre class="prettyprint"><code>
NAMED_GROUPS_PATTERN = Pattern.compile(&quot;(?&lt;([a-zA-Z][a-zA-Z0-9]*)&gt;.+?)&quot;);
</code></pre>
<p>
Any parameter is resolved as a <i>group name</i>
(<a href="https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html" class="externalLink">Java Pattern-&gt;Groups and Capturing-&gt;Group name</a>).
These group names are predefined (symbolic group name)):
</p>
<ul>
<li><strong>&lt;webAppRoot&gt;</strong></li>
<li><strong>&lt;contextPath&gt;</strong></li></ul>
Be aware, that this does not allow replacing parameters containing other characters (e.g underscore or hyphens). You may use implicit parameter matching.
Following is an example for a configuration :
<pre class="prettyprint"><code>
&lt;url-mapping name=&quot;default&quot;&gt;
&lt;maps&gt;
&lt;map&gt;
&lt;pattern&gt;/(?&amp;lt;webAppRoot&amp;gt;[.\\-\\w]+)/(?&amp;lt;contextPath&amp;gt;\w+)/book/(?&amp;lt;bookId&amp;gt;\d+)&lt;/pattern&gt;
&lt;implicit-parameters&gt;
&lt;parameter key=&quot;template&quot;&gt;Book.vm&lt;/parameter&gt;
&lt;parameter key=&quot;detail&quot;&gt;0&lt;/parameter&gt;
&lt;/implicit-parameters&gt;
&lt;/map&gt;
...
</code></pre>
<p>Three parameters are evaluated:
</p>
<ul>
<li>a parameter name <strong>template</strong> and value <strong>Book.vm</strong></li>
<li>a parameter <strong>detail</strong> and value <strong>0</strong></li>
<li>a parameter <strong>bookId</strong> with <i>any</i> value, e.g. <strong>4</strong></li>
</ul>
This will be converted, if matched, to an URL like <strong>/book/4</strong>.
The pattern uses type restrictions for the value, e.g. number for the bookId and a extended character set for the webAppRoot, which will be applied in (back resolving) <strong>mapFromURL</strong>.
<p>Another example in <strong>JSON</strong> format, which is much more readable, if not viewing in a browser is here (showing a shortened URL by replacing two parameters):</p>
<pre class="prettyprint"><code>
{
&quot;name&quot;: &quot;default&quot;,
&quot;maps&quot;: [
{
&quot;pattern&quot;: &quot;/(?&lt;webAppRoot&gt;[\\w]+)/(?&lt;contextPath&gt;\\w+)/register&quot;,
&quot;implicit-parameters&quot;: {
&quot;page&quot;: &quot;Register&quot;,
&quot;role&quot;: &quot;anon&quot;
}
},
...
</code></pre>
</section>
<section><a id="Service_Description"></a>
<h1>Service Description</h1>
<p>The main methods of the service <strong>TurbineURLMapperService</strong> are</p>
<ul>
<li><strong>mapToUrl</strong>, which as the Javadoc explains &quot;maps a set of parameters (contained in TurbineURI PathInfo and QueryData) to a TurbineURIs&quot;</li>
<li><strong>mapFromUrl</strong>, which &quot;maps a simplified URL to a set of parameters&quot;</li>
</ul>
<section><a id="Matrix"></a>
<h2>Matrix</h2>
<table class="table table-striped">
<tr class="a">
<th colspan="6">Turbine URL Mapper Model</th>
</tr>
<tr class="b">
<th>Mechanism</th>
<th>Method</th>
<th>Pattern</th>
<th>Implicit Param</th>
<th>Override Param</th>
<th>Ignore Param</th>
</tr>
<tr class="a">
<th>Converts Parameterized URL to simplified URL</th>
<th>mapToUrl</th>
<td>
&quot;Match Group Name&quot;: The pattern of the target URL after evaluation of parameters. If a group name is set, a matching parameter key must be provided and the value will replace the group name in the target URL.</td>
<td>&quot;Exact Filter&quot;, &quot;Reduce&quot;: If a parameter key is is set implicitely, both key and value must exactly matched by a parameter pair in the provided (unmapped) URI. It will then be removed</td>
<td>- An override could be achieved by hard coding it in the pattern and filterign in implicit param.
On the other hand you can then ignore the parameter</td>
<td>The parameter will be removed from the required parameter key set and also from the target URL if it is provided as a group name</td></tr>
<tr class="b">
<th>Resolves URL to Params for evaluating by the backend</th>
<th>mapFromUrl</th>
<td>
The pattern of the URL to be matched to evaluate parameter resolving</td>
<td>Param key/value will be set implicitely</td>
<td>Overrides (provided) URL parameter with provided value</td>
<td>will remove parameter key/value from result parameter list, even if provided as capturing group name</td></tr>
</table>
</section>
<p>N.B. Symbolic group names <i>webAppRoot</i> and <i>context</i> could not be ignored or overridden!</p>
</section>
<section><a id="Usage"></a>
<h1>Usage</h1>
<p>
Use the methods getRelative or getAbsoluteLink of the provided convenience class MappedTemplateLink class (of type TemplateLink)
in a velocity template like this:
</p>
<pre class="prettyprint"><code>
$mlink.addPathInfo(&quot;world&quot;,&quot;nice&quot;).getRelativeLink()
## should result into a URL: /beautiful/world
</code></pre>
<p>
<p>Alternatively you can use the service explicitely in Java, e.g. in a Java Action or other class if you inject the URLMapperService (or provide this in a shared controller class).</p>
<pre class="prettyprint"><code>
// inside any assembler you may alternatively use annotation
// @TurbineService( &quot;URLMapperService&quot; ) urlMapper;
URLMapperService urlMapper = (URLMapperService) TurbineServices.getInstance().getService(URLMapperService.SERVICE_NAME);
// Any turbineURI ..e.g. from PoolService or
TurbineURI uri ...
urlMapper.mapToURL( uri );
// use it, e.g by putting it into a velocity context (org.apache.velocity.context.Context(
context.put(&quot;myLink&quot;, link);
</code></pre>
More examples ...
</section>
</main>
</div>
</div>
<hr/>
<footer>
<div class="container-fluid">
<div class="row-fluid">
<p>© 2000–2025
<a href="https://www.apache.org/">The Apache Software Foundation</a>
</p>
</div>
</div>
</footer>
</body>
</html>