blob: 3882977076b2a5e569f8f2dd58316eaf91207fc8 [file] [log] [blame]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Using and Implementing Matchers and Selectors</title>
<link href="http://purl.org/DC/elements/1.0/" rel="schema.DC">
<meta content="Christian Haul" name="DC.Creator">
</head>
<body>
<h1>Introduction</h1>
<p>
Matchers and selectors are sitemap components. They are used to
determine the flow, the other components involved and their ordering
of the request processing. One particular matcher you're probably
familiar with, is the WildcardURIMatcher. That is the one that
determines the (sub-)pipeline in the welcome example. But there are
many more matchers supplied with Apache Cocoon, one matches the requested
URI on regular expressions, others match the client's hostname,
existence of parameters and so on.
</p>
<p>
There is also a number of selectors supplied with Cocoon. Selectors
test a generally simple boolean expression and allow to select on
roughly the same things as matchers would. There is a selector on
the client's hostname, on the client's browser etc.
</p>
<p>
To make things even more complicated, actions have very similar
properties. You can nest other sitemap elements in an action and
those are included in the processing only if the action completes
successfully.
</p>
<h1>So what are the differences?</h1>
<p>
The basic structure of a selector is that of a case, switch or
if-elseif-...-elseif-else statement in programming languages while
matchers and actions compare more to a if statement. In addition
selectors don't communicate the basis for their decision to the
embedded elements, just select the next part(s) of the
pipeline. Matchers and actions, however, add a new map to the
environment that can be used for the further processing in the
sub pipeline.
</p>
<p>
You've already come across this feature on the example sitemap: The
value matched by the WildcardURIMatcher is used to determine the
filename <span class="codefrag">docs/samples/xsp/{1}.xsp</span>. Here <span class="codefrag">{1}</span>
represents the value that is stored in the environmental map with the
key <span class="codefrag">1</span>. The name of the key is arbitrary and set by the
matcher. If you had supplied a more complex pattern, there would be
others. For example <span class="codefrag">&lt;map:match pattern="*/*/*/*/report.html"&gt;</span>
would result in keys <span class="codefrag">1</span>, <span class="codefrag">2</span>, <span class="codefrag">3</span>,
and <span class="codefrag">4</span> being defined, corresponding to the <span class="codefrag">*</span>s
in the pattern.
</p>
<p>
BTW you cannot access those maps from your XSP. Use parameters to the
generator to explicitly send them. On your XSP you can access them
through an object called <span class="codefrag">parameters</span>. Example
</p>
<pre class="code">
&lt;map:match pattern="*/*/*/*/report.html"&gt;
&lt;map:generate type="serverpages" src="docs/getPostcodeData.xsp"&gt;
&lt;parameter name="postcode" value="{1}{2} {3}{4}"/&gt;
&lt;/map:generate&gt;
&lt;map:transform src="stylesheets/html/report.xsl"/&gt;
&lt;map:serialize/&gt;
&lt;/map:match&gt;
</pre>
<p>On your XSP do</p>
<pre class="code">
&lt;xsp:expr&gt;parameters.getParameter("postcode")&lt;/xsp:expr&gt;
</pre>
<p>
Generally, one could say that selectors are better suited if the
decisions has few easily distinguishable cases, the map feature is not
needed and the decision occurs later in the pipeline. Their
implementation should be lightweight and so is their integration in
the compiled sitemap.
</p>
<p>
Matchers are often the very first element in a pipeline. They direct
the processing based on more complex decision process. They are
general purpose but more costly than selectors.
</p>
<p>
Actions should be used to <em>"do"</em> something, not to chose
between different sub pipelines. That should be done only, if an error
occurred and you cannot continue the regular pipeline. Of course this
is a fuzzy criterion and using an action to choose between exactly two
sub pipelines is a very common task i.e. for authentication. Also,
often actions have no nested elements and the further processing is
not affected by the result of the action. </p>
<h1>Using Matchers</h1>
<p>
Like every other sitemap component, matchers need to be declared in
the sitemap:
</p>
<pre class="code">
&lt;map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0"&gt;
&lt;map:components&gt;
...
&lt;map:matchers default="wildcard"&gt;
&lt;map:matcher name="wildcard"
src="org.apache.cocoon.matching.WildcardURIMatcher"/&gt;
...
&lt;map:matcher name="next-page"
src="org.apache.cocoon.matching.WildcardRequestParameterMatcher"&gt;
&lt;map:parameter name="parameter-name" value="next-state"/&gt;
&lt;/map:matcher&gt;
&lt;/map:matchers&gt;
...
&lt;/map:components&gt;
&lt;map:resources/&gt;
&lt;map:pipelines/&gt;
&lt;/map:sitemap&gt;
</pre>
<p>Matchers are given a short name (e.g, "wildcard") and of course the
name of the JAVA class that implements the matcher. In addition,
parameters can be defined as well.
</p>
<p>
One matcher may be defined as default matcher, so whenever a matcher
appears in the sitemap without explicit type specification it will be
assumed that it is of the default type.
</p>
<p>
In a pipeline use the matcher like this
</p>
<pre class="code">
&lt;map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0"&gt;
&lt;map:components/&gt;
&lt;map:resources/&gt;
&lt;map:pipelines&gt;
&lt;map:pipeline&gt;
&lt;map:match pattern="*"&gt;
&lt;map:generate type="serverpages" src="test/{1}.xsp"/&gt;
&lt;map:transform src="stylesheets/dynamic-page2html.xsl"/&gt;
&lt;map:serialize/&gt;
&lt;/map:match&gt;
&lt;/map:pipeline&gt;
&lt;/map:pipelines&gt;
&lt;/map:sitemap&gt;
</pre>
<p>
Matchers can be nested:
</p>
<pre class="code">
&lt;map:match type="sessionstate" pattern="edit*"&gt;
&lt;!-- here you could insert parameters for the above matcher --&gt;
&lt;map:parameter name="attribute-name" value="__sessionstate"/&gt;
&lt;map:match type="next-page" pattern="ok*"&gt;
&lt;!-- do something here, eg. database updates --&gt;
&lt;map:call resource="simple-page1"/&gt;
&lt;/map:match&gt;
&lt;map:match type="next-page" pattern="delete*"&gt;
&lt;!-- do something different here, eg. database deletions --&gt;
&lt;map:call resource="simple-page1"/&gt;
&lt;/map:match&gt;
&lt;/map:match&gt;
</pre>
<h1>Using Selectors</h1>
<p>
As said above, selectors are very similar to matchers. Again, you need
to declare selectors in the sitemap.xmap
</p>
<pre class="code">
&lt;map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0"&gt;
&lt;map:components&gt;
...
&lt;map:selectors default="browser"&gt;
&lt;map:selector name="browser"
src="org.apache.cocoon.selection.BrowserSelector"&gt;
&lt;browser name="explorer" useragent="MSIE"/&gt;
&lt;browser name="lynx" useragent="Lynx"/&gt;
&lt;browser name="netscape" useragent="Mozilla"/&gt;
&lt;/map:selector&gt;
&lt;map:selector name="parameter"
src="org.apache.cocoon.selection.ParameterSelector"/&gt;
&lt;/map:selectors&gt;
...
&lt;/map:components&gt;
&lt;map:resources/&gt;
&lt;map:pipelines/&gt;
&lt;/map:sitemap&gt;
</pre>
<p>
Their use is a bit different to matchers, though:
</p>
<pre class="code">
&lt;map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0"&gt;
&lt;map:components/&gt;
&lt;map:resources/&gt;
&lt;map:pipelines&gt;
&lt;map:pipeline&gt;
&lt;map:match pattern="*"&gt;
&lt;map:generate type="serverpages" src="test/{1}.xsp"/&gt;
&lt;map:select type="browser"&gt;
&lt;!-- you could insert parameters here as well --&gt;
&lt;map:when test="explorer"&gt;
&lt;map:transform src="stylesheets/w3c-2-msie.xsl"/&gt;
&lt;/map:when&gt;
&lt;map:when test="lynx"&gt;
&lt;map:transform
src="stylesheets/dynamic-page2html-text.xsl"/&gt;
&lt;map:serialize/&gt;
&lt;/map:when&gt;
&lt;map:when test="netscape"&gt;
&lt;map:transform src="stylesheets/ns4.xsl"/&gt;
&lt;/map:when&gt;
&lt;map:otherwise&gt;
&lt;map:transform src="stylesheets/w3c.xsl"/&gt;
&lt;/map:otherwise&gt;
&lt;/map:select&gt;
&lt;map:transform
src="stylesheets/dynamic-page2html.xsl"/&gt;
&lt;map:serialize/&gt;
&lt;/map:match&gt;
&lt;/map:pipeline&gt;
&lt;/map:pipelines&gt;
&lt;/map:sitemap&gt;
</pre>
<p>
Obviously, this could have been done with matchers as well. Decide on
yourself, what appears clearer to you in a specific situation.
</p>
<h1>Write Your Own Matchers and Selectors</h1>
<h2>Matchers</h2>
<p>
Since the basic structure and the assumptions are very similar, we
look first at matchers and point out the differences to selectors
at the end.
</p>
<p>
Matchers need to implement the org.apache.cocoon.matching.Matcher
interface. See javadocs for more details, see also example matchers
included in the distribution.
</p>
<p>
If you would like to do global configuration for your matcher, it has
to implement the
<span class="codefrag">org.apache.avalon.framework.configuration.Configurable</span>
interface.
</p>
<p>
Local configuration parameters are avalon parameters and thus can be
easily read and used with the generated matcher method.
</p>
<p>
If the matcher returns not null, the match was successful and the
nested sub pipeline is executed. Components in sub pipeline can access
the matching result through the returned map.
</p>
<p>
The easiest way to write your own matcher would be to base it upon
org.apache.cocoon.matching.WildcardURIMatcher and override the
getMatchString method with your own.
</p>
<h2>Selectors</h2>
<p>
Selectors and selector factories differ from their matcher counter
parts only in the fact that selectors return boolean values rather
than maps. Thus when a selector returns <span class="codefrag">true</span> the nested
elements will be included in the processing, otherwise they are not
included. Since no map is returned, no additional information may be
passed to those elements.
</p>
<p>
For selectors, the last argument reads <span class="codefrag">param</span> instead of
<span class="codefrag">parameters</span>. </p>
</body>
</html>