Renamed FOUserAgent.getStream() to FOUserAgent.resolveURI() which now simply returns a Source instance which the ImageFactory uses to get at an InputStream somehow. Submitted by: Manuel Mall <mm.at.arcus.com.au> git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@232949 13f79535-47bb-0310-9956-ffa450edef68pull/31/head
* @see javax.xml.transform.URIResolver | * @see javax.xml.transform.URIResolver | ||||
*/ | */ | ||||
public class FOURIResolver | public class FOURIResolver | ||||
implements javax.xml.transform.URIResolver | |||||
{ | |||||
implements javax.xml.transform.URIResolver { | |||||
private Log log = LogFactory.getLog("FOP"); | private Log log = LogFactory.getLog("FOP"); | ||||
/** | /** | ||||
* Called by the processor through {@link FOUserAgent} when it encounters an uri in an external-graphic element. | |||||
* Called by the processor through {@link FOUserAgent} when it encounters an | |||||
* uri in an external-graphic element. | |||||
* (see also {@link javax.xml.transform.URIResolver#resolve(String, String)} | * (see also {@link javax.xml.transform.URIResolver#resolve(String, String)} | ||||
* This resolver will allow URLs without a scheme, i.e. it assumes 'file:' as the default | |||||
* scheme. It also allows relative URLs with scheme, e.g. file:../../abc.jpg which is | |||||
* not strictly RFC compliant as long as the scheme is the same as the scheme of the | |||||
* base URL. If the base URL is null a 'file:' URL referencing the current directory is used as | |||||
* the base URL. | |||||
* This resolver will allow URLs without a scheme, i.e. it assumes 'file:' as | |||||
* the default scheme. It also allows relative URLs with scheme, | |||||
* e.g. file:../../abc.jpg which is not strictly RFC compliant as long as the | |||||
* scheme is the same as the scheme of the base URL. If the base URL is null | |||||
* a 'file:' URL referencing the current directory is used as the base URL. | |||||
* If the method is successful it will return a Source of type | * If the method is successful it will return a Source of type | ||||
* {@link javax.xml.transform.stream.StreamSource} with its SystemID set to the resolved | |||||
* URL used to open the underlying InputStream. | |||||
* {@link javax.xml.transform.stream.StreamSource} with its SystemID set to | |||||
* the resolved URL used to open the underlying InputStream. | |||||
* | * | ||||
* @param href An href attribute, which may be relative or absolute. | * @param href An href attribute, which may be relative or absolute. | ||||
* @param base The base URI against which the first argument will be made absolute if the absolute URI is required. | |||||
* @return A {@link javax.xml.transform.Source} object, or null if the href cannot be resolved. | |||||
* @throws TransformerException Never thrown by this implementation. | |||||
* @param base The base URI against which the first argument will be made | |||||
* absolute if the absolute URI is required. | |||||
* @return A {@link javax.xml.transform.Source} object, or null if the href | |||||
* cannot be resolved. | |||||
* @throws javax.xml.transform.TransformerException Never thrown by this implementation. | |||||
* @see javax.xml.transform.URIResolver#resolve(String, String) | * @see javax.xml.transform.URIResolver#resolve(String, String) | ||||
*/ | */ | ||||
public Source resolve(String href, String base) | public Source resolve(String href, String base) | ||||
throws javax.xml.transform.TransformerException | |||||
{ | |||||
throws javax.xml.transform.TransformerException { | |||||
URL absoluteURL = null; | URL absoluteURL = null; | ||||
URL baseURL = toBaseURL(base); | URL baseURL = toBaseURL(base); | ||||
if (baseURL == null) { | if (baseURL == null) { | ||||
* @param baseURL the base URL | * @param baseURL the base URL | ||||
* @returns the base URL as java.net.URL | * @returns the base URL as java.net.URL | ||||
*/ | */ | ||||
private URL toBaseURL(String baseURL) | |||||
{ | |||||
private URL toBaseURL(String baseURL) { | |||||
try { | try { | ||||
return new URL(baseURL == null | return new URL(baseURL == null | ||||
? new java.io.File("").toURL().toExternalForm() | ? new java.io.File("").toURL().toExternalForm() |
// Java | // Java | ||||
import java.io.File; | import java.io.File; | ||||
import java.io.IOException; | |||||
import java.util.Date; | import java.util.Date; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
import javax.xml.transform.Source; | import javax.xml.transform.Source; | ||||
import javax.xml.transform.TransformerException; | import javax.xml.transform.TransformerException; | ||||
import javax.xml.transform.URIResolver; | import javax.xml.transform.URIResolver; | ||||
import javax.xml.transform.stream.StreamSource; | |||||
// avalon configuration | // avalon configuration | ||||
import org.apache.avalon.framework.configuration.Configuration; | import org.apache.avalon.framework.configuration.Configuration; | ||||
* @return the URI Resolver | * @return the URI Resolver | ||||
*/ | */ | ||||
public URIResolver getURIResolver() { | public URIResolver getURIResolver() { | ||||
return this.uriResolver != null ? this.uriResolver : this.foURIResolver; | |||||
return this.uriResolver; | |||||
} | } | ||||
/** | /** | ||||
/** | /** | ||||
* Get a stream source for a reference. Subclass FOUserAgent and override this method to | |||||
* do custom URI to {@link javax.xml.transform.stream.StreamSource} resolution. | |||||
* Alternatively set your own {@link javax.xml.transform.URIResolver} on the FOUserAgent. | |||||
* Temporary solution until the API is better. | |||||
* Attempts to resolve the given URI. | |||||
* Will use the configured resolver and if not successful fall back | |||||
* to the default resolver. | |||||
* @param uri URI to access | * @param uri URI to access | ||||
* @return StreamSource for accessing the resource. | |||||
* @throws IOException in case of an I/O problem | |||||
* @return A {@link javax.xml.transform.Source} object, or null if the URI | |||||
* cannot be resolved. | |||||
* @see org.apache.fop.apps.FOURIResolver | |||||
*/ | */ | ||||
public StreamSource getStream(String uri) throws IOException { | |||||
public Source resolveURI(String uri) { | |||||
Source source = null; | Source source = null; | ||||
try { | |||||
source = getURIResolver().resolve(uri, getBaseURL()); | |||||
} catch (TransformerException te) { | |||||
log.error("Attempt to resolve URI '" + uri + "' failed: ", te); | |||||
URIResolver uriResolver = getURIResolver(); | |||||
if (uriResolver != null) { | |||||
try { | |||||
source = uriResolver.resolve(uri, getBaseURL()); | |||||
} catch (TransformerException te) { | |||||
log.error("Attempt to resolve URI '" + uri + "' failed: ", te); | |||||
} | |||||
} | } | ||||
if (source != null) { | |||||
if (source instanceof StreamSource) { | |||||
return (StreamSource)source; | |||||
} else { | |||||
log.error("Attempt to resolve URI returned unknown source"); | |||||
if (source == null) { | |||||
// URI Resolver not configured or returned null, use default resolver | |||||
try { | |||||
source = foURIResolver.resolve(uri, getBaseURL()); | |||||
} catch (TransformerException te) { | |||||
log.error("Attempt to resolve URI '" + uri + "' failed: ", te); | |||||
} | } | ||||
} | } | ||||
return null; | |||||
return source; | |||||
} | } | ||||
/** | /** |
package org.apache.fop.image; | package org.apache.fop.image; | ||||
// Java | // Java | ||||
import java.io.IOException; | |||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import java.lang.reflect.Constructor; | import java.lang.reflect.Constructor; | ||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.Iterator; | import java.util.Iterator; | ||||
import java.util.List; | import java.util.List; | ||||
import javax.xml.transform.Source; | |||||
import javax.xml.transform.stream.StreamSource; | import javax.xml.transform.stream.StreamSource; | ||||
import org.apache.commons.logging.Log; | import org.apache.commons.logging.Log; | ||||
*/ | */ | ||||
public FopImage loadImage(String href, FOUserAgent ua) { | public FopImage loadImage(String href, FOUserAgent ua) { | ||||
StreamSource source = openStream(href, ua); | |||||
Source source = ua.resolveURI(href); | |||||
if (source == null) { | if (source == null) { | ||||
return null; | return null; | ||||
} | } | ||||
// Got a valid source, obtain an InputStream from it | |||||
InputStream in = null; | |||||
if (source instanceof StreamSource) { | |||||
in = ((StreamSource)source).getInputStream(); | |||||
} | |||||
if (in == null) { | |||||
try { | |||||
in = new java.net.URL(source.getSystemId()).openStream(); | |||||
} catch (Exception ex) { | |||||
log.error("Unable to obtain stream from id '" | |||||
+ source.getSystemId() + "'"); | |||||
} | |||||
} | |||||
if (in == null) { | |||||
return null; | |||||
} | |||||
InputStream in = source.getInputStream(); | |||||
//Make sure the InputStream is decorated with a BufferedInputStream | //Make sure the InputStream is decorated with a BufferedInputStream | ||||
if (!(in instanceof java.io.BufferedInputStream)) { | if (!(in instanceof java.io.BufferedInputStream)) { | ||||
in = new java.io.BufferedInputStream(in); | in = new java.io.BufferedInputStream(in); | ||||
return (FopImage) imageInstance; | return (FopImage) imageInstance; | ||||
} | } | ||||
/** | |||||
* Create a StreamSource objects. | |||||
* @param href image URL as a String | |||||
* @param ua user agent | |||||
* @return a new StreamSource object | |||||
*/ | |||||
protected StreamSource openStream(String href, FOUserAgent ua) { | |||||
StreamSource in = null; | |||||
try { | |||||
in = ua.getStream(href); | |||||
} catch (IOException ioe) { | |||||
log.error("Error while opening stream for (" | |||||
+ href + "): " + ioe.getMessage(), ioe); | |||||
return null; | |||||
} | |||||
return in; | |||||
} | |||||
private Class getImageClass(String imgMimeType) { | private Class getImageClass(String imgMimeType) { | ||||
ImageMimeType imt = (ImageMimeType)imageMimeTypes.get(imgMimeType); | ImageMimeType imt = (ImageMimeType)imageMimeTypes.get(imgMimeType); | ||||
if (imt == null) { | if (imt == null) { |
package org.apache.fop; | package org.apache.fop; | ||||
import java.io.File; | import java.io.File; | ||||
import java.io.FileNotFoundException; | |||||
import java.io.OutputStream; | import java.io.OutputStream; | ||||
import javax.xml.transform.Result; | import javax.xml.transform.Result; | ||||
Document doc = createAreaTree(foFile, ua); | Document doc = createAreaTree(foFile, ua); | ||||
//Check how many times the resolver was consulted | //Check how many times the resolver was consulted | ||||
assertEquals(1, resolver.successCount); | |||||
assertEquals(0, resolver.failureCount); | |||||
assertEquals("Expected resolver to do 1 successful URI resolution", | |||||
1, resolver.successCount); | |||||
assertEquals("Expected resolver to do 0 failed URI resolution", | |||||
0, resolver.failureCount); | |||||
//Additional XPath checking on the area tree | //Additional XPath checking on the area tree | ||||
assertEquals("viewport for external-graphic is missing", | assertEquals("viewport for external-graphic is missing", | ||||
"true", evalXPath(doc, "boolean(//flow/block[1]/lineArea/viewport)")); | "true", evalXPath(doc, "boolean(//flow/block[1]/lineArea/viewport)")); | ||||
* @throws Exception if anything fails | * @throws Exception if anything fails | ||||
*/ | */ | ||||
public void testFO2() throws Exception { | public void testFO2() throws Exception { | ||||
//TODO This will only work when we can do URI resolution inside Batik! | |||||
File foFile = new File(getBaseDir(), "test/xml/uri-resolution2.fo"); | File foFile = new File(getBaseDir(), "test/xml/uri-resolution2.fo"); | ||||
FOUserAgent ua = new FOUserAgent(); | FOUserAgent ua = new FOUserAgent(); | ||||
} | } | ||||
//Check how many times the resolver was consulted | //Check how many times the resolver was consulted | ||||
assertEquals(1, resolver.successCount); | |||||
assertEquals(0, resolver.failureCount); | |||||
assertEquals("Expected resolver to do 1 successful URI resolution", | |||||
1, resolver.successCount); | |||||
assertEquals("Expected resolver to do 0 failed URI resolutions", | |||||
0, resolver.failureCount); | |||||
//Test using PDF as the area tree doesn't invoke Batik so we could check | //Test using PDF as the area tree doesn't invoke Batik so we could check | ||||
//if the resolver is actually passed to Batik by FOP | //if the resolver is actually passed to Batik by FOP | ||||
assertTrue("Generated PDF has zero length", baout.size() > 0); | assertTrue("Generated PDF has zero length", baout.size() > 0); | ||||
if ("myimage123".equals(name)) { | if ("myimage123".equals(name)) { | ||||
File image = new File(getBaseDir(), "test/resources/images/bgimg300dpi.jpg"); | File image = new File(getBaseDir(), "test/resources/images/bgimg300dpi.jpg"); | ||||
StreamSource src = new StreamSource(image); | StreamSource src = new StreamSource(image); | ||||
try { | |||||
//TODO The next line should not be necessary!!! | |||||
src.setInputStream(new java.io.FileInputStream(image)); | |||||
} catch (FileNotFoundException e) { | |||||
throw new TransformerException(e.getMessage(), e); | |||||
} | |||||
successCount++; | successCount++; | ||||
return src; | return src; | ||||
} else { | } else { |