package lux;
import java.io.IOException;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.URIResolver;
import lux.exception.NotFoundException;
import lux.search.DocIterator;
import lux.search.LuxSearcher;
import net.sf.saxon.s9api.XdmNode;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.DocIdSetIterator;
import org.apache.lucene.search.TermQuery;
public class LuxURIResolver implements URIResolver {
private final URIResolver systemURIResolver;
protected final Evaluator evaluator;
protected final String uriFieldName;
/**
* @param systemURIResolver resolver to use for file: uris
* @param evaluator the evaluator to use to retrieve docs from the index
* @param uriFieldName the name of the URI field
*/
public LuxURIResolver(URIResolver systemURIResolver, Evaluator evaluator, String uriFieldName) {
this.systemURIResolver = systemURIResolver;
this.evaluator = evaluator;
this.uriFieldName = uriFieldName;
}
/**
* file: uri resolution is delegated to the system URI resolver. lux: and other uris are all resolved
* by #getDocument(String). The lux: prefix is optional, e.g: the uris "lux:/hello.xml" and "/hello.xml"
* are equivalent.
* @throws TransformerException if the document is not found
*/
@Override
public Source resolve(String href, String base) throws TransformerException {
boolean isFile;
String path = href;
if (href.matches("^\\w+:.*$")) {
isFile = href.startsWith("file:");
if (isFile) {
path = href.substring(5);
} else if (href.startsWith("lux:/")) {
path = href.substring(5);
}
} else {
// relative url, look at base
if (base != null) {
isFile = base.startsWith("file:");
} else {
isFile = false;
}
}
if (isFile) {
return systemURIResolver.resolve (path, base);
}
path = path.replace('\\', '/');
return getDocument(path).asSource();
}
/**
* Evaluator provides this method as an implementation of URIResolver so as to resolve uris in service of fn:doc().
* file: uri resolution is delegated to the default resolver by returning null. lux: and other uris are all resolved
* using the provided searcher. The lux: prefix is optional, e.g: the uris "lux:/hello.xml" and "/hello.xml"
* are equivalent. Documents read from the index are numbered according to their Lucene docIDs, and retrieved
* using the {@link CachingDocReader}.
* @param uri the uri of the document to retrieve
* @return the document node
* @throws IllegalStateException if the resolver wasn't configured properly (has no searcher)
* @throws TransformerException or there was an IOException thrown by Lucene.
* @throws NotFoundException if the document is not found in the index
*/
public XdmNode getDocument(String uri) throws TransformerException {
if (getSearcher() == null) {
throw new IllegalStateException ("Attempted search, but no searcher was provided");
}
try {
DocIterator disi = getSearcher().search(new TermQuery(new Term(uriFieldName, uri)));
int docID = disi.nextDoc();
if (docID == DocIdSetIterator.NO_MORE_DOCS) {
throw new NotFoundException(uri);
}
return getDocReader().get(docID, disi.getCurrentReaderContext());
} catch (IOException e) {
throw new TransformerException(e);
}
}
public LuxSearcher getSearcher () {
return evaluator.getSearcher();
}
public CachingDocReader getDocReader() {
return evaluator.getDocReader();
}
}