aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/fop/apps/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/java/org/apache/fop/apps/io')
-rw-r--r--src/java/org/apache/fop/apps/io/DefaultResourceResolver.java49
-rw-r--r--src/java/org/apache/fop/apps/io/FOURIResolver.java377
-rw-r--r--src/java/org/apache/fop/apps/io/Resource.java59
-rw-r--r--src/java/org/apache/fop/apps/io/ResourceResolver.java32
-rw-r--r--src/java/org/apache/fop/apps/io/URIResolverWrapper.java74
-rw-r--r--src/java/org/apache/fop/apps/io/package.html6
6 files changed, 597 insertions, 0 deletions
diff --git a/src/java/org/apache/fop/apps/io/DefaultResourceResolver.java b/src/java/org/apache/fop/apps/io/DefaultResourceResolver.java
new file mode 100644
index 000000000..af04f218a
--- /dev/null
+++ b/src/java/org/apache/fop/apps/io/DefaultResourceResolver.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.apps.io;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URI;
+
+
+public class DefaultResourceResolver implements ResourceResolver {
+
+ public Resource getResource(URI uri) throws IOException {
+ try {
+ return new Resource(uri.toURL().openStream());
+ } catch (MalformedURLException mue) {
+ throw new RuntimeException(mue);
+ }
+ }
+
+ public OutputStream getOutputStream(URI uri) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public static URIResolverWrapper createDefaultWrapper() {
+ // Not sure if this is the right place for this, but I don't have any better ideas as of yet
+ URI thisUri = new File(".").getAbsoluteFile().toURI();
+ return new URIResolverWrapper(thisUri, new DefaultResourceResolver());
+ }
+
+}
diff --git a/src/java/org/apache/fop/apps/io/FOURIResolver.java b/src/java/org/apache/fop/apps/io/FOURIResolver.java
new file mode 100644
index 000000000..b73c67fa8
--- /dev/null
+++ b/src/java/org/apache/fop/apps/io/FOURIResolver.java
@@ -0,0 +1,377 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.apps.io;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.fop.apps.FOUserAgent;
+
+import org.apache.xmlgraphics.util.io.Base64EncodeStream;
+import org.apache.xmlgraphics.util.uri.CommonURIResolver;
+
+/**
+ * Provides FOP specific URI resolution. This is the default URIResolver
+ * {@link FOUserAgent} will use unless overridden.
+ *
+ * @see javax.xml.transform.URIResolver
+ */
+public class FOURIResolver implements javax.xml.transform.URIResolver {
+
+ // log
+ private Log log = LogFactory.getLog("FOP");
+
+ /** Common URIResolver */
+ private CommonURIResolver commonURIResolver = new CommonURIResolver();
+
+ /** A user settable URI Resolver */
+ private URIResolver uriResolver = null;
+
+ /** true if exceptions are to be thrown if the URIs cannot be resolved. */
+ private boolean throwExceptions = false;
+
+ /**
+ * Checks if the given base URL is acceptable. It also normalizes the URL.
+ * @param base the base URL to check
+ * @return the normalized URL
+ * @throws MalformedURLException if there's a problem with a file URL
+ */
+ public String checkBaseURL(String base) throws MalformedURLException {
+ // replace back slash with forward slash to ensure windows file:/// URLS are supported
+ base = base.replace('\\', '/');
+ if (!base.endsWith("/")) {
+ // The behavior described by RFC 3986 regarding resolution of relative
+ // references may be misleading for normal users:
+ // file://path/to/resources + myResource.res -> file://path/to/myResource.res
+ // file://path/to/resources/ + myResource.res -> file://path/to/resources/myResource.res
+ // We assume that even when the ending slash is missing, users have the second
+ // example in mind
+ base += "/";
+ }
+ File dir = new File(base);
+ if (dir.isDirectory()) {
+ return dir.toURI().toASCIIString();
+ } else {
+ URI baseURI;
+ try {
+ baseURI = new URI(base);
+ String scheme = baseURI.getScheme();
+ boolean directoryExists = true;
+ if ("file".equals(scheme)) {
+ dir = FileUtils.toFile(baseURI.toURL());
+ directoryExists = dir.isDirectory();
+ }
+ if (scheme == null || !directoryExists) {
+ String message = "base " + base + " is not a valid directory";
+ if (throwExceptions) {
+ throw new MalformedURLException(message);
+ }
+ log.error(message);
+ }
+ return baseURI.toASCIIString();
+ } catch (URISyntaxException e) {
+ //TODO not ideal: our base URLs are actually base URIs.
+ throw new MalformedURLException(e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Default constructor
+ */
+ public FOURIResolver() {
+ this(false);
+ }
+
+ /**
+ * Additional constructor
+ *
+ * @param throwExceptions
+ * true if exceptions are to be thrown if the URIs cannot be
+ * resolved.
+ */
+ public FOURIResolver(boolean throwExceptions) {
+ this.throwExceptions = throwExceptions;
+ }
+
+ /**
+ * Handles resolve exceptions appropriately.
+ *
+ * @param e
+ * the exception
+ * @param errorStr
+ * error string
+ * @param strict
+ * strict user config
+ */
+ private void handleException(Exception e, String errorStr, boolean strict)
+ throws TransformerException {
+ if (strict) {
+ throw new TransformerException(errorStr, e);
+ }
+ log.error(e.getMessage());
+ }
+
+ /**
+ * 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)} 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
+ * {@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 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)
+ */
+ public Source resolve(String href, String base) throws TransformerException {
+ Source source = null;
+
+ // data URLs can be quite long so evaluate early and don't try to build a File
+ // (can lead to problems)
+ source = commonURIResolver.resolve(href, base);
+
+ // Custom uri resolution
+ if (source == null && uriResolver != null) {
+ source = uriResolver.resolve(href, base);
+ }
+
+ // Fallback to default resolution mechanism
+ if (source == null) {
+ URL absoluteURL = null;
+ int hashPos = href.indexOf('#');
+ String fileURL;
+ String fragment;
+ if (hashPos >= 0) {
+ fileURL = href.substring(0, hashPos);
+ fragment = href.substring(hashPos);
+ } else {
+ fileURL = href;
+ fragment = null;
+ }
+ File file = new File(fileURL);
+ if (file.canRead() && file.isFile()) {
+ try {
+ if (fragment != null) {
+ absoluteURL = new URL(file.toURI().toURL().toExternalForm() + fragment);
+ } else {
+ absoluteURL = file.toURI().toURL();
+ }
+ } catch (MalformedURLException mfue) {
+ handleException(mfue, "Could not convert filename '" + href
+ + "' to URL", throwExceptions);
+ }
+ } else {
+ // no base provided
+ if (base == null) {
+ // We don't have a valid file protocol based URL
+ try {
+ absoluteURL = new URL(href);
+ } catch (MalformedURLException mue) {
+ try {
+ // the above failed, we give it another go in case
+ // the href contains only a path then file: is
+ // assumed
+ absoluteURL = new URL("file:" + href);
+ } catch (MalformedURLException mfue) {
+ handleException(mfue, "Error with URL '" + href
+ + "'", throwExceptions);
+ }
+ }
+
+ // try and resolve from context of base
+ } else {
+ URL baseURL = null;
+ try {
+ baseURL = new URL(base);
+ } catch (MalformedURLException mfue) {
+ handleException(mfue, "Error with base URL '" + base
+ + "'", throwExceptions);
+ }
+
+ /*
+ * This piece of code is based on the following statement in
+ * RFC2396 section 5.2:
+ *
+ * 3) If the scheme component is defined, indicating that
+ * the reference starts with a scheme name, then the
+ * reference is interpreted as an absolute URI and we are
+ * done. Otherwise, the reference URI's scheme is inherited
+ * from the base URI's scheme component.
+ *
+ * Due to a loophole in prior specifications [RFC1630], some
+ * parsers allow the scheme name to be present in a relative
+ * URI if it is the same as the base URI scheme.
+ * Unfortunately, this can conflict with the correct parsing
+ * of non-hierarchical URI. For backwards compatibility, an
+ * implementation may work around such references by
+ * removing the scheme if it matches that of the base URI
+ * and the scheme is known to always use the <hier_part>
+ * syntax.
+ *
+ * The URL class does not implement this work around, so we
+ * do.
+ */
+ assert (baseURL != null);
+ String scheme = baseURL.getProtocol() + ":";
+ if (href.startsWith(scheme) && "file:".equals(scheme)) {
+ href = href.substring(scheme.length());
+ int colonPos = href.indexOf(':');
+ int slashPos = href.indexOf('/');
+ if (slashPos >= 0 && colonPos >= 0
+ && colonPos < slashPos) {
+ href = "/" + href; // Absolute file URL doesn't
+ // have a leading slash
+ }
+ }
+ try {
+ absoluteURL = new URL(baseURL, href);
+ } catch (MalformedURLException mfue) {
+ handleException(mfue, "Error with URL; base '" + base
+ + "' " + "href '" + href + "'", throwExceptions);
+ }
+ }
+ }
+
+ if (absoluteURL != null) {
+ String effURL = absoluteURL.toExternalForm();
+ try {
+ URLConnection connection = absoluteURL.openConnection();
+ connection.setAllowUserInteraction(false);
+ connection.setDoInput(true);
+ updateURLConnection(connection, href);
+ connection.connect();
+ return new StreamSource(connection.getInputStream(), effURL);
+ } catch (FileNotFoundException fnfe) {
+ // Note: This is on "debug" level since the caller is
+ // supposed to handle this
+ log.debug("File not found: " + effURL);
+ } catch (java.io.IOException ioe) {
+ log.error("Error with opening URL '" + effURL + "': "
+ + ioe.getMessage());
+ }
+ }
+ }
+ return source;
+ }
+
+ /**
+ * This method allows you to set special values on a URLConnection just
+ * before the connect() method is called. Subclass FOURIResolver and
+ * override this method to do things like adding the user name and password
+ * for HTTP basic authentication.
+ *
+ * @param connection
+ * the URLConnection instance
+ * @param href
+ * the original URI
+ */
+ protected void updateURLConnection(URLConnection connection, String href) {
+ // nop
+ }
+
+ /**
+ * This is a convenience method for users who want to override
+ * updateURLConnection for HTTP basic authentication. Simply call it using
+ * the right username and password.
+ *
+ * @param connection
+ * the URLConnection to set up for HTTP basic authentication
+ * @param username
+ * the username
+ * @param password
+ * the password
+ */
+ protected void applyHttpBasicAuthentication(URLConnection connection,
+ String username, String password) {
+ String combined = username + ":" + password;
+ try {
+ ByteArrayOutputStream baout = new ByteArrayOutputStream(combined
+ .length() * 2);
+ Base64EncodeStream base64 = new Base64EncodeStream(baout);
+ // TODO Not sure what charset/encoding can be used with basic
+ // authentication
+ base64.write(combined.getBytes("UTF-8"));
+ base64.close();
+ connection.setRequestProperty("Authorization", "Basic "
+ + new String(baout.toByteArray(), "UTF-8"));
+ } catch (IOException e) {
+ // won't happen. We're operating in-memory.
+ throw new RuntimeException(
+ "Error during base64 encodation of username/password");
+ }
+ }
+
+ /**
+ * Sets the custom URI Resolver. It is used for resolving factory-level URIs like
+ * hyphenation patterns and as backup for URI resolution performed during a
+ * rendering run.
+ *
+ * @param resolver
+ * the new URI resolver
+ */
+ public void setCustomURIResolver(URIResolver resolver) {
+ this.uriResolver = resolver;
+ }
+
+ /**
+ * Returns the custom URI Resolver.
+ *
+ * @return the URI Resolver or null, if none is set
+ */
+ public URIResolver getCustomURIResolver() {
+ return this.uriResolver;
+ }
+
+ /**
+ * @param throwExceptions
+ * Whether or not to throw exceptions on resolution error
+ */
+ public void setThrowExceptions(boolean throwExceptions) {
+ this.throwExceptions = throwExceptions;
+ }
+}
diff --git a/src/java/org/apache/fop/apps/io/Resource.java b/src/java/org/apache/fop/apps/io/Resource.java
new file mode 100644
index 000000000..0a8b8c22a
--- /dev/null
+++ b/src/java/org/apache/fop/apps/io/Resource.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.apps.io;
+
+import java.io.FilterInputStream;
+import java.io.InputStream;
+
+/**
+ * This class represents a resolved resource. The type property is used by FOP to identify the resource
+ * content.
+ *
+ */
+public class Resource extends FilterInputStream {
+
+ private final String type;
+
+ /**
+ * @param type resource type
+ * @param inputStream input stream of the resource
+ */
+ public Resource(String type, InputStream inputStream) {
+ super(inputStream);
+ this.type = type;
+ }
+
+ /**
+ * Constructs a resource of 'unknown' type.
+ *
+ * @param inputStream input stream of the resource
+ */
+ public Resource(InputStream inputStream) {
+ this("unknown", inputStream);
+ }
+
+ /**
+ * @return the resource type
+ */
+ public String getType() {
+ return this.type;
+ }
+
+}
diff --git a/src/java/org/apache/fop/apps/io/ResourceResolver.java b/src/java/org/apache/fop/apps/io/ResourceResolver.java
new file mode 100644
index 000000000..3d20aaebc
--- /dev/null
+++ b/src/java/org/apache/fop/apps/io/ResourceResolver.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.apps.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+
+public interface ResourceResolver {
+
+ Resource getResource(URI uri) throws IOException;
+
+ OutputStream getOutputStream(URI uri) throws IOException;
+
+}
diff --git a/src/java/org/apache/fop/apps/io/URIResolverWrapper.java b/src/java/org/apache/fop/apps/io/URIResolverWrapper.java
new file mode 100644
index 000000000..7ff912089
--- /dev/null
+++ b/src/java/org/apache/fop/apps/io/URIResolverWrapper.java
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.apps.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+
+public class URIResolverWrapper {
+ private final URI baseUri;
+ private final ResourceResolver uriResolver;
+
+ public URIResolverWrapper(URI baseUri, ResourceResolver uriResolver) {
+ this.baseUri = baseUri;
+ this.uriResolver = uriResolver;
+ }
+
+ public URI getBaseURI() {
+ return baseUri;
+ }
+
+ public InputStream resolveIn(String stringUri) throws IOException, URISyntaxException {
+ return resolveIn(cleanURI(stringUri));
+ }
+
+ public InputStream resolveIn(URI uri) throws IOException {
+ return uriResolver.getResource(resolveFromBase(uri));
+ }
+
+ public OutputStream resolveOut(URI uri) throws IOException {
+ return uriResolver.getOutputStream(resolveFromBase(uri));
+ }
+
+ private URI resolveFromBase(URI uri) {
+ return baseUri.resolve(uri);
+ }
+
+ public static URI cleanURI(String base) throws URISyntaxException {
+ // replace back slash with forward slash to ensure windows file:/// URLS are supported
+ if (base == null) {
+ return null;
+ }
+ String fixedUri = base.replace('\\', '/');
+ fixedUri = fixedUri.replace(" ", "%20");
+ URI baseURI = new URI(fixedUri);
+ return baseURI;
+ }
+
+ public static URI getBaseURI(String base) throws URISyntaxException {
+ String path = base + (base.endsWith("/") ? "" : "/");
+ return cleanURI(path);
+ }
+
+}
diff --git a/src/java/org/apache/fop/apps/io/package.html b/src/java/org/apache/fop/apps/io/package.html
new file mode 100644
index 000000000..d631dc998
--- /dev/null
+++ b/src/java/org/apache/fop/apps/io/package.html
@@ -0,0 +1,6 @@
+<HTML>
+<TITLE>org.apache.fop.io Package</TITLE>
+<BODY>
+<P>Classes that control all IO in FOP.</P>
+</BODY>
+</HTML> \ No newline at end of file