org.apache.cocoon.transformation
public class: VariableRewriterTransformer [javadoc |
source]
java.lang.Object
org.apache.avalon.framework.logger.AbstractLogEnabled
org.apache.cocoon.xml.AbstractXMLProducer
org.apache.cocoon.xml.AbstractXMLPipe
org.apache.cocoon.transformation.AbstractTransformer
org.apache.cocoon.transformation.AbstractSAXTransformer
org.apache.cocoon.transformation.VariableRewriterTransformer
All Implemented Interfaces:
org.apache.avalon.framework.activity.Disposable, org.apache.avalon.framework.activity.Initializable, org.apache.avalon.framework.activity.Disposable, org.apache.avalon.framework.service.Serviceable, org.apache.avalon.framework.configuration.Configurable, Transformer, XMLPipe, org.apache.avalon.excalibur.pool.Recyclable, XMLProducer
Rewrites URIs in links to a value determined by an InputModule.
The URI scheme identifies the InputModule to use, and the rest of the URI is
used as the attribute name.
Example
For instance, if we had an
org.apache.cocoon.components.modules.input.XMLFileModule , configured to
read values from an XML file:
<site>
<faq>
<how_to_boil_eggs href="faq/eggs.html"/>
</faq>
</site>
mapped to the prefix 'site:', then <link
href="site:/site/faq/how_to_boil_eggs/@href"> would be replaced with
<link href="faq/eggs.html">
InputModules are configured twice; first statically in
cocoon.xconf, and then dynamically at runtime, with dynamic
configuration (if any) taking precedence. VariableRewriterTransformer allows
you to pass a dynamic configuration to used InputModules as follows.
First, a template Configuration is specified in the static
<map:components> block of the sitemap:
<map:transformer name="linkrewriter"
src="org.apache.cocoon.transformation.VariableRewriterTransformer">
<input-module name="site" src="cocoon://samples/link/linkmap" reloadable="true"/>
<input-module name="mapper">
<input-module name="site" src="{src}" reloadable="true"/>
<prefix>/site/</prefix>
<suffix>/@href</suffix>
</input-module>
</map:transformer>
Here, we have established dynamic configuration templates for two modules,
'site' (an
org.apache.cocoon.components.modules.input.XMLFileModule
and 'mapper' (A
org.apache.cocoon.components.modules.input.SimpleMappingMetaModule . All
other InputModules will use their static configs. Note that the dynamic
config syntax different to the static config syntax (attributes instead of
elements). Note also that, when configuring a Meta InputModule like
'mapper', we need to also configure the 'inner' module (here, 'site') with a
nested <input-module>.
There is one further twist; to have really dynamic configuration,
we need information available only when the transformer actually runs. This
is why the above config was called a "template" Configuration; it needs to
be 'instantiated' and provided extra info, namely:
- The {src} string will be replaced with the map:transform @src attribute value.
- Any other {variables} will be replaced with map:parameter values
With the above config template, we can have a matcher like:
<map:match pattern="**welcome">
<map:generate src="index.xml"/>
<map:transform type="linkrewriter" src="cocoon:/{1}linkmap"/>
<map:serialize type="xml"/>
</map:match>
Which would cause the 'mapper' XMLFileModule to be configured with a
different XML file, depending on the request.
Similarly, we could use a dynamic prefix:
<prefix>{prefix}</prefix>
in the template config, and:
<map:parameter name="prefix" value="/site/"/>
in the map:transform
Configuration
The following map:parameter's are recognised:
- link-attrs
- Space-separated list of attributes to consider links (to be
transformed). Defaults to 'href'.
- schemes
- Space-separated list of URI schemes to explicitly include. If specified, all URIs with unlisted schemes will not be converted.
- exclude-schemes
- Space-separated list of URI schemes to explicitly exclude.
- bad-link-str
- String to use for links with a correct InputModule prefix, but no value
therein. Defaults to the original URI.
Note that currently, only links in the default ("") namespace are converted.
- author:
< - a href="mailto:jefft@apache.org">Jeff Turner
- version:
$ - Id: VariableRewriterTransformer.java 433543 2006-08-22 06:22:54Z crossley $
| Fields inherited from org.apache.cocoon.transformation.AbstractSAXTransformer: |
|---|
| EMPTY_ATTRIBUTES, ignoreWhitespaces, ignoreEmptyCharacters, ignoreEventsCount, ignoreHooksCount, namespaceURI, defaultNamespaceURI, stack, recorderStack, request, response, context, objectModel, parameters, source, manager, resolver, emptyAttributes |
| Methods from org.apache.cocoon.transformation.AbstractSAXTransformer: |
|---|
|
addRecorder, characters, comment, configure, dispose, endCDATA, endDTD, endDocument, endElement, endEntity, endParametersRecording, endParametersRecording, endPrefixMapping, endRecording, endSAXRecording, endSerializedXMLRecording, endTextRecording, endTransformingElement, findPrefixMapping, getMutableAttributes, ignorableWhitespace, processingInstruction, recycle, removeRecorder, sendEndElementEvent, sendEndElementEventNS, sendEndPrefixMapping, sendEvents, sendParametersEvents, sendStartElementEvent, sendStartElementEvent, sendStartElementEventNS, sendStartElementEventNS, sendStartPrefixMapping, sendTextEvent, service, setDocumentLocator, setup, setupTransforming, skippedEntity, startCDATA, startDTD, startDocument, startElement, startEntity, startParametersRecording, startPrefixMapping, startRecording, startSAXRecording, startSerializedXMLRecording, startTextRecording, startTransformingElement |
| Methods from org.apache.cocoon.xml.AbstractXMLPipe: |
|---|
|
characters, comment, endCDATA, endDTD, endDocument, endElement, endEntity, endPrefixMapping, ignorableWhitespace, processingInstruction, setDocumentLocator, skippedEntity, startCDATA, startDTD, startDocument, startElement, startEntity, startPrefixMapping |
| Method from org.apache.cocoon.transformation.VariableRewriterTransformer Detail: |
public void characters(char[] p0,
int p1,
int p2) throws SAXException {
if (this.ignoreEventsCount == 0) {
if (this.ignoreEmptyCharacters == true) {
String value = new String(p0, p1, p2);
if (value.trim().length() > 0) {
super.characters(p0, p1, p2);
}
} else {
super.characters(p0, p1, p2);
}
}
}
|
public void configure(Configuration conf) throws ConfigurationException {
super.configure(conf);
this.origConf = conf;
}
Configure this component from the map:transformer block. Called before
initialization and setup. |
public void dispose() {
if (this.modHelper != null) {
this.modHelper.releaseAll();
this.modHelper = null;
}
super.dispose();
}
|
public void initialize() throws Exception {
this.defaultNamespaceURI = NAMESPACE;
this.modHelper = new InputModuleHelper();
this.modHelper.setup(this.manager);
}
Initiate resources prior to this component becoming active. |
public void recycle() {
this.resolver = null;
this.linkAttrs = null;
this.inSchemes = null;
this.outSchemes = null;
this.conf = null;
// Note: configure() and initialize() are not called after every
//recycle, so don't null origConf
super.recycle();
}
Recycle this component for use in another map:transform. |
public void setup(SourceResolver resolver,
Map objectModel,
String src,
Parameters parameters) throws IOException, SAXException, ProcessingException {
super.setup(resolver, objectModel, src, parameters);
this.badLinkStr = parameters.getParameter("bad-link-str", null);
this.linkAttrs = split(parameters.getParameter("link-attrs", "href"), " ");
this.inSchemes = split(parameters.getParameter("schemes", ""), " ");
this.outSchemes = split(parameters.getParameter("exclude-schemes", ""), " ");
// Generate conf
VariableConfiguration varConf = new VariableConfiguration(this.origConf);
varConf.addVariable("src", src);
varConf.addVariables(parameters);
try {
this.conf = varConf.getConfiguration();
} catch (ConfigurationException ce) {
throw new ProcessingException("Couldn't create dynamic config ", ce);
}
}
Setup this component to handle a map:transform instance. |
public void startTransformingElement(String uri,
String name,
String raw,
Attributes attr) throws IOException, SAXException, ProcessingException {
Attributes newAttrs = null;
boolean matched = false;
Iterator iter = linkAttrs.iterator();
while (iter.hasNext()) {
int attrIdx = attr.getIndex((String)iter.next());
if (attrIdx != -1) {
String oldAttr = attr.getValue(attrIdx);
int i = oldAttr.indexOf(":");
if (i != -1) {
String scheme = oldAttr.substring(0, i);
String addr = oldAttr.substring(i+1);
if (outSchemes.contains(scheme)) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Ignoring link '"+scheme+":"+addr+"'");
}
} else if (inSchemes.contains(scheme)) {
matched = true;
newAttrs = getLinkAttr(attr, attrIdx, scheme, addr);
if (getLogger().isDebugEnabled()) {
getLogger().debug("Converted link '"+oldAttr+"' to '"+newAttrs.getValue(attrIdx)+"'");
}
} else {
if (inSchemes.size() == 0) {
// If the link wasn't deliberately excluded from a
// list of 'good' links, then include it.
matched = true;
newAttrs = getLinkAttr(attr, attrIdx, scheme, addr);
getLogger().debug("Converted link '"+oldAttr+"' to '"+newAttrs.getValue(attrIdx)+"'");
}
}
}
}
}
if (matched) {
super.startTransformingElement(uri, name, raw, newAttrs);
} else {
super.startTransformingElement(uri, name, raw, attr);
}
}
Start processing elements of our namespace.
This hook is invoked for each sax event with our namespace. |