Introduction

Unaltered Turbine URLs may look like this: http://www.foo.com:8080/CONTEXT/servlet/MAPPING/template/Foo.vm.
But you want shorter URLs Maybe this url would suit you better: http://www.foo.com:8080/CONTEXT/servlet/beautiful/world

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!

Turbine Configuration

You need to

  • register the URL Mapper service in turbine configuration (TR.properties)
  • register the valve in the pipeline (turbine-classic-pipeline.xml)

Consider the following example configuration: MappedTemplateLink is for now optional, you can add it as a separate tool or just replace the existing TemplateLink.

	# -------------------------------------------------------------------
	#
	#  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

To resolve a provided / mapped URL add the valve into pipeline (pipeline.default.descriptor = /conf/turbine-classic-pipeline.xml).

  <valves>
    <valve>org.apache.turbine.services.urlmapper.URLMapperValve</valve>
    ...

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.

URL Mapping Mechanism

The pattern format scheme is as follows, e.g. in JSON:

 "pattern":  "/(?<webAppRoot>[.\\-\\w]+)/(?<contextPath>\\w+)/(?<resolvableParam>\\w+)/beautifulname"

That is any specific parameter name or key, which should be resolved, has to be set like this

 /(?<resolvableParam>\\w+)

Another condition to be met, is that the parameter name must follow the "Java Named Group pattern characters restriction":

 NAMED_GROUPS_PATTERN = Pattern.compile("(?<([a-zA-Z][a-zA-Z0-9]*)>.+?)");

Any parameter is resolved as a group name (Java Pattern->Groups and Capturing->Group name). These group names are predefined (symbolic group name)):

  • <webAppRoot>
  • <contextPath>
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 :
<url-mapping name="default">
    <maps>
        <map>
            <pattern>/(?&lt;webAppRoot&gt;[.\\-\\w]+)/(?&lt;contextPath&gt;\w+)/book/(?&lt;bookId&gt;\d+)</pattern>
            <implicit-parameters>
                <parameter key="template">Book.vm</parameter>
                <parameter key="detail">0</parameter>
            </implicit-parameters>
        </map>
        ...

Three parameters are evaluated:

  • a parameter name template and value Book.vm
  • a parameter detail and value 0
  • a parameter bookId with any value, e.g. 4
This will be converted, if matched, to an URL like /book/4. 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) mapFromURL.

Another example in JSON format with just more short URL by replacing two parameters:

{
  "name": "default",
  "maps": [
	{
		"pattern": "/(?<webAppRoot>[\\w]+)/(?<contextPath>\\w+)/register",
		"implicit-parameters": {
			"page": "Register",
			"role": "anon"
		}
	},
        ...

Turbine Service Description and Usage

The main methods of the service TurbineURLMapperService are

  • mapToUrl, which as the Javadoc explains "maps a set of parameters (contained in TurbineURI PathInfo and QueryData) to a TurbineURIs"
  • mapFromUrl, which "maps a simplified URL to a set of parameters"

Matrix

Turbine URL Simplifier Mapping Model
Mechanism Method Pattern Implicit Param Override Param Ignore Param
Converts Parameterized URL to simplified URL mapToUrl "Match Group Name": 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. "Exact Filter", "Reduce": 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 - 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 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
Resolves URL to Params for evaluating by the backend mapFromUrl The pattern of the URL to be matched to evaluate parameter resolving Param key/value will be set implicitely Overrides (provided) URL parameter with provided value will remove parameter key/value from result parameter list, even if provided as capturing group name

N.B. Symbolic group names wenapproot and context could not be ignored or overridden!

The convenience class MappedTemplateLink class (of type TemplateLink) calls with its methods getRelative or getAbsoluteLink mapToUrl implicitely. Use it in a velocity template like this:

  $mlink.addPathInfo("world","nice").getRelativeLink()
  ## may result into /beautiful/world

Alternatively you can use the service explicitely in Java, e.g. in a Java Action or other class:

   // inside any assembler you may alternatively use annotation @TurbineService( "URLMapperService" ) 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("myLink", link);
     
More examples ...