net.sf.saxon.resource.JarCollection Maven / Gradle / Ivy
package net.sf.saxon.resource;
import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.functions.URIQueryParameters;
import net.sf.saxon.lib.ParseOptions;
import net.sf.saxon.lib.Resource;
import net.sf.saxon.om.Sequence;
import net.sf.saxon.om.SpaceStrippingRule;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.value.Base64BinaryValue;
import net.sf.saxon.value.DateTimeValue;
import net.sf.saxon.value.Int64Value;
import net.sf.saxon.value.StringValue;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
* A JarCollection represents a collection of resources held in a JAR or ZIP archive, accessed typically
* using a URI using the (Java-defined) "jar" URI scheme, or simply a "file" URI where the target
* file is a JAR or ZIP file.
*/
public class JarCollection extends AbstractResourceCollection {
private XPathContext context;
private String collectionURI;
private SpaceStrippingRule whitespaceRules;
/**
* Create a JarCollection
* @param context The XPath dynamic context
* @param collectionURI the collection URI used to identify this collection (typically but not necessarily
* the location of the JAR file)
* @param params URI query parameters appearing on the collection URI
*/
public JarCollection(XPathContext context, String collectionURI, URIQueryParameters params) {
super(context.getConfiguration());
this.context = context;
this.collectionURI = collectionURI;
this.params = params;
}
/**
* Supply information about the whitespace stripping rules that apply to this collection.
* This method will only be called when the collection() function is invoked from XSLT.
*
* @param rules the space-stripping rules that apply to this collection, derived from
* the xsl:strip-space and xsl:preserve-space declarations in the stylesheet
* package containing the call to the collection() function.
* @return true if the collection finder intends to take responsibility for whitespace
* stripping according to these rules; false if it wishes Saxon itself to post-process
* any returned XML documents to strip whitespace. Returning true may either indicate
* that the collection finder will strip whitespace before returning a document, or it
* may indicate that it does not wish the space stripping rules to be applied. The
* default (returned by this method if not overridden) is false.
*/
@Override
public boolean stripWhitespace(SpaceStrippingRule rules) {
this.whitespaceRules = rules;
return true;
}
/**
* Get the URI identifying this collection
*
* @return the collection URI
*/
public String getCollectionURI() {
return collectionURI;
}
/**
* Get the URIs of the resources within the collection
*
* @return a list of all the URIs of resources within the collection. The resources are identified
* by URIs of the form collection-uri!entry-path
* @throws XPathException if any error occurs accessing the JAR file contents
* @param context
*/
public Iterator getResourceURIs(XPathContext context) throws XPathException {
FilenameFilter filter = null;
boolean recurse = false;
if (params != null) {
FilenameFilter f = params.getFilenameFilter();
if (f != null) {
filter = f;
}
Boolean r = params.getRecurse();
if (r != null) {
recurse = r;
}
}
ZipInputStream zipInputStream = getZipInputStream();
List result = new ArrayList();
try {
ZipEntry entry;
String dirStr = "";
while ((entry = zipInputStream.getNextEntry()) != null) {
if (entry.isDirectory()) {
dirStr = entry.getName();
}
if (!entry.isDirectory()) {
String entryName = entry.getName();
if (filter != null) {
if (dirStr.equals("") || !entryName.contains(dirStr)) {
if (entryName.contains("/")) {
dirStr = entryName.substring(0, entryName.lastIndexOf("/"));
} else {
dirStr = "";
}
}
if (filter.accept(new File(dirStr), entryName)) {
result.add(makeResourceURI(entryName));
}
} else {
result.add(makeResourceURI(entryName));
}
}
entry = zipInputStream.getNextEntry();
}
} catch (IOException e) {
throw new XPathException("Unable to extract entry in JAR/ZIP file: " + collectionURI, e);
}
return result.iterator();
}
private ZipInputStream getZipInputStream() throws XPathException {
URL url;
try {
url = new URL(collectionURI);
} catch (MalformedURLException e) {
throw new XPathException("Malformed JAR/ZIP file URI: " + collectionURI, e);
}
URLConnection connection;
try {
connection = url.openConnection();
} catch (IOException e) {
throw new XPathException("Unable to open connection to JAR/ZIP file URI: " + collectionURI, e);
}
InputStream stream;
try {
stream = connection.getInputStream();
} catch (IOException e) {
throw new XPathException("Unable to get input stream for JAR/ZIP file connection: " + collectionURI, e);
}
return new ZipInputStream(stream);
}
public Iterator getResources(XPathContext context) throws XPathException {
FilenameFilter filter = null;
boolean recurse = false;
if (params != null) {
FilenameFilter f = params.getFilenameFilter();
if (f != null) {
filter = f;
}
Boolean r = params.getRecurse();
if (r != null) {
recurse = r;
}
}
ZipInputStream zipInputStream = getZipInputStream();
return new JarIterator(this.context, zipInputStream, filter);
}
private String makeResourceURI(String entryName) {
return
(collectionURI.startsWith("jar:") ? "" : "jar:") +
collectionURI + "!/" + entryName;
}
private class JarIterator implements Iterator {
private FilenameFilter filter;
private Resource next = null;
private XPathContext context;
private ZipInputStream zipInputStream;
private String dirStr = "";
private ParseOptions options;
private boolean metadata;
public JarIterator(XPathContext context, ZipInputStream zipInputStream, FilenameFilter filter) throws XPathException {
this.context = context;
this.filter = filter;
this.zipInputStream = zipInputStream;
this.options = optionsFromQueryParameters(params, context);
this.options.setSpaceStrippingRule(whitespaceRules);
Boolean metadataParam = params == null ? null : params.getMetaData();
metadata = metadataParam != null && metadataParam;
//this.resourceURIs = resourceURIs;
advance();
}
public boolean hasNext() {
return next != null;
}
public Resource next() {
Resource current = next;
advance();
return current;
}
public void remove() {
throw new UnsupportedOperationException();
}
private void advance() {
while (true) {
ZipEntry entry;
try {
entry = zipInputStream.getNextEntry();
if (entry == null) {
next = null;
return;
}
} catch (IOException e) {
// TODO error handling
e.printStackTrace();
return;
}
if (entry.isDirectory()) {
dirStr = entry.getName();
continue;
} else {
String entryName = entry.getName();
if (filter != null) {
if (dirStr.equals("") || !entryName.contains(dirStr)) {
if (entryName.contains("/")) {
dirStr = entryName.substring(0, entryName.lastIndexOf("/"));
} else {
dirStr = "";
}
}
if (!filter.accept(new File(dirStr), entryName)) {
continue;
}
}
try {
InputStream is = zipInputStream;
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
byte[] buffer = new byte[4096];
int len = 0;
while ((len = is.read(buffer)) > 0) {
output.write(buffer, 0, len);
}
} catch (IOException err) {
err.printStackTrace();
} finally {
// we must always close the output file
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
InputStream entryContent = new ByteArrayInputStream(output.toByteArray());
InputDetails details = new InputDetails();
details.inputStream = entryContent;
details.contentType = guessContentType(entry.getName(), entryContent);
details.parseOptions = options;
String resourceURI = makeResourceURI(entry.getName());
next = makeResource(context.getConfiguration(), details, resourceURI);
if (metadata) {
Map properties = makeProperties(entry);
next = new MetadataResource(resourceURI, next, properties);
}
return;
} catch (XPathException e) {
// TODO: error handling
e.printStackTrace();
}
}
}
}
}
/**
* Get the properties of a Zip file entry, for use when returning a MetadataResource containing this information
* @param entry the current Zip file entry
* @return a map containing the properties of this entry: comment, compressed-size, crc, extra, compression-method,
* entry-name, size, and last-modified.
*/
protected Map makeProperties(ZipEntry entry) {
HashMap map = new HashMap(10);
map.put("comment", StringValue.makeStringValue(entry.getComment()));
map.put("compressed-size", new Int64Value(entry.getCompressedSize()));
map.put("crc", new Int64Value(entry.getCrc()));
byte[] extra = entry.getExtra();
if (extra != null) {
map.put("extra", new Base64BinaryValue(extra));
}
map.put("compression-method", new Int64Value(entry.getMethod()));
map.put("entry-name", StringValue.makeStringValue(entry.getName()));
map.put("size", new Int64Value(entry.getSize()));
try {
map.put("last-modified", DateTimeValue.fromJavaTime(entry.getTime()));
} catch (XPathException err) {
// ignore the failure
}
return map;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy