Author: rgardler
Date: Wed Dec 6 16:27:56 2006
New Revision: 483309
URL: http://svn.apache.org/viewvc?view=rev&rev=483309
Log:
Add source document aggregation.
Added:
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/AggregateNode.java
(with props)
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/plugin/AggregateInputPlugin.java
(with props)
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/AggregateReader.java
(with props)
Modified:
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/Controller.java
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/IController.java
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/document/AbstractSourceDocument.java
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/document/AggregatedSourceDocument.java
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/AbstractSourceNode.java
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/LocationMap.java
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/LocationNode.java
forrest/trunk/whiteboard/forrest2/core/src/test/locationmap.xml
Modified:
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/Controller.java
URL:
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/Controller.java?view=diff&rev=483309&r1=483308&r2=483309
==============================================================================
---
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/Controller.java
(original)
+++
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/Controller.java
Wed Dec 6 16:27:56 2006
@@ -36,11 +36,14 @@
import org.apache.forrest.core.exception.LocationmapException;
import org.apache.forrest.core.exception.ProcessingException;
import org.apache.forrest.core.locationMap.AbstractSourceNode;
+import org.apache.forrest.core.locationMap.AggregateNode;
import org.apache.forrest.core.locationMap.LocationNode;
import org.apache.forrest.core.locationMap.LocationMap;
import org.apache.forrest.core.plugin.AbstractInputPlugin;
+import org.apache.forrest.core.plugin.AggregateInputPlugin;
import org.apache.forrest.core.plugin.BaseOutputPlugin;
import org.apache.forrest.core.plugin.PassThroughInputPlugin;
+import org.apache.forrest.core.reader.AggregateReader;
import org.apache.forrest.core.reader.IReader;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
@@ -206,6 +209,9 @@
* @see
org.apache.forrest.core.IController#getInputPlugin(org.apache.forrest.core.document.AbstractSourceDocument)
*/
public AbstractInputPlugin getInputPlugin(final AbstractSourceDocument
doc) {
+ if (doc instanceof AggregatedSourceDocument) {
+ return new AggregateInputPlugin();
+ }
AbstractInputPlugin plugin;
try {
plugin = (AbstractInputPlugin)
this.context.getBean(doc.getType());
@@ -257,7 +263,7 @@
}
/**
- * Load each of the source documents into the docuemnt cache.
+ * Load each of the source documents into the document cache.
*
* @throws MalformedURLException
* @throws ProcessingException
@@ -287,7 +293,7 @@
AbstractSourceDocument doc = sourceDocsCache.get(requestURI);
if (doc == null) {
for (AbstractSourceNode node :
location.getSourceNodes()) {
- IReader reader = getReader(node.getSourceURI());
+ IReader reader = getReader(node);
doc = reader.read(this, requestURI, node,
location.getMatcher());
if (doc != null) {
addToSourceDocCache(requestURI, doc);
@@ -328,6 +334,16 @@
}
readerClass = reader.getClass().toString();
return reader;
+ }
+
+
+
+ public IReader getReader(AbstractSourceNode sourceNode) throws
ProcessingException {
+ if (sourceNode instanceof AggregateNode) {
+ return new AggregateReader();
+ } else {
+ return getReader(sourceNode.getSourceURI());
+ }
}
/**
Modified:
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/IController.java
URL:
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/IController.java?view=diff&rev=483309&r1=483308&r2=483309
==============================================================================
---
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/IController.java
(original)
+++
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/IController.java
Wed Dec 6 16:27:56 2006
@@ -10,6 +10,7 @@
import org.apache.forrest.core.document.InternalDocument;
import org.apache.forrest.core.exception.LocationmapException;
import org.apache.forrest.core.exception.ProcessingException;
+import org.apache.forrest.core.locationMap.AbstractSourceNode;
import org.apache.forrest.core.locationMap.LocationNode;
import org.apache.forrest.core.plugin.AbstractInputPlugin;
import org.apache.forrest.core.plugin.BaseOutputPlugin;
@@ -29,13 +30,26 @@
/**
* Get a reader that can be used for retrieving a resource
- * from a given URI.
+ * from a given URI. Note that this method will never
+ * return an aggregate reader so it should be used with
+ * caution. It is much safer to use getReader(sourceNode).
*
* @param sourceURI
* @return
* @throws ProcessingException
+ * @see [EMAIL PROTECTED] #getReader(AbstractSourceNode)}
*/
public abstract IReader getReader(final URI sourceURI) throws
ProcessingException;
+
+ /**
+ * Get a reader that can be used for retrieving a resource
+ * from a given source node.
+ *
+ * @param sourceNode
+ * @return
+ * @throws ProcessingException
+ */
+ public abstract IReader getReader(final AbstractSourceNode sourceNode)
throws ProcessingException;
/**
* Get the source URLs for a given request URI.
Modified:
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/document/AbstractSourceDocument.java
URL:
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/document/AbstractSourceDocument.java?view=diff&rev=483309&r1=483308&r2=483309
==============================================================================
---
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/document/AbstractSourceDocument.java
(original)
+++
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/document/AbstractSourceDocument.java
Wed Dec 6 16:27:56 2006
@@ -26,11 +26,15 @@
*
*/
public abstract class AbstractSourceDocument extends AbstractDocument {
- String type;
+ String type = "org.apache.forrest.AggregateDocument";
public AbstractSourceDocument(URI requestURI, String content) {
setRequestURI(requestURI);
setContent(content);
+ }
+
+ public AbstractSourceDocument(URI requestURI) {
+ setRequestURI(requestURI);
}
@Override
Modified:
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/document/AggregatedSourceDocument.java
URL:
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/document/AggregatedSourceDocument.java?view=diff&rev=483309&r1=483308&r2=483309
==============================================================================
---
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/document/AggregatedSourceDocument.java
(original)
+++
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/document/AggregatedSourceDocument.java
Wed Dec 6 16:27:56 2006
@@ -16,14 +16,14 @@
*/
package org.apache.forrest.core.document;
+import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
/**
- * An aggregated source document is used to represent
- * a source document that consists of a number of
- * separate documents.
+ * An aggregated source document is used to represent a source document that
+ * consists of a number of separate documents.
*
*/
public class AggregatedSourceDocument extends AbstractSourceDocument {
@@ -32,11 +32,15 @@
super(requestURI, content);
}
+ public AggregatedSourceDocument(URI requestURI) {
+ super(requestURI);
+ }
+
List<AbstractSourceDocument> docs = new
ArrayList<AbstractSourceDocument>();
/**
- * Look to see if this aggregation of documents contains
- * a specificed document.
+ * Look to see if this aggregation of documents contains a specificed
+ * document.
*
* @param doc
* @return
@@ -47,10 +51,27 @@
/**
* Add a document to the aggregated documents list.
+ *
* @param doc
*/
public boolean add(AbstractSourceDocument doc) {
- return docs.add(doc);
+ if (doc != null) {
+ return docs.add(doc);
+ }
+ return false;
}
+ public List<AbstractSourceDocument> getDocuments() {
+ return docs;
+ }
+
+ @Override
+ public String getContentAsString() throws IOException {
+ StringBuffer sb = new StringBuffer("<aggregate>");
+ for (AbstractSourceDocument doc : docs) {
+ sb.append(doc.getContentAsString());
+ }
+ sb.append("</aggegate>");
+ return sb.toString();
+ }
}
Modified:
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/AbstractSourceNode.java
URL:
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/AbstractSourceNode.java?view=diff&rev=483309&r1=483308&r2=483309
==============================================================================
---
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/AbstractSourceNode.java
(original)
+++
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/AbstractSourceNode.java
Wed Dec 6 16:27:56 2006
@@ -44,8 +44,11 @@
setSourceURI(new URI(atts.getNamedItem("href").getNodeValue()));
final Node required = atts.getNamedItem("required");
if (required != null) {
- setRequired(required.getNodeValue().equals("true"));
+
setRequired(required.getNodeValue().toLowerCase().equals("true"));
}
+ }
+
+ public AbstractSourceNode() {
}
public boolean isRequired() {
Added:
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/AggregateNode.java
URL:
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/AggregateNode.java?view=auto&rev=483309
==============================================================================
---
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/AggregateNode.java
(added)
+++
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/AggregateNode.java
Wed Dec 6 16:27:56 2006
@@ -0,0 +1,32 @@
+package org.apache.forrest.core.locationMap;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class AggregateNode extends AbstractSourceNode {
+ List<AbstractSourceNode> nodes = new ArrayList<AbstractSourceNode>();
+
+ public AggregateNode(Node element) throws URISyntaxException,
IOException {
+ super();
+
+ final NodeList children = element.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ final Node child = children.item(i);
+ String nodeName = child.getNodeName();
+ if (nodeName != null && nodeName.equals("source")) {
+ nodes.add(new SourceNode(child));
+ }
+ }
+ }
+
+ public List<AbstractSourceNode> getNodes() {
+ return nodes;
+ }
+
+}
Propchange:
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/AggregateNode.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/LocationMap.java
URL:
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/LocationMap.java?view=diff&rev=483309&r1=483308&r2=483309
==============================================================================
---
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/LocationMap.java
(original)
+++
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/LocationMap.java
Wed Dec 6 16:27:56 2006
@@ -46,7 +46,7 @@
*/
public class LocationMap {
Logger log = Logger.getLogger(LocationMap.class);
-
+
private final Map<String, List<LocationNode>> locations = new
HashMap<String, List<LocationNode>>();
/**
@@ -98,12 +98,10 @@
}
/**
- * Get all matching sets of locations for the given URI.
- * A matching location is one that provides a source
- * location that <em>may</em> provide a source document
- * for the request. That is, the existence of the source
- * document is not checked before adding the location
- * to the results.
+ * Get all matching sets of locations for the given URI. A matching
location
+ * is one that provides a source location that <em>may</em> provide a
+ * source document for the request. That is, the existence of the source
+ * document is not checked before adding the location to the results.
*
* @param requestURI
* @return
@@ -113,7 +111,8 @@
*/
public List<List<LocationNode>> get(final URI requestURI)
throws MalformedURLException, LocationmapException {
- log.debug("Getting potential locations for request of " +
requestURI.toASCIIString());
+ log.debug("Getting potential locations for request of "
+ + requestURI.toASCIIString());
final List<List<LocationNode>> results = new
ArrayList<List<LocationNode>>();
final Set<String> locPatterns = this.locations.keySet();
for (final String pattern : locPatterns) {
@@ -121,7 +120,8 @@
if (this.isMatch(pattern, requestURI)) {
List<LocationNode> locs =
this.locations.get(pattern);
results.add(locs);
- log.info(locs.size() + " potenatial
location from pattern " + pattern);
+ log.info(locs.size() + " potenatial
location from pattern "
+ + pattern);
}
} catch (final RESyntaxException e) {
throw new LocationmapException(
Modified:
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/LocationNode.java
URL:
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/LocationNode.java?view=diff&rev=483309&r1=483308&r2=483309
==============================================================================
---
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/LocationNode.java
(original)
+++
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/LocationNode.java
Wed Dec 6 16:27:56 2006
@@ -61,6 +61,8 @@
String nodeName = child.getNodeName();
if (nodeName != null && nodeName.equals("source")) {
nodes.add(new SourceNode(child));
+ } else if (nodeName != null &&
nodeName.equals("aggregate")) {
+ nodes.add(new AggregateNode(child));
}
}
this.init(pattern, nodes);
Added:
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/plugin/AggregateInputPlugin.java
URL:
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/plugin/AggregateInputPlugin.java?view=auto&rev=483309
==============================================================================
---
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/plugin/AggregateInputPlugin.java
(added)
+++
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/plugin/AggregateInputPlugin.java
Wed Dec 6 16:27:56 2006
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.forrest.core.plugin;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.forrest.core.Controller;
+import org.apache.forrest.core.document.AbstractSourceDocument;
+import org.apache.forrest.core.document.AggregatedSourceDocument;
+import org.apache.forrest.core.document.IDocument;
+import org.apache.forrest.core.document.InternalDocument;
+import org.apache.forrest.core.exception.ProcessingException;
+
+/**
+ * The aggregate plugin iis a wrapper for other plugins. It is used to parse
+ * aggregated documents. It iterates over each of the documents within the
+ * aggregated document and delegates the processing of each one to the relevant
+ * input plugin. The resulting output document is a single Forrest internal
+ * document that contains the body of each of the component documents.
+ *
+ */
+public class AggregateInputPlugin extends AbstractInputPlugin {
+
+ public AggregateInputPlugin() {
+ super();
+ }
+
+ public IDocument process(final Controller controller,
+ final IDocument aggregateDoc) throws IOException,
ProcessingException {
+ StringBuffer sb = new StringBuffer(getDocumentHeader());
+ for (AbstractSourceDocument doc : ((AggregatedSourceDocument)
aggregateDoc)
+ .getDocuments()) {
+ AbstractInputPlugin inputPlugin =
controller.getInputPlugin(doc);
+ IDocument internalDoc = inputPlugin.process(controller,
doc);
+ String content = internalDoc.getContentAsString();
+ int startPos = content.toLowerCase().indexOf("<body>");
+ int endPos = content.toLowerCase().indexOf("</body>");
+ if (startPos > -1 && endPos > -1) {
+ sb.append(content.substring(startPos + 6,
endPos - 1));
+ } else {
+ throw new ProcessingException("Invalid document
in the aggregate collection");
+ }
+ }
+ sb.append(getDocumentFooter());
+
+ return new InternalDocument(aggregateDoc.getRequestURI(),
sb.toString());
+ }
+
+ private CharSequence getDocumentHeader() {
+ return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<html
xmlns=\"http://www.w3.org/2002/06/xhtml2\" xml:lang=\"en\"
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xsi:schemaLocation=\"http://www.w3.org/2002/06/xhtml2/
http://www.w3.org/MarkUp/SCHEMA/xhtml2.xsd\" > <head> <title>XHTML 2 Simple
Sample Page</title> </head> <body> ";
+ }
+
+ private CharSequence getDocumentFooter() {
+ return "</body></html>";
+ }
+
+ public URI getXsltURI() {
+ return null;
+ }
+}
Propchange:
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/plugin/AggregateInputPlugin.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/AggregateReader.java
URL:
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/AggregateReader.java?view=auto&rev=483309
==============================================================================
---
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/AggregateReader.java
(added)
+++
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/AggregateReader.java
Wed Dec 6 16:27:56 2006
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.forrest.core.reader;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+
+import org.apache.forrest.core.IController;
+import org.apache.forrest.core.document.AbstractSourceDocument;
+import org.apache.forrest.core.document.AggregatedSourceDocument;
+import org.apache.forrest.core.document.DefaultSourceDocument;
+import org.apache.forrest.core.exception.ProcessingException;
+import org.apache.forrest.core.locationMap.AbstractSourceNode;
+import org.apache.forrest.core.locationMap.AggregateNode;
+import org.apache.forrest.core.matcher.AbstractMatcher;
+
+/**
+ * An AggregateReader reader is a wrapper for other readers. It is not intended
+ * to be used directly by the user, instead the Controller will use it whenever
+ * an aggregate document is required. This reader will iterate over all sources
+ * in the aggregate document and will delegate to the relevant reader to get
the
+ * source document from each location.
+ *
+ */
+public class AggregateReader extends AbstractReader {
+
+ public AbstractSourceDocument read(IController controller, URI
requestURI,
+ final AbstractSourceNode sourceNode, AbstractMatcher
matcher)
+ throws ProcessingException {
+ AggregatedSourceDocument doc = new
AggregatedSourceDocument(requestURI);
+ AggregateNode aggregateNode = (AggregateNode) sourceNode;
+ for (AbstractSourceNode node : aggregateNode.getNodes()) {
+ IReader reader = (IReader) controller.getReader(node);
+ try {
+ doc.add((DefaultSourceDocument)
reader.read(controller,
+ requestURI, node, matcher));
+ } catch (MalformedURLException e) {
+ throw new ProcessingException(e.getMessage(),
e);
+ }
+ }
+ return doc;
+ }
+
+}
Propchange:
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/AggregateReader.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: forrest/trunk/whiteboard/forrest2/core/src/test/locationmap.xml
URL:
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/forrest2/core/src/test/locationmap.xml?view=diff&rev=483309&r1=483308&r2=483309
==============================================================================
--- forrest/trunk/whiteboard/forrest2/core/src/test/locationmap.xml (original)
+++ forrest/trunk/whiteboard/forrest2/core/src/test/locationmap.xml Wed Dec 6
16:27:56 2006
@@ -37,4 +37,13 @@
<source href="classpath:/xdocs/samples/xhtml2/DOES_NOT_EXIST.html"
required="true"/>
<source href="classpath:/xdocs/samples/xhtml2/$(2).html"/>
</location>
+
+ <location regexp="(.*)/aggregate/(.*)\..*">
+ <aggregate>
+ <source href="classpath:/xdocs/samples/xhtml2/second_sample.html"/>
+ <source href="classpath:/xdocs/samples/xhtml2/DOES_NOT_EXIST.html"
required="false"/>
+ <source href="classpath:/xdocs/samples/xhtml2/$(2).html"/>
+ </aggregate>
+ </location>
+
</locationmap>