You are viewing a plain text version of this content. The canonical link for it is here.
Posted to svn@forrest.apache.org by rg...@apache.org on 2006/11/24 01:32:15 UTC

svn commit: r478728 - in /forrest/trunk/whiteboard/forrest2/core/src/core/org/apache/forrest/core: ./ locationMap/ reader/

Author: rgardler
Date: Thu Nov 23 16:32:14 2006
New Revision: 478728

URL: http://svn.apache.org/viewvc?view=rev&rev=478728
Log:
Handle required and optional resources.
This includes a completion of the refactoring of the way 
aggregated resources will be hanled. Instead of having multiple
internal documents that are processed at the output stage we
now have an AggregatedInputDocument, so the aggregation will
be done at the input stage instead. This means we have a 
single internal document.

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/Location.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

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=478728&r1=478727&r2=478728
==============================================================================
--- 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 Thu Nov 23 16:32:14 2006
@@ -65,7 +65,7 @@
  * 
  */
 public class Controller implements IController {
-	
+
 	Logger log = Logger.getLogger(Controller.class);
 
 	private final String sourceURLExtension = ".forrestSource";
@@ -76,7 +76,7 @@
 
 	private final Map<URI, AbstractSourceDocument> sourceDocsCache = new HashMap<URI, AbstractSourceDocument>();
 
-	private final Map<URI, List<InternalDocument>> internalDocsCache = new HashMap<URI, List<InternalDocument>>();
+	private final Map<URI, InternalDocument> internalDocsCache = new HashMap<URI, InternalDocument>();
 
 	private final Map<URI, AbstractOutputDocument> outputDocCache = new HashMap<URI, AbstractOutputDocument>();
 
@@ -102,8 +102,7 @@
 		final File file = new File(contextPath);
 		if (file.exists()) {
 			log.info("Using Spring Context definition in " + contextPath);
-			this.context = new FileSystemXmlApplicationContext(file
-					.getPath());
+			this.context = new FileSystemXmlApplicationContext(file.getPath());
 		} else {
 			log.info("Using default spring context definition");
 			this.context = new ClassPathXmlApplicationContext(
@@ -151,15 +150,16 @@
 	 */
 	private AbstractOutputDocument processRequest(final URI requestURI)
 			throws IOException, LocationmapException, ProcessingException {
-		final List<Location> sourceLocs = this.resolveSourceLocations(requestURI);
+		final List<Location> sourceLocs = this
+				.resolveSourceLocations(requestURI);
 		this.sourceLocationsCache.put(requestURI, sourceLocs);
 
 		final List<AbstractSourceDocument> sourceDocs = this
 				.loadAllSourceDocuments(requestURI, sourceLocs);
 
-		final List<InternalDocument> internalDocs = this
+		final InternalDocument internalDoc = this
 				.processInputPlugins(sourceDocs);
-		this.internalDocsCache.put(requestURI, internalDocs);
+		this.internalDocsCache.put(requestURI, internalDoc);
 
 		final AbstractOutputDocument output = this
 				.processOutputPlugins(requestURI);
@@ -175,11 +175,10 @@
 	 * @throws IOException
 	 * @throws ProcessingException
 	 */
-	private List<InternalDocument> processInputPlugins(
+	private InternalDocument processInputPlugins(
 			final List<AbstractSourceDocument> sourceDocuments)
 			throws IOException, ProcessingException {
-		final List<InternalDocument> results = new ArrayList<InternalDocument>(
-				sourceDocuments.size());
+		InternalDocument result = null;
 		for (int i = 0; i < sourceDocuments.size(); i++) {
 			final AbstractSourceDocument doc = sourceDocuments.get(i);
 			if (doc == null) {
@@ -187,9 +186,9 @@
 						"No source document is available.");
 			}
 			AbstractInputPlugin plugin = getInputPlugin(doc);
-			results.add((InternalDocument) plugin.process(doc));
+			result = (InternalDocument) plugin.process(doc);
 		}
-		return results;
+		return result;
 	}
 
 	/*
@@ -218,18 +217,9 @@
 	 */
 	private AbstractOutputDocument processOutputPlugins(final URI requestURI)
 			throws ProcessingException, IOException {
-		IDocument doc = null;
-		final List<InternalDocument> intDocs = this
-				.getInternalDocuments(requestURI);
-		if (intDocs.size() > 1) {
-			doc = new AggregateInteralDocument(intDocs);
-		} else {
-			doc = intDocs.get(0);
-		}
-
+		final InternalDocument intDoc = this.getInternalDocument(requestURI);
 		BaseOutputPlugin plugin = getOutputPlugin(requestURI);
-
-		return (AbstractOutputDocument) plugin.process(doc);
+		return (AbstractOutputDocument) plugin.process(intDoc);
 	}
 
 	/*
@@ -285,9 +275,14 @@
 			MalformedURLException {
 		AbstractSourceDocument doc = sourceDocsCache.get(requestURI);
 		if (doc == null) {
-			IReader reader = getReader(location);
-			doc = reader.read(this, requestURI, location);
-			addToSourceDocCache(requestURI, doc);
+			for (URI uri : location.getSourceURIs()) {
+				IReader reader = getReader(uri);
+				doc = reader.read(this, requestURI, location, uri);
+				if (doc != null) {
+				  addToSourceDocCache(requestURI, doc);
+				  break;
+				}
+			}
 		}
 		return doc;
 	}
@@ -308,14 +303,17 @@
 	 * 
 	 * @see org.apache.forrest.core.IController#getReader(org.apache.forrest.core.locationMap.Location)
 	 */
-	public IReader getReader(final Location location)
-			throws ProcessingException {
+	public IReader getReader(final URI uri) throws ProcessingException {
 		IReader reader;
+		String scheme = uri.getScheme();
+		if (scheme.equals("classpath")) {
+			scheme = "file";
+		}
 		try {
-			reader = (IReader) this.context.getBean(location.getScheme());
+			reader = (IReader) this.context.getBean(scheme);
 		} catch (Exception e) {
-			throw new ProcessingException("Unable to get a reader for : "
-					+ location.getRequestPattern(), e);
+			throw new ProcessingException(
+					"Unable to get a reader for : " + uri, e);
 		}
 		return reader;
 	}
@@ -358,7 +356,9 @@
 				} else {
 					if (loc.isRequired()) {
 						isValid = false;
-						log.debug("Can't use this set of locations because one is required: " + loc.toString());
+						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());
 					}
@@ -430,21 +430,20 @@
 	 * 
 	 * @see org.apache.forrest.core.IController#getInternalDocuments(java.net.URI)
 	 */
-	public List<InternalDocument> getInternalDocuments(final URI requestURI)
+	public InternalDocument getInternalDocument(final URI requestURI)
 			throws ProcessingException {
-		List<InternalDocument> internalDocs = this.internalDocsCache
-				.get(requestURI);
-		if (internalDocs == null)
+		InternalDocument internalDoc = this.internalDocsCache.get(requestURI);
+		if (internalDoc == null)
 			try {
 				this.processRequest(requestURI);
-				internalDocs = this.internalDocsCache.get(requestURI);
+				internalDoc = this.internalDocsCache.get(requestURI);
 			} catch (final Exception e) {
 				throw new ProcessingException(
 						"Unable to create the internal representation of the source documents for "
 								+ requestURI.toString(), e);
 			}
 
-		return internalDocs;
+		return internalDoc;
 	}
 
 	/*
@@ -470,18 +469,14 @@
 					content.toString());
 			return output;
 		} else if (requestURI.getPath().endsWith(this.internalURLExtension)) {
-			final List<InternalDocument> docs = this
-					.getInternalDocuments(requestURI);
+			final InternalDocument doc = this.getInternalDocument(requestURI);
 			final StringBuffer content = new StringBuffer();
-			for (final InternalDocument doc : docs) {
-				try {
-					content.append(doc.getContentAsString());
-				} catch (final IOException e) {
-					content
-							.append("<error>Unable to read source document for ");
-					content.append(requestURI);
-					content.append("</error>");
-				}
+			try {
+				content.append(doc.getContentAsString());
+			} catch (final IOException e) {
+				content.append("<error>Unable to read source document for ");
+				content.append(requestURI);
+				content.append("</error>");
 			}
 			final DefaultOutputDocument output = new DefaultOutputDocument(
 					content.toString());

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=478728&r1=478727&r2=478728
==============================================================================
--- 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 Thu Nov 23 16:32:14 2006
@@ -22,7 +22,15 @@
 
 	public abstract BaseOutputPlugin getOutputPlugin(final URI requestURI);
 
-	public abstract IReader getReader(final Location location) throws ProcessingException;
+	/**
+	 * Get a reader that can be used for retrieving a resource
+	 * from a given URI.
+	 * 
+	 * @param sourceURI
+	 * @return
+	 * @throws ProcessingException
+	 */
+	public abstract IReader getReader(final URI sourceURI) throws ProcessingException;
 
 	/**
 	 * Get the source URLs for a given request URI.
@@ -58,7 +66,7 @@
 	 * @throws MalformedURLException
 	 * @throws IOException
 	 */
-	public abstract List<InternalDocument> getInternalDocuments(
+	public abstract InternalDocument getInternalDocument(
 			final URI requestURI) throws ProcessingException;
 
 	/**

Modified: 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/Location.java?view=diff&rev=478728&r1=478727&r2=478728
==============================================================================
--- 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/Location.java Thu Nov 23 16:32:14 2006
@@ -21,6 +21,8 @@
 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.log4j.Logger;
@@ -38,18 +40,20 @@
  * 
  */
 public class Location {
-	
+
 	Logger log = Logger.getLogger(Location.class);
-	
+
 	private String requestPattern;
 
 	private boolean isRequired;
 
-	private URI sourceURI;
+	private List<URI> sourceURIs;
 
 	public Location(final String pattern, final URL sourceURL,
 			final boolean isRequired) throws URISyntaxException {
-		this.init(pattern, sourceURL.toURI(), isRequired);
+		List<URI> uris = new ArrayList<URI>();
+		uris.add(sourceURL.toURI());
+		this.init(pattern, uris, isRequired);
 	}
 
 	/**
@@ -62,35 +66,39 @@
 	public Location(final Node element) throws URISyntaxException, IOException {
 		String pattern = null;
 		String url = null;
-		boolean isOptional = false;
+		List<URI> uris = new ArrayList<URI>();
+		boolean isRequired = false;
 
 		final NamedNodeMap atts = element.getAttributes();
 		pattern = atts.getNamedItem("pattern").getNodeValue();
 		final NodeList children = element.getChildNodes();
 		for (int i = 0; i < children.getLength(); i++) {
 			final Node child = children.item(i);
-			if (child.getNodeName().equals("source")) {
+			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) {
-					isOptional = required.getNodeValue().equals("false");
+					isRequired = required.getNodeValue().equals("true");
 				}
+				uris.add(new URI(url));
 			}
 		}
-		this.init(pattern, new URI(url), isOptional);
+		this.init(pattern, uris, isRequired);
 	}
 
-	private void init(final String pattern, final URI uri,
-			final boolean isOptional) throws URISyntaxException {
+	private void init(final String pattern, final List<URI> uris,
+			final boolean isRequired) throws URISyntaxException {
 		if (pattern == null)
 			throw new IllegalArgumentException(
 					"requestURIPattern cannot be null");
-		if (uri == null)
-			throw new IllegalArgumentException("sourceURI cannot be null");
+		if (uris == null || uris.size() == 0)
+			throw new IllegalArgumentException(
+					"There must be at least one postential source uri");
 		this.setRequestPattern(pattern);
-		this.setSourceURI(uri);
-		this.setRequired(this.isRequired);
+		this.setSourceURIs(uris);
+		this.setRequired(isRequired);
 	}
 
 	public boolean isRequired() {
@@ -110,114 +118,51 @@
 	}
 
 	/**
-	 * Get the source URL, that is the one to use when reading the source
-	 * document. The source URL is the sourceURI modified appropriately for the
-	 * given request.
+	 * 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 URL getResolvedSourceURL(URI requestURI)
+	public List<URL> getResolvedSourceURL(URI requestURI)
 			throws MalformedURLException, ProcessingException {
-
-		URL url;
-		try {
-			url = requestURI.toURL();
-		} catch (final IllegalArgumentException e) {
-			// we'll assume that this is not an absolute URL and therefore
-			// refers to a file
-			url = new URL("file://" + requestURI);
+		List<URL> resolvedUrls = new ArrayList<URL>();
+		for (URI sourceURI : getSourceURIs()) {
+			resolvedUrls.add(resolveURL(requestURI, sourceURI));
 		}
-		final String urlString = url.toExternalForm();
-
-		RE r;
-		String sourcePath = this.getSourceURI().getPath();
-		try {
-			r = new RE(getRequestPattern());
-		} catch (RESyntaxException re) {
-			throw new ProcessingException(
-					"Unable to extract variable values from request: "
-							+ re.getMessage(), re);
-		}
-
-		if (r.match(urlString)) {
-			String variable;
-			String value;
-			for (int i = 0; i < r.getParenCount(); i++) {
-				variable = "$(" + i + ")";
-				value = r.getParen(i);
-				sourcePath = sourcePath.replace(variable, value);
-			}
-			log.debug("After variable substitution the source path is " + sourcePath);
-		} else {
-			throw new ProcessingException(
-					"Unable to extract variable values from requestURI");
-		}
-
-		URI uri = getSourceURI();
-		URL resourceURL;
-		if (uri.getScheme().equals("classpath")) {
-			resourceURL = resolveClasspathURI(sourcePath);
-		} else {
-			String strURI = uri.getSchemeSpecificPart();
-			if (strURI.contains(":")) {
-				String subProtocol = strURI.substring(0, strURI
-						.lastIndexOf(':'));
-				sourcePath = strURI.substring(strURI.lastIndexOf(':') + 1);
-				if (subProtocol.equals("classpath")) {
-					resourceURL = resolveClasspathURI(sourcePath);
-				} else {
-					URI subURI;
-					try {
-						subURI = new URI(subProtocol, sourcePath, null);
-						resourceURL = subURI.toURL();
-					} catch (URISyntaxException e) {
-						throw new MalformedURLException(
-								"Unable to work out sub protocol URI");
-					}
-				}
-			} else {
-				resourceURL = uri.toURL();
-			}
-		}
-		return resourceURL;
+		return resolvedUrls;
 	}
 
+	/**
+	 * 
+	 * @param sourcePath
+	 * @return
+	 * @throws ProcessingException - if the path to the resource cannot be resolved
+	 */
 	private URL resolveClasspathURI(final String sourcePath)
-			throws MalformedURLException {
+			throws ProcessingException {
 		URL resourceURL;
 		resourceURL = this.getClass().getResource(sourcePath);
 		if (resourceURL == null)
-			throw new MalformedURLException(
+			throw new ProcessingException(
 					"Cannot find the classpath resource: " + sourcePath);
 		return resourceURL;
 	}
 
-	public void setSourceURL(final URL sourceURL) throws URISyntaxException {
-		this.setSourceURI(sourceURL.toURI());
-	}
-
-	public URI getSourceURI() {
-		return this.sourceURI;
-	}
-
-	public void setSourceURI(final URI sourceURI) {
-		this.sourceURI = sourceURI;
+	public List<URI> getSourceURIs() {
+		return this.sourceURIs;
 	}
 
 	/**
-	 * Get the scheme used for retrieving this resource. The scheme will be the
-	 * first protocol in the source URI.
+	 * Set the list of potential source URIs for this document.
 	 * 
-	 * @return
+	 * @param sourceURI
 	 */
-	public String getScheme() {
-		String scheme = getSourceURI().getScheme();
-		if (scheme.equals("classpath")) {
-			scheme = "file";
-		}
-		return scheme;
+	public void setSourceURIs(final List<URI> sourceURIs) {
+		this.sourceURIs = sourceURIs;
 	}
 	
 	public String toString() {
@@ -230,10 +175,90 @@
 		sb.append("location: ");
 		sb.append("Pattern: ");
 		sb.append(this.getRequestPattern());
-		sb.append(" SourceURI: ");
-		sb.append(this.getSourceURI().toASCIIString());
-		
+		sb.append(" Potential sourceURIs: ");
+		for (URI uri : getSourceURIs()) {
+		  sb.append(uri.toASCIIString());
+		  sb.append(" ");
+		}
+
 		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);
+		}
+
+		try {
+			url = requestURI.toURL();
+		} catch (final IllegalArgumentException e) {
+			// we'll assume that this is not an absolute URL and therefore
+			// refers to a file
+			url = new URL("file://" + requestURI);
+		}
+		final String urlString = url.toExternalForm();
+
+			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);
+					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");
+			}
+
+			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;
+		
 	}
 
 }

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=478728&r1=478727&r2=478728
==============================================================================
--- 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 Thu Nov 23 16:32:14 2006
@@ -98,7 +98,12 @@
 	}
 
 	/**
-	 * Get the all matching sets of locations for the given URI.
+	 * 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

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=478728&r1=478727&r2=478728
==============================================================================
--- 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 Thu Nov 23 16:32:14 2006
@@ -27,32 +27,25 @@
 import org.apache.forrest.core.locationMap.Location;
 
 /**
- * A chained reader implements a psuedo protocol.
- * It is commonly used when you need to retrieve a
- * document that whose type cannot be identified
- * from the raw source alone.
+ * A chained reader implements a psuedo protocol. It is commonly used when you
+ * need to retrieve a document that whose type cannot be identified from the raw
+ * source alone.
  * 
  * It is defined in forrestContext.xml as follows:
  * 
- * <bean id="fooProtocol"
- *   class="org.apache.forrest.core.reader.ChainedReader" >
- *   <property name="docType"
- *             value="org.foo.Bar" />
- * </bean>
+ * <bean id="fooProtocol" class="org.apache.forrest.core.reader.ChainedReader" >
+ * <property name="docType" value="org.foo.Bar" /> </bean>
  * 
  * We can then define a chain of readers like this:
- *
- * <location pattern="classpath/foo.*">
- *   <source href="fooProtocol:classpath:/xdocs/exampleFeed.xml"/>
- * </location>
- *
- * <location pattern="file/foo.*">
- *    <source href="fooProtocol:file:/xdocs/exampleFeed.xml"/>
- * </location>
- * 
- * <location pattern="http/foo.*">
- *   <source href="fooProtocol:http:/xdocs/exampleFeed.xml"/>
- * </location>
+ * 
+ * <location pattern="classpath/foo.*"> <source
+ * href="fooProtocol:classpath:/xdocs/exampleFeed.xml"/> </location>
+ * 
+ * <location pattern="file/foo.*"> <source
+ * href="fooProtocol:file:/xdocs/exampleFeed.xml"/> </location>
+ * 
+ * <location pattern="http/foo.*"> <source
+ * href="fooProtocol:http:/xdocs/exampleFeed.xml"/> </location>
  * 
  * etc.
  * 
@@ -60,29 +53,30 @@
 public class ChainedReader extends AbstractReader {
 
 	private String docType;
-	
-	public AbstractSourceDocument read(IController controller,
-			URI requestURI, final Location location) throws ProcessingException {
+
+	public AbstractSourceDocument read(IController controller, URI requestURI,
+			final Location location, URI sourceURI) throws ProcessingException {
 		DefaultSourceDocument doc = null;
-		final URI psudeoURI = location.getSourceURI();
-		final String ssp = psudeoURI.getSchemeSpecificPart();
-		URI uri;
-		try {
-			uri = new URI(ssp);
-			location.setSourceURI(uri);
-			IReader reader;
-			reader = (IReader) controller.getReader(location);
-			doc = (DefaultSourceDocument) reader.read(controller, requestURI, location);
-			if (doc != null) {
-				doc
-						.setType(getDocType());
+		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();
 			}
-		} catch (final URISyntaxException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		} catch (MalformedURLException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
 		}
 		return doc;
 	}
@@ -94,6 +88,5 @@
 	public void setDocType(String docType) {
 		this.docType = docType;
 	}
-	
-	
+
 }

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=478728&r1=478727&r2=478728
==============================================================================
--- 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 Thu Nov 23 16:32:14 2006
@@ -20,6 +20,7 @@
 import java.io.FileInputStream;
 import java.io.InputStream;
 import java.net.URI;
+import java.net.URL;
 
 import org.apache.forrest.core.IController;
 import org.apache.forrest.core.document.AbstractSourceDocument;
@@ -28,7 +29,7 @@
 import org.apache.forrest.core.locationMap.Location;
 
 /**
- * An File reader reads a resource using the file protocol, i.e. it will read
+ * A File reader reads a resource using the file protocol, i.e. it will read
  * from local storage.
  * 
  */
@@ -39,11 +40,12 @@
 	 * 
 	 * @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) {
+	public AbstractSourceDocument read(IController controller, URI requestURI,
+			final Location location, final URI sourceURI) {
 		AbstractSourceDocument result = null;
 		try {
-			final InputStream is = new FileInputStream(new File(location
-					.getResolvedSourceURL(requestURI).toURI()));
+			URL resolvedURL = location.resolveURL(requestURI, sourceURI);
+			final InputStream is = new FileInputStream(new File(resolvedURL.toURI()));
 			result = DocumentFactory.getSourceDocumentFor(is);
 		} catch (final Exception e) {
 			if (location.isRequired())

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=478728&r1=478727&r2=478728
==============================================================================
--- 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 Thu Nov 23 16:32:14 2006
@@ -20,6 +20,7 @@
 import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URI;
+import java.net.URL;
 
 import org.apache.commons.httpclient.HttpClient;
 import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
@@ -55,13 +56,14 @@
 	 * 
 	 * @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)
+	public AbstractSourceDocument read(IController controller,
+			final URI requestURI, final Location location, URI sourceURI)
 			throws MalformedURLException, ProcessingException {
 		InputStream is;
 		DefaultSourceDocument result = null;
+		URL resolvedURL = location.resolveURL(requestURI, sourceURI);
 		final ByteArrayOutputStream out = new ByteArrayOutputStream();
-		final GetMethod get = new GetMethod(location.getResolvedSourceURL(requestURI)
-				.toExternalForm());
+		final GetMethod get = new GetMethod(resolvedURL.toExternalForm());
 		get.setFollowRedirects(true);
 		try {
 			this.client.executeMethod(get);
@@ -71,6 +73,7 @@
 			tidy.parseDOM(is, out);
 			result = new DefaultSourceDocument(out.toString());
 		} catch (final Exception e) {
+			result = null;
 			if (location.isRequired())
 				throw new SourceException("Source URL is invalid", e);
 		} finally {

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=478728&r1=478727&r2=478728
==============================================================================
--- 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 Thu Nov 23 16:32:14 2006
@@ -34,20 +34,20 @@
 	abstract void init();
 
 	/**
-	 * Read a resource from a given location. If the resource cannot be read,
+	 * Read a resource from a given uri. If the resource cannot be read,
 	 * but it is an optional location then return null, if it cannot be read and
 	 * it is a required location throw SourceException.
 	 * @param context 
 	 * 
 	 * @param controller - the forrest controller in use
 	 * @param requestURI - the URI being requested
-	 * @param location - the location we are to read the document from
+	 * @param uri - the uri we are to read the document from
 	 * 
 	 * @return
 	 * @throws MalformedURLException
 	 * @throws ProcessingException 
 	 */
-	public abstract AbstractSourceDocument read(IController controller, URI requestURI, Location location)
+	public abstract AbstractSourceDocument read(IController controller, URI requestURI, Location location, URI sourceURI)
 			throws MalformedURLException, ProcessingException;
 
 }