Author: rgardler
Date: Mon Dec  4 16:34:50 2006
New Revision: 482430

URL: http://svn.apache.org/viewvc?view=rev&rev=482430
Log:
@refactor abstract out handling of various nodes in the locationmap
@refactor use a matcher class for prossing pattern matching

Added:
    
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/AbstractSourceNode.java
   (with props)
    
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/LocationNode.java
      - copied, changed from r482324, 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/Location.java
    
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/SourceNode.java
   (with props)
    
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/matcher/
    
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/matcher/AbstractMatcher.java
   (with props)
    
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/matcher/REMatcher.java
   (with props)
Removed:
    
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/Location.java
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/locationMap/LocationMap.java
    
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/ChainedReader.java
    
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/FileReader.java
    
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/HTTPReader.java
    
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/IReader.java
    
forrest/trunk/whiteboard/forrest2/core/src/test/org/apache/forrest/test/core/TestController.java

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=482430&r1=482429&r2=482430
==============================================================================
--- 
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
 Mon Dec  4 16:34:50 2006
@@ -35,7 +35,8 @@
 import org.apache.forrest.core.document.InternalErrorDocument;
 import org.apache.forrest.core.exception.LocationmapException;
 import org.apache.forrest.core.exception.ProcessingException;
-import org.apache.forrest.core.locationMap.Location;
+import org.apache.forrest.core.locationMap.AbstractSourceNode;
+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.BaseOutputPlugin;
@@ -67,7 +68,7 @@
 
        Logger log = Logger.getLogger(Controller.class);
 
-       private final Map<URI, List<Location>> sourceLocationsCache = new 
HashMap<URI, List<Location>>();
+       private final Map<URI, List<LocationNode>> sourceLocationsCache = new 
HashMap<URI, List<LocationNode>>();
 
        private final Map<URI, AbstractSourceDocument> sourceDocsCache = new 
HashMap<URI, AbstractSourceDocument>();
 
@@ -151,7 +152,7 @@
         */
        private AbstractOutputDocument processRequest(final URI requestURI)
                        throws IOException, LocationmapException, 
ProcessingException {
-               final List<Location> sourceLocs = this
+               final List<LocationNode> sourceLocs = this
                                .resolveSourceLocations(requestURI);
                this.sourceLocationsCache.put(requestURI, sourceLocs);
 
@@ -266,13 +267,13 @@
         * @fixme resource handlers should be provided from a factory class
         */
        private List<AbstractSourceDocument> loadAllSourceDocuments(URI 
requestURI,
-                       final List<Location> sourceLocations) throws 
MalformedURLException,
+                       final List<LocationNode> sourceLocations) throws 
MalformedURLException,
                        ProcessingException {
                final List<AbstractSourceDocument> results = new 
ArrayList<AbstractSourceDocument>(
                                sourceLocations.size());
 
                for (int i = 0; i < sourceLocations.size(); i++) {
-                       final Location location = sourceLocations.get(i);
+                       final LocationNode location = sourceLocations.get(i);
                        AbstractSourceDocument doc = 
loadSourceDocument(requestURI,
                                        location);
                        results.add(doc);
@@ -281,13 +282,13 @@
        }
 
        private AbstractSourceDocument loadSourceDocument(URI requestURI,
-                       final Location location) throws ProcessingException,
+                       final LocationNode location) throws ProcessingException,
                        MalformedURLException {
                AbstractSourceDocument doc = sourceDocsCache.get(requestURI);
                if (doc == null) {
-                       for (URI uri : location.getSourceURIs()) {
-                               IReader reader = getReader(uri);
-                               doc = reader.read(this, requestURI, location, 
uri);
+                       for (AbstractSourceNode node : 
location.getSourceNodes()) {
+                               IReader reader = getReader(node.getSourceURI());
+                               doc = reader.read(this, requestURI, node, 
location.getMatcher());
                                if (doc != null) {
                                        addToSourceDocCache(requestURI, doc);
                                        break;
@@ -311,7 +312,7 @@
        /*
         * (non-Javadoc)
         * 
-        * @see 
org.apache.forrest.core.IController#getReader(org.apache.forrest.core.locationMap.Location)
+        * @see 
org.apache.forrest.core.IController#getReader(org.apache.forrest.core.locationMap.LocationNode)
         */
        public IReader getReader(final URI uri) throws ProcessingException {
                IReader reader;
@@ -343,36 +344,27 @@
         * @throws ProcessingException
         * @FIXME handle fall through if the first location is not correct
         */
-       private List<Location> resolveSourceLocations(final URI requestURI)
+       private List<LocationNode> resolveSourceLocations(final URI requestURI)
                        throws LocationmapException, MalformedURLException,
                        ProcessingException {
-               final List<List<Location>> possibleLocs = this.locationMap
+               final List<List<LocationNode>> possibleLocs = this.locationMap
                                .get(requestURI);
                if (possibleLocs == null || possibleLocs.size() == 0)
                        throw new LocationmapException(
                                        "Unable to find a source location for " 
+ requestURI);
 
-               List<Location> result = new ArrayList<Location>();
+               List<LocationNode> result = new ArrayList<LocationNode>();
                Boolean isValid = false;
-               for (List<Location> locs : possibleLocs) {
-                       result = new ArrayList<Location>();
+               for (List<LocationNode> locs : possibleLocs) {
+                       result = new ArrayList<LocationNode>();
                        isValid = true;
-                       Iterator<Location> sourceLocs = locs.iterator();
-                       Location loc;
+                       Iterator<LocationNode> sourceLocs = locs.iterator();
+                       LocationNode loc;
                        while (sourceLocs.hasNext() && isValid) {
                                loc = sourceLocs.next();
                                if (sourceExists(requestURI, loc)) {
                                        result.add(loc);
                                        log.debug("Found valid location");
-                               } else {
-                                       if (loc.isRequired()) {
-                                               isValid = false;
-                                               log
-                                                               .debug("Can't 
use this set of locations because one is required: "
-                                                                               
+ loc.toString());
-                                       } else {
-                                               log.debug("Can't find file for 
" + loc.toString());
-                                       }
                                }
                        }
                        if (isValid)
@@ -395,7 +387,7 @@
         * @throws MalformedURLException
         * @TODO we need a more efficient test for existence.
         */
-       private boolean sourceExists(URI requestURI, Location location)
+       private boolean sourceExists(URI requestURI, LocationNode location)
                        throws MalformedURLException, ProcessingException {
                AbstractSourceDocument doc = loadSourceDocument(requestURI, 
location);
                return doc != null;
@@ -406,9 +398,9 @@
         * 
         * @see 
org.apache.forrest.core.IController#getSourceLocations(java.net.URI)
         */
-       public List<Location> getSourceLocations(final URI requestURI)
+       public List<LocationNode> getSourceLocations(final URI requestURI)
                        throws IOException, LocationmapException, 
ProcessingException {
-               List<Location> locs = this.sourceLocationsCache.get(requestURI);
+               List<LocationNode> locs = 
this.sourceLocationsCache.get(requestURI);
                if (locs == null) {
                        this.processRequest(requestURI);
                        locs = this.sourceLocationsCache.get(requestURI);

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=482430&r1=482429&r2=482430
==============================================================================
--- 
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
 Mon Dec  4 16:34:50 2006
@@ -10,7 +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.Location;
+import org.apache.forrest.core.locationMap.LocationNode;
 import org.apache.forrest.core.plugin.AbstractInputPlugin;
 import org.apache.forrest.core.plugin.BaseOutputPlugin;
 import org.apache.forrest.core.reader.IReader;
@@ -46,7 +46,7 @@
         * @throws LocationmapException
         * @throws ProcessingException
         */
-       public abstract List<Location> getSourceLocations(final URI requestURI)
+       public abstract List<LocationNode> getSourceLocations(final URI 
requestURI)
                        throws IOException, LocationmapException, 
ProcessingException;
 
        /**

Added: 
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=auto&rev=482430
==============================================================================
--- 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/AbstractSourceNode.java
 (added)
+++ 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/AbstractSourceNode.java
 Mon Dec  4 16:34:50 2006
@@ -0,0 +1,141 @@
+package org.apache.forrest.core.locationMap;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.forrest.core.exception.ProcessingException;
+import org.apache.forrest.core.matcher.AbstractMatcher;
+import org.apache.log4j.Logger;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import com.sun.org.apache.regexp.internal.RE;
+import com.sun.org.apache.regexp.internal.RESyntaxException;
+
+/**
+ * A Source Node represents a single possible source or, in the case of an
+ * aggregated node a collection of possible source nodes.
+ * 
+ */
+public abstract class AbstractSourceNode {
+
+       Logger log = Logger.getLogger(AbstractSourceNode.class);
+
+       private boolean isRequired;
+
+       private URI sourceURI;
+
+       /**
+        * Construct a new LocationNode from an XML node.
+        * 
+        * @param element
+        * @throws URISyntaxException
+        * @throws IOException
+        */
+       public AbstractSourceNode(final Node element) throws URISyntaxException,
+                       IOException {
+               final NamedNodeMap atts = element.getAttributes();
+               setSourceURI(new URI(atts.getNamedItem("href").getNodeValue()));
+               final Node required = atts.getNamedItem("required");
+               if (required != null) {
+                       setRequired(required.getNodeValue().equals("true"));
+               }
+       }
+
+       public boolean isRequired() {
+               return this.isRequired;
+       }
+
+       public void setRequired(final boolean isRequired) {
+               this.isRequired = isRequired;
+       }
+
+       /**
+        * 
+        * @param sourceURI
+        * @return
+        * @throws ProcessingException -
+        *             if the path to the resource cannot be resolved
+        */
+       private URL resolveClasspathURI(final URI sourceURI)
+                       throws ProcessingException {
+               URL resourceURL;
+               resourceURL = this.getClass().getResource(sourceURI.getPath());
+               if (resourceURL == null)
+                       throw new ProcessingException(
+                                       "Cannot find the classpath resource: " 
+ sourceURI);
+               return resourceURL;
+       }
+
+       public String toString() {
+               StringBuffer sb = new StringBuffer();
+               if (isRequired()) {
+                       sb.append("Required ");
+               } else {
+                       sb.append("Optional ");
+               }
+               sb.append("Source URI: ");
+               sb.append(this.getSourceURI());
+               return sb.toString();
+       }
+
+       /**
+        * Resolve the supplied URI and return a URL that can be used to 
attempt to
+        * retrieve the resource. A resolved uri has all variables substituted 
with
+        * their values.
+        * 
+        * @param requestURI -
+        *            the full request URI
+        * @return
+        * @throws MalformedURLException
+        * @throws ProcessingException
+        */
+       public URL resolveURL(AbstractMatcher matcher, URI requestURI)
+                       throws MalformedURLException, ProcessingException {
+               URI uri = matcher.substituteVariables(requestURI, 
getSourceURI());
+
+               URL resolvedURL;
+               if (uri.getScheme().equals("classpath")) {
+                       resolvedURL = resolveClasspathURI(uri);
+               } else {
+                       try {
+                               String strURI = uri.getSchemeSpecificPart();
+                               if (strURI.contains(":")) {
+                                       String subProtocol = 
strURI.substring(0, strURI
+                                                       .lastIndexOf(':'));
+                                       uri = new 
URI(strURI.substring(strURI.lastIndexOf(':') + 1));
+                                       if (subProtocol.equals("classpath")) {
+                                               resolvedURL = 
resolveClasspathURI(uri);
+                                       } else {
+                                               URI subURI;
+                                               subURI = new URI(subProtocol, 
uri
+                                                               
.getSchemeSpecificPart(), null);
+                                               resolvedURL = subURI.toURL();
+                                       }
+                               } else {
+                                       resolvedURL = uri.toURL();
+                               }
+                       } catch (URISyntaxException e) {
+                               throw new MalformedURLException(
+                                               "Unable to work out sub 
protocol URI");
+                       }
+               }
+               return resolvedURL;
+
+       }
+
+       public URI getSourceURI() {
+               return sourceURI;
+       }
+
+       public void setSourceURI(URI sourceURI) {
+               this.sourceURI = sourceURI;
+       }
+
+}

Propchange: 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/AbstractSourceNode.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=482430&r1=482429&r2=482430
==============================================================================
--- 
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
 Mon Dec  4 16:34:50 2006
@@ -47,7 +47,7 @@
 public class LocationMap {
        Logger log = Logger.getLogger(LocationMap.class);
        
-       private final Map<String, List<Location>> locations = new 
HashMap<String, List<Location>>();
+       private final Map<String, List<LocationNode>> locations = new 
HashMap<String, List<LocationNode>>();
 
        /**
         * Create a new locationmap, configured by the file at the given path 
within
@@ -74,7 +74,7 @@
                for (int i = 0; i < nodes.getLength(); i++) {
                        final Node element = nodes.item(i);
                        if (element.getNodeName().equals("location")) {
-                               Location loc = new Location(element);
+                               LocationNode loc = new LocationNode(element);
                                this.put(loc);
                                log.debug("Adding " + loc.toString());
                        }
@@ -87,14 +87,14 @@
         * @param requestURI
         * @param location
         */
-       public void put(final Location location) {
-               List<Location> sourceLocations = this.locations.get(location
-                               .getRequestPattern());
+       public void put(final LocationNode location) {
+               List<LocationNode> sourceLocations = this.locations.get(location
+                               .getMatcher().getPattern());
                if (sourceLocations == null)
-                       sourceLocations = new ArrayList<Location>();
+                       sourceLocations = new ArrayList<LocationNode>();
                if (sourceLocations.contains(location) == false)
                        sourceLocations.add(location);
-               this.locations.put(location.getRequestPattern(), 
sourceLocations);
+               this.locations.put(location.getMatcher().getPattern(), 
sourceLocations);
        }
 
        /**
@@ -111,15 +111,15 @@
         *             if the Request URI is invalid
         * @throws LocationmapException
         */
-       public List<List<Location>> get(final URI requestURI)
+       public List<List<LocationNode>> get(final URI requestURI)
                        throws MalformedURLException, LocationmapException {
                log.debug("Getting potential locations for request of " + 
requestURI.toASCIIString());
-               final List<List<Location>> results = new 
ArrayList<List<Location>>();
+               final List<List<LocationNode>> results = new 
ArrayList<List<LocationNode>>();
                final Set<String> locPatterns = this.locations.keySet();
                for (final String pattern : locPatterns) {
                        try {
                                if (this.isMatch(pattern, requestURI)) {
-                                       List<Location> locs = 
this.locations.get(pattern);
+                                       List<LocationNode> locs = 
this.locations.get(pattern);
                                        results.add(locs);
                                        log.info(locs.size() + " potenatial 
location from pattern " + pattern);
                                }

Copied: 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/LocationNode.java
 (from r482324, 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/Location.java)
URL: 
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/LocationNode.java?view=diff&rev=482430&p1=forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/Location.java&r1=482324&p2=forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/LocationNode.java&r2=482430
==============================================================================
--- 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/Location.java
 (original)
+++ 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/LocationNode.java
 Mon Dec  4 16:34:50 2006
@@ -17,58 +17,42 @@
 package org.apache.forrest.core.locationMap;
 
 import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URI;
 import java.net.URISyntaxException;
-import java.net.URL;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.forrest.core.exception.ProcessingException;
+import org.apache.forrest.core.matcher.AbstractMatcher;
+import org.apache.forrest.core.matcher.REMatcher;
 import org.apache.log4j.Logger;
 import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
-import com.sun.org.apache.regexp.internal.RE;
-import com.sun.org.apache.regexp.internal.RESyntaxException;
-
 /**
  * A location is a possible source location for a given request URI. There may
  * be more than one location for any request URI, each of the possible 
locations
  * may be optional or requried.
  * 
  */
-public class Location {
-
-       Logger log = Logger.getLogger(Location.class);
-
-       private String requestPattern;
-
-       private boolean isRequired;
+public class LocationNode {
 
-       private List<URI> sourceURIs;
-
-       public Location(final String pattern, final URL sourceURL,
-                       final boolean isRequired) throws URISyntaxException {
-               List<URI> uris = new ArrayList<URI>();
-               uris.add(sourceURL.toURI());
-               this.init(pattern, uris, isRequired);
-       }
+       Logger log = Logger.getLogger(LocationNode.class);
+       
+       private AbstractMatcher matcher;
+       
+       private List<AbstractSourceNode> sourceNodes;
 
        /**
-        * Construct a new Location from an XML node.
+        * Construct a new LocationNode from an XML node.
         * 
         * @param element
         * @throws URISyntaxException
         * @throws IOException
         */
-       public Location(final Node element) throws URISyntaxException, 
IOException {
+       public LocationNode(final Node element) throws URISyntaxException, 
IOException {
                String pattern = null;
-               String url = null;
-               List<URI> uris = new ArrayList<URI>();
-               boolean isRequired = false;
-
+               List<AbstractSourceNode> nodes = new 
ArrayList<AbstractSourceNode>();
+               
                final NamedNodeMap atts = element.getAttributes();
                pattern = atts.getNamedItem("regexp").getNodeValue();
                final NodeList children = element.getChildNodes();
@@ -76,184 +60,46 @@
                        final Node child = children.item(i);
                        String nodeName = child.getNodeName();
                        if (nodeName != null && nodeName.equals("source")) {
-                               url = 
child.getAttributes().getNamedItem("href").getNodeValue();
-                               final Node required = 
child.getAttributes().getNamedItem(
-                                               "required");
-                               if (required != null) {
-                                       isRequired = 
required.getNodeValue().equals("true");
-                               }
-                               uris.add(new URI(url));
+                               nodes.add(new SourceNode(child));
                        }
                }
-               this.init(pattern, uris, isRequired);
+               this.init(pattern, nodes);
        }
 
-       private void init(final String pattern, final List<URI> uris,
-                       final boolean isRequired) throws URISyntaxException {
+       private void init(final String pattern, final List<AbstractSourceNode> 
nodes) throws URISyntaxException {
                if (pattern == null)
                        throw new IllegalArgumentException(
                                        "requestURIPattern cannot be null");
-               if (uris == null || uris.size() == 0)
+               if (nodes == null || nodes.size() == 0)
                        throw new IllegalArgumentException(
-                                       "There must be at least one potential 
source uri");
-               this.setRequestPattern(pattern);
-               this.setSourceURIs(uris);
-               this.setRequired(isRequired);
-       }
-
-       public boolean isRequired() {
-               return this.isRequired;
-       }
-
-       public void setRequired(final boolean isRequired) {
-               this.isRequired = isRequired;
-       }
-
-       public String getRequestPattern() {
-               return this.requestPattern;
+                                       "There must be at least one source node 
for a location");
+               this.setMatcher(new REMatcher(pattern));
+               this.setSourceNodes(nodes);
        }
 
-       public void setRequestPattern(final String pattern) {
-               this.requestPattern = pattern;
-       }
-
-       /**
-        * Get the source URLs, that may be used to read the source document. A
-        * source URL is the sourceURI modified appropriately for the given 
request.
-        * Note that the resulting list of URLs have not been verified with 
respect
-        * to the existence of a document, it is only a potential location.
-        * 
-        * @return
-        * @throws MalformedURLException
-        * @throws ProcessingException
-        */
-       public List<URL> getResolvedSourceURL(URI requestURI)
-                       throws MalformedURLException, ProcessingException {
-               List<URL> resolvedUrls = new ArrayList<URL>();
-               for (URI sourceURI : getSourceURIs()) {
-                       resolvedUrls.add(resolveURL(requestURI, sourceURI));
-               }
-               return resolvedUrls;
-       }
-
-       /**
-        * 
-        * @param sourcePath
-        * @return
-        * @throws ProcessingException - if the path to the resource cannot be 
resolved
-        */
-       private URL resolveClasspathURI(final String sourcePath)
-                       throws ProcessingException {
-               URL resourceURL;
-               resourceURL = this.getClass().getResource(sourcePath);
-               if (resourceURL == null)
-                       throw new ProcessingException(
-                                       "Cannot find the classpath resource: " 
+ sourcePath);
-               return resourceURL;
-       }
-
-       public List<URI> getSourceURIs() {
-               return this.sourceURIs;
-       }
-
-       /**
-        * Set the list of potential source URIs for this document.
-        * 
-        * @param sourceURI
-        */
-       public void setSourceURIs(final List<URI> sourceURIs) {
-               this.sourceURIs = sourceURIs;
-       }
-       
        public String toString() {
                StringBuffer sb = new StringBuffer();
-               if (isRequired()) {
-                       sb.append("Required ");
-               } else {
-                       sb.append("Optional ");
-               }
                sb.append("location: ");
-               sb.append("Pattern: ");
-               sb.append(this.getRequestPattern());
-               sb.append(" Potential sourceURIs: ");
-               for (URI uri : getSourceURIs()) {
-                 sb.append(uri.toASCIIString());
-                 sb.append(" ");
-               }
-
+               sb.append("Matcher:");
+               sb.append(this.getMatcher().toString());
+               
                return sb.toString();
        }
 
-       /**
-        * Resolve the supplied URI and return a URL that can
-        * be used to attempt to retrieve the resource. A resolved
-        * uri has all variables substituted with their values.
-        * 
-        * @param sourceURI
-        * @return
-        * @throws MalformedURLException 
-        * @throws ProcessingException 
-        */
-       public URL resolveURL(URI requestURI, URI sourceURI) throws 
MalformedURLException, ProcessingException {
-               URL url;
-               RE r;
-
-               try {
-                       r = new RE(getRequestPattern());
-               } catch (RESyntaxException re) {
-                       throw new ProcessingException(
-                                       "Unable to extract variable values from 
request: "
-                                                       + re.getMessage(), re);
-               }
-               
-               String urlString = requestURI.getPath();
+       public List<AbstractSourceNode> getSourceNodes() {
+               return sourceNodes;
+       }
 
-                       String sourceSSP = sourceURI.getSchemeSpecificPart();
+       public void setSourceNodes(List<AbstractSourceNode> sourceNodes) {
+               this.sourceNodes = sourceNodes;
+       }
 
-                       if (r.match(urlString)) {
-                               String variable;
-                               String value;
-                               for (int i = 0; i < r.getParenCount(); i++) {
-                                       variable = "$(" + i + ")";
-                                       value = r.getParen(i);
-                                       if (value != null) {
-                                               sourceSSP = 
sourceSSP.replace(variable, value);
-                                       }
-                               }
-                               log.debug("After variable substitution a 
potential source path is "
-                                               + sourceSSP);
-                       } else {
-                               throw new ProcessingException(
-                                               "Unable to extract variable 
values from requestURI");
-                       }
+       public AbstractMatcher getMatcher() {
+               return matcher;
+       }
 
-                       URL resolvedURL;
-                       if (sourceURI.getScheme().equals("classpath")) {
-                               resolvedURL = resolveClasspathURI(sourceSSP);
-                       } else {
-                               String strURI = 
sourceURI.getSchemeSpecificPart();
-                               if (strURI.contains(":")) {
-                                       String subProtocol = 
strURI.substring(0, strURI
-                                                       .lastIndexOf(':'));
-                                       sourceSSP = 
strURI.substring(strURI.lastIndexOf(':') + 1);
-                                       if (subProtocol.equals("classpath")) {
-                                               resolvedURL = 
resolveClasspathURI(sourceSSP);
-                                       } else {
-                                               URI subURI;
-                                               try {
-                                                       subURI = new 
URI(subProtocol, sourceSSP, null);
-                                                       resolvedURL = 
subURI.toURL();
-                                               } catch (URISyntaxException e) {
-                                                       throw new 
MalformedURLException(
-                                                                       "Unable 
to work out sub protocol URI");
-                                               }
-                                       }
-                               } else {
-                                       resolvedURL = sourceURI.toURL();
-                               }
-                       }
-                       return resolvedURL;
-               
+       public void setMatcher(AbstractMatcher matcher) {
+               this.matcher = matcher;
        }
 
 }

Added: 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/SourceNode.java
URL: 
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/SourceNode.java?view=auto&rev=482430
==============================================================================
--- 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/SourceNode.java
 (added)
+++ 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/SourceNode.java
 Mon Dec  4 16:34:50 2006
@@ -0,0 +1,36 @@
+/*
+ * 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.locationMap;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+
+import org.w3c.dom.Node;
+
+/**
+ * A location is a possible source location for a given request URI. There may
+ * be more than one location for any request URI, each of the possible 
locations
+ * may be optional or requried.
+ * 
+ */
+public class SourceNode extends AbstractSourceNode {
+
+       public SourceNode(Node element) throws URISyntaxException, IOException {
+               super(element);
+       }
+       
+}

Propchange: 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/locationMap/SourceNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/matcher/AbstractMatcher.java
URL: 
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/matcher/AbstractMatcher.java?view=auto&rev=482430
==============================================================================
--- 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/matcher/AbstractMatcher.java
 (added)
+++ 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/matcher/AbstractMatcher.java
 Mon Dec  4 16:34:50 2006
@@ -0,0 +1,46 @@
+package org.apache.forrest.core.matcher;
+
+import java.net.URI;
+import java.net.URL;
+
+import org.apache.forrest.core.exception.ProcessingException;
+
+
+/**
+ * A matcher is used to match a pattern against a given 
+ * string. 
+ *
+ */
+public abstract class AbstractMatcher {
+       
+       String pattern;
+
+       /**
+        * Get the pattern used by this mathcer.
+        * The syntax of the pattern is dependant on the
+        * implementation of the matcher.
+        * @return
+        */
+       public String getPattern() {
+               return pattern;
+       }
+
+       /**
+        * Set the pattern used by this mathcer.
+        * The syntax of the pattern is dependant on the
+        * implementation of the matcher.
+        * @param pattern
+        */
+       public void setPattern(String pattern) {
+               this.pattern = pattern;
+       }
+
+       /**
+        * Perform any necessary variable substitution in the
+        * supplied sourceURI using the given requestURI to find
+        * values for variables.
+        * @throws ProcessingException 
+        * 
+        */
+       public abstract URI substituteVariables(URI requestURI, URI sourceURI) 
throws ProcessingException;
+}

Propchange: 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/matcher/AbstractMatcher.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/matcher/REMatcher.java
URL: 
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/matcher/REMatcher.java?view=auto&rev=482430
==============================================================================
--- 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/matcher/REMatcher.java
 (added)
+++ 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/matcher/REMatcher.java
 Mon Dec  4 16:34:50 2006
@@ -0,0 +1,78 @@
+package org.apache.forrest.core.matcher;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+import org.apache.forrest.core.exception.ProcessingException;
+import org.apache.forrest.core.locationMap.AbstractSourceNode;
+import org.apache.log4j.Logger;
+
+import com.sun.org.apache.regexp.internal.RE;
+import com.sun.org.apache.regexp.internal.RESyntaxException;
+
+/**
+ * An REMatcher uses a regular expression to define a match.
+ * 
+ */
+public class REMatcher extends AbstractMatcher {
+
+       Logger log = Logger.getLogger(REMatcher.class);
+
+       /**
+        * Create an REMatcher using the supplied Regular Expression.
+        * 
+        * @param pattern
+        */
+       public REMatcher(String re) {
+               this.setPattern(re);
+       }
+
+       @Override
+       public URI substituteVariables(URI requestURI, URI sourceURI)
+                       throws ProcessingException {
+               URL url;
+               RE r;
+
+               try {
+                       r = new RE(getPattern());
+               } catch (RESyntaxException re) {
+                       throw new ProcessingException(
+                                       "Unable to extract variable values from 
request: "
+                                                       + re.getMessage(), re);
+               }
+
+               String urlString = requestURI.getPath();
+
+               String sourceSSP = sourceURI.getSchemeSpecificPart();
+
+               if (r.match(urlString)) {
+                       String variable;
+                       String value;
+                       for (int i = 0; i < r.getParenCount(); i++) {
+                               variable = "$(" + i + ")";
+                               value = r.getParen(i);
+                               if (value != null) {
+                                       sourceSSP = sourceSSP.replace(variable, 
value);
+                               }
+                       }
+                       log.debug("After variable substitution a potential 
source path is "
+                                       + sourceSSP);
+               } else {
+                       throw new ProcessingException(
+                                       "Unable to extract variable values from 
requestURI");
+               }
+
+               URI newURI;
+               try {
+                       newURI = new URI(sourceURI.getScheme(), sourceSSP, 
null);
+               } catch (URISyntaxException e) {
+                       throw new ProcessingException(
+                                       "Unable to perform variable 
substitution on the source uri "
+                                                       + sourceURI + " cuased 
by " + e.getMessage(), e);
+               }
+               return newURI;
+       }
+
+}

Propchange: 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/matcher/REMatcher.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/ChainedReader.java
URL: 
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/ChainedReader.java?view=diff&rev=482430&r1=482429&r2=482430
==============================================================================
--- 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/ChainedReader.java
 (original)
+++ 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/ChainedReader.java
 Mon Dec  4 16:34:50 2006
@@ -24,7 +24,9 @@
 import org.apache.forrest.core.document.AbstractSourceDocument;
 import org.apache.forrest.core.document.DefaultSourceDocument;
 import org.apache.forrest.core.exception.ProcessingException;
-import org.apache.forrest.core.locationMap.Location;
+import org.apache.forrest.core.locationMap.AbstractSourceNode;
+import org.apache.forrest.core.locationMap.LocationNode;
+import org.apache.forrest.core.matcher.AbstractMatcher;
 
 /**
  * A chained reader implements a psuedo protocol. It is commonly used when you
@@ -55,28 +57,26 @@
        private String docType;
 
        public AbstractSourceDocument read(IController controller, URI 
requestURI,
-                       final Location location, URI sourceURI) throws 
ProcessingException {
+                       final AbstractSourceNode sourceNode, AbstractMatcher 
matcher)
+                       throws ProcessingException {
                DefaultSourceDocument doc = null;
-               for (URI psuedoURI: location.getSourceURIs()) {
-                       final String ssp = psuedoURI.getSchemeSpecificPart();
-                       URI subSourceURI;
-                       try {
-                               subSourceURI = new URI(ssp);
-                               IReader reader;
-                               reader = (IReader) 
controller.getReader(subSourceURI);
-                               doc = (DefaultSourceDocument) 
reader.read(controller,
-                                               requestURI, location, 
subSourceURI);
-                               if (doc != null) {
-                                       doc.setType(getDocType());
-                                       break;
-                               }
-                       } catch (final URISyntaxException e) {
-                               // TODO Auto-generated catch block
-                               e.printStackTrace();
-                       } catch (MalformedURLException e) {
-                               // TODO Auto-generated catch block
-                               e.printStackTrace();
+               final String ssp = 
sourceNode.getSourceURI().getSchemeSpecificPart();
+               URI subSourceURI;
+               try {
+                       subSourceURI = new URI(ssp);
+                       IReader reader;
+                       reader = (IReader) controller.getReader(subSourceURI);
+                       doc = (DefaultSourceDocument) reader.read(controller, 
requestURI,
+                                       sourceNode, matcher);
+                       if (doc != null) {
+                               doc.setType(getDocType());
                        }
+               } catch (final URISyntaxException e) {
+                       // TODO Auto-generated catch block
+                       e.printStackTrace();
+               } catch (MalformedURLException e) {
+                       // TODO Auto-generated catch block
+                       e.printStackTrace();
                }
                return doc;
        }

Modified: 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/FileReader.java
URL: 
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/FileReader.java?view=diff&rev=482430&r1=482429&r2=482430
==============================================================================
--- 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/FileReader.java
 (original)
+++ 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/FileReader.java
 Mon Dec  4 16:34:50 2006
@@ -26,7 +26,9 @@
 import org.apache.forrest.core.document.AbstractSourceDocument;
 import org.apache.forrest.core.document.DocumentFactory;
 import org.apache.forrest.core.exception.SourceException;
-import org.apache.forrest.core.locationMap.Location;
+import org.apache.forrest.core.locationMap.AbstractSourceNode;
+import org.apache.forrest.core.locationMap.LocationNode;
+import org.apache.forrest.core.matcher.AbstractMatcher;
 
 /**
  * A File reader reads a resource using the file protocol, i.e. it will read
@@ -41,14 +43,14 @@
         * @see 
org.apache.forrest.core.reader.IReader#read(org.apache.forrest.test.core.locationMap.Location)
         */
        public AbstractSourceDocument read(IController controller, URI 
requestURI,
-                       final Location location, final URI sourceURI) {
+                       final AbstractSourceNode sourceNode, AbstractMatcher 
matcher) {
                AbstractSourceDocument result = null;
                try {
-                       URL resolvedURL = location.resolveURL(requestURI, 
sourceURI);
+                       URL resolvedURL = sourceNode.resolveURL(matcher, 
requestURI);
                        final InputStream is = new FileInputStream(new 
File(resolvedURL.toURI()));
                        result = 
DocumentFactory.getSourceDocumentFor(requestURI, is);
                } catch (final Exception e) {
-                       if (location.isRequired())
+                       if (sourceNode.isRequired())
                                throw new SourceException("Source URL is 
invalid", e);
                }
                return result;

Modified: 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/HTTPReader.java
URL: 
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/HTTPReader.java?view=diff&rev=482430&r1=482429&r2=482430
==============================================================================
--- 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/HTTPReader.java
 (original)
+++ 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/HTTPReader.java
 Mon Dec  4 16:34:50 2006
@@ -30,7 +30,9 @@
 import org.apache.forrest.core.document.DefaultSourceDocument;
 import org.apache.forrest.core.exception.ProcessingException;
 import org.apache.forrest.core.exception.SourceException;
-import org.apache.forrest.core.locationMap.Location;
+import org.apache.forrest.core.locationMap.AbstractSourceNode;
+import org.apache.forrest.core.locationMap.LocationNode;
+import org.apache.forrest.core.matcher.AbstractMatcher;
 import org.w3c.tidy.Tidy;
 
 /**
@@ -56,12 +58,12 @@
         * 
         * @see 
org.apache.forrest.core.reader.IReader#read(org.apache.forrest.test.core.locationMap.Location)
         */
-       public AbstractSourceDocument read(IController controller,
-                       final URI requestURI, final Location location, URI 
sourceURI)
+       public AbstractSourceDocument read(IController controller, URI 
requestURI,
+                       final AbstractSourceNode sourceNode, AbstractMatcher 
matcher)
                        throws MalformedURLException, ProcessingException {
                InputStream is;
                DefaultSourceDocument result = null;
-               URL resolvedURL = location.resolveURL(requestURI, sourceURI);
+               URL resolvedURL = sourceNode.resolveURL(matcher, requestURI);
                final ByteArrayOutputStream out = new ByteArrayOutputStream();
                final GetMethod get = new 
GetMethod(resolvedURL.toExternalForm());
                get.setFollowRedirects(true);
@@ -74,7 +76,7 @@
                        result = new DefaultSourceDocument(requestURI, 
out.toString());
                } catch (final Exception e) {
                        result = null;
-                       if (location.isRequired())
+                       if (sourceNode.isRequired())
                                throw new SourceException("Source URL is 
invalid", e);
                } finally {
                        get.releaseConnection();

Modified: 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/IReader.java
URL: 
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/IReader.java?view=diff&rev=482430&r1=482429&r2=482430
==============================================================================
--- 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/IReader.java
 (original)
+++ 
forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core/reader/IReader.java
 Mon Dec  4 16:34:50 2006
@@ -22,7 +22,9 @@
 import org.apache.forrest.core.IController;
 import org.apache.forrest.core.document.AbstractSourceDocument;
 import org.apache.forrest.core.exception.ProcessingException;
-import org.apache.forrest.core.locationMap.Location;
+import org.apache.forrest.core.locationMap.AbstractSourceNode;
+import org.apache.forrest.core.locationMap.LocationNode;
+import org.apache.forrest.core.matcher.AbstractMatcher;
 
 public interface IReader {
 
@@ -41,14 +43,15 @@
         * 
         * @param controller - the forrest controller in use
         * @param requestURI - the URI being requested
-        * @param uri - the uri we are to read the document from
-        * @param sourceURI - the source URI we are trying to read
+        * @param sourceNode - the source node we are trying to use to resole 
this document
+        * @param matcher - the matcher that produced this source node
         * 
         * @return
         * @throws MalformedURLException
         * @throws ProcessingException 
         */
-       public abstract AbstractSourceDocument read(IController controller, URI 
requestURI, Location location, URI sourceURI)
+       public abstract AbstractSourceDocument read(IController controller, URI 
requestURI,
+                       final AbstractSourceNode sourceNode, AbstractMatcher 
matcher)
                        throws MalformedURLException, ProcessingException;
 
 }

Modified: 
forrest/trunk/whiteboard/forrest2/core/src/test/org/apache/forrest/test/core/TestController.java
URL: 
http://svn.apache.org/viewvc/forrest/trunk/whiteboard/forrest2/core/src/test/org/apache/forrest/test/core/TestController.java?view=diff&rev=482430&r1=482429&r2=482430
==============================================================================
--- 
forrest/trunk/whiteboard/forrest2/core/src/test/org/apache/forrest/test/core/TestController.java
 (original)
+++ 
forrest/trunk/whiteboard/forrest2/core/src/test/org/apache/forrest/test/core/TestController.java
 Mon Dec  4 16:34:50 2006
@@ -32,7 +32,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.Location;
+import org.apache.forrest.core.locationMap.LocationNode;
 
 public class TestController extends TestCase {
        static final String SOURCE_DOCUMENT_XHTML2_SIMPLE = 
"/xdocs/samples/xhtml2/sample_simple.html";
@@ -83,7 +83,7 @@
 
        public void testSourceURLs() throws IOException, LocationmapException,
                        ProcessingException, URISyntaxException {
-               final List<Location> sourceURLs = this.controller
+               final List<LocationNode> sourceURLs = this.controller
                                .getSourceLocations(new URI(XHTML_REQUEST_URI));
                assertNotNull(sourceURLs);
        }
@@ -92,7 +92,7 @@
                        URISyntaxException {
                final AbstractSourceDocument document = this.controller
                                .getSourceDocuments(new URI(XHTML_REQUEST_URI));
-               assertNotNull(document);
+               assertNotNull("No document returned", document);
        }
 
        public void testInternalDocuments() throws IOException,
@@ -102,6 +102,7 @@
                final InternalDocument internalDoc = this.controller
                                .getInternalDocument(new 
URI(XHTML_REQUEST_URI));
                final AbstractSourceDocument firstSrcDoc = srcDoc;
+               assertNotNull("No internal document returned", internalDoc);
                assertFalse(firstSrcDoc.equals(internalDoc));
        }