Changes to improve server-side speed and thread safety by caching reusable, compiled stylesheets.

git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@503500 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Mark Harwood 2007-02-04 22:51:28 +00:00
parent 842995a83c
commit 0149b5f82f
2 changed files with 128 additions and 46 deletions

View File

@ -4,6 +4,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Properties;
import javax.xml.parsers.DocumentBuilder;
@ -11,7 +12,9 @@ import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
@ -21,6 +24,7 @@ import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@ -43,6 +47,8 @@ import org.xml.sax.SAXException;
* and changing how user input is turned into Lucene queries.
* Database applications often adopt similar practices by externalizing SQL in template files that can
* be easily changed/optimized by a DBA.
* The static methods can be used on their own or by creating an instance of this class you can store and
* re-use compiled stylesheets for fast use (e.g. in a server environment)
* @author Mark Harwood
*/
public class QueryTemplateManager
@ -50,42 +56,127 @@ public class QueryTemplateManager
static DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance ();
static TransformerFactory tFactory = TransformerFactory.newInstance();
public static String getQueryAsXmlString(Properties formProperties, String templateName) throws SAXException, IOException, ParserConfigurationException, TransformerException
HashMap compiledTemplatesCache=new HashMap();
Templates defaultCompiledTemplates=null;
public QueryTemplateManager()
{
return getQueryAsXmlString(formProperties,
getDOMSource(QueryTemplateManager.class.getResourceAsStream(templateName)));
}
public QueryTemplateManager(InputStream xslIs) throws TransformerConfigurationException, ParserConfigurationException, SAXException, IOException
{
addDefaultQueryTemplate(xslIs);
}
public void addDefaultQueryTemplate(InputStream xslIs) throws TransformerConfigurationException, ParserConfigurationException, SAXException, IOException
{
defaultCompiledTemplates=getTemplates(xslIs);
}
public void addQueryTemplate(String name, InputStream xslIs) throws TransformerConfigurationException, ParserConfigurationException, SAXException, IOException
{
compiledTemplatesCache.put(name,getTemplates(xslIs));
}
public String getQueryAsXmlString(Properties formProperties,String queryTemplateName) throws SAXException, IOException, ParserConfigurationException, TransformerException
{
Templates ts=(Templates) compiledTemplatesCache.get(queryTemplateName);
return getQueryAsXmlString(formProperties, ts);
}
public static String getQueryAsXmlString(Properties formProperties, Source xslDs) throws SAXException, IOException, ParserConfigurationException, TransformerException
public Document getQueryAsDOM(Properties formProperties,String queryTemplateName) throws SAXException, IOException, ParserConfigurationException, TransformerException
{
Templates ts=(Templates) compiledTemplatesCache.get(queryTemplateName);
return getQueryAsDOM(formProperties, ts);
}
public String getQueryAsXmlString(Properties formProperties) throws SAXException, IOException, ParserConfigurationException, TransformerException
{
return getQueryAsXmlString(formProperties, defaultCompiledTemplates);
}
public Document getQueryAsDOM(Properties formProperties) throws SAXException, IOException, ParserConfigurationException, TransformerException
{
return getQueryAsDOM(formProperties, defaultCompiledTemplates);
}
/**
* Fast means of constructing query using a precompiled stylesheet
*/
public static String getQueryAsXmlString(Properties formProperties, Templates template) throws SAXException, IOException, ParserConfigurationException, TransformerException
{
ByteArrayOutputStream baos=new ByteArrayOutputStream();
StreamResult result=new StreamResult(baos);
transformCriteria(formProperties,xslDs,result);
transformCriteria(formProperties,template,result);
return baos.toString();
}
public static Document getQueryAsDOM(Properties formProperties, String templateName) throws SAXException, IOException, ParserConfigurationException, TransformerException
/**
* Slow means of constructing query parsing a stylesheet from an input stream
*/
public static String getQueryAsXmlString(Properties formProperties, InputStream xslIs) throws SAXException, IOException, ParserConfigurationException, TransformerException
{
return getQueryAsDOM(formProperties, getDOMSource(QueryTemplateManager.class.getResourceAsStream(templateName)));
}
public static Document getQueryAsDOM(Properties formProperties, InputStream xslIs) throws SAXException, IOException, ParserConfigurationException, TransformerException
{
return getQueryAsDOM(formProperties, getDOMSource(xslIs));
ByteArrayOutputStream baos=new ByteArrayOutputStream();
StreamResult result=new StreamResult(baos);
transformCriteria(formProperties,xslIs,result);
return baos.toString();
}
public static Document getQueryAsDOM(Properties formProperties, Source xslDs) throws SAXException, IOException, ParserConfigurationException, TransformerException
/**
* Fast means of constructing query using a cached,precompiled stylesheet
*/
public static Document getQueryAsDOM(Properties formProperties, Templates template) throws SAXException, IOException, ParserConfigurationException, TransformerException
{
DOMResult result=new DOMResult();
transformCriteria(formProperties,xslDs,result);
transformCriteria(formProperties,template,result);
return (Document)result.getNode();
}
public static void transformCriteria(Properties formProperties, Source xslDs, Result result) throws SAXException, IOException, ParserConfigurationException, TransformerException
/**
* Slow means of constructing query - parses stylesheet from input stream
*/
public static Document getQueryAsDOM(Properties formProperties, InputStream xslIs) throws SAXException, IOException, ParserConfigurationException, TransformerException
{
DOMResult result=new DOMResult();
transformCriteria(formProperties,xslIs,result);
return (Document)result.getNode();
}
/**
* Slower transformation using an uncompiled stylesheet (suitable for development environment)
*/
public static void transformCriteria(Properties formProperties, InputStream xslIs, Result result) throws SAXException, IOException, ParserConfigurationException, TransformerException
{
dbf.setNamespaceAware(true);
DocumentBuilder builder = dbf.newDocumentBuilder();
org.w3c.dom.Document xslDoc = builder.parse(xslIs);
DOMSource ds = new DOMSource(xslDoc);
Transformer transformer =null;
synchronized (tFactory)
{
transformer = tFactory.newTransformer(ds);
}
transformCriteria(formProperties,transformer,result);
}
/**
* Fast transformation using a pre-compiled stylesheet (suitable for production environments)
*/
public static void transformCriteria(Properties formProperties, Templates template, Result result) throws SAXException, IOException, ParserConfigurationException, TransformerException
{
transformCriteria(formProperties,template.newTransformer(),result);
}
public static void transformCriteria(Properties formProperties, Transformer transformer, Result result) throws SAXException, IOException, ParserConfigurationException, TransformerException
{
dbf.setNamespaceAware(true);
Transformer transformer = tFactory.newTransformer(xslDs);
//Create an XML document representing the search index document.
DocumentBuilder db = dbf.newDocumentBuilder ();
org.w3c.dom.Document doc = db.newDocument ();
@ -107,11 +198,15 @@ public class QueryTemplateManager
transformer.transform(xml,result);
}
public static DOMSource getDOMSource(InputStream xslIs) throws ParserConfigurationException, SAXException, IOException
/**
* Parses a query stylesheet for repeated use
*/
public static Templates getTemplates(InputStream xslIs) throws ParserConfigurationException, SAXException, IOException, TransformerConfigurationException
{
dbf.setNamespaceAware(true);
DocumentBuilder builder = dbf.newDocumentBuilder();
org.w3c.dom.Document xslDoc = builder.parse(xslIs);
return new DOMSource(xslDoc);
DOMSource ds = new DOMSource(xslDoc);
return tFactory.newTemplates(ds);
}
}

View File

@ -1,15 +1,11 @@
package org.apache.lucene.xmlparser;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Properties;
import java.util.StringTokenizer;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMSource;
import junit.framework.TestCase;
@ -24,6 +20,7 @@ import org.apache.lucene.search.Query;
import org.apache.lucene.store.RAMDirectory;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@ -49,7 +46,6 @@ public class TestQueryTemplateManager extends TestCase {
CoreParser builder;
Analyzer analyzer=new StandardAnalyzer();
HashMap templates=new HashMap();
private IndexSearcher searcher;
//A collection of documents' field values for use in our tests
@ -66,26 +62,31 @@ public class TestQueryTemplateManager extends TestCase {
// a choice of query style template to use in the test, with expected number of hits
String queryForms[]=
{
"artist=Fugazi \texpectedMatches=2 \ttemplate=albumBooleanQuery.xsl",
"artist=Fugazi \treleaseDate=1990 \texpectedMatches=1 \ttemplate=albumBooleanQuery.xsl",
"artist=Buckley \tgenre=rock \texpectedMatches=1 \ttemplate=albumFilteredQuery.xsl",
"artist=Buckley \tgenre=electronic \texpectedMatches=0 \ttemplate=albumFilteredQuery.xsl",
"queryString=artist:buckly~ NOT genre:electronic \texpectedMatches=1 \ttemplate=albumLuceneClassicQuery.xsl"
"artist=Fugazi \texpectedMatches=2 \ttemplate=albumBooleanQuery",
"artist=Fugazi \treleaseDate=1990 \texpectedMatches=1 \ttemplate=albumBooleanQuery",
"artist=Buckley \tgenre=rock \texpectedMatches=1 \ttemplate=albumFilteredQuery",
"artist=Buckley \tgenre=electronic \texpectedMatches=0 \ttemplate=albumFilteredQuery",
"queryString=artist:buckly~ NOT genre:electronic \texpectedMatches=1 \ttemplate=albumLuceneClassicQuery"
};
public void testFormTransforms() throws SAXException, IOException, ParserConfigurationException, TransformerException, ParserException
{
//Cache all the query templates we will be referring to.
QueryTemplateManager qtm=new QueryTemplateManager();
qtm.addQueryTemplate("albumBooleanQuery", getClass().getResourceAsStream("albumBooleanQuery.xsl"));
qtm.addQueryTemplate("albumFilteredQuery", getClass().getResourceAsStream("albumFilteredQuery.xsl"));
qtm.addQueryTemplate("albumLuceneClassicQuery", getClass().getResourceAsStream("albumLuceneClassicQuery.xsl"));
//Run all of our test queries
for (int i = 0; i < queryForms.length; i++)
{
Properties queryFormProperties=getPropsFromString(queryForms[i]);
//Get the required query XSL template for this test
Source template=getTemplate(queryFormProperties.getProperty("template"));
// Templates template=getTemplate(queryFormProperties.getProperty("template"));
//Transform the queryFormProperties into a Lucene XML query
Document doc=QueryTemplateManager.getQueryAsDOM(queryFormProperties,template);
Document doc=qtm.getQueryAsDOM(queryFormProperties,queryFormProperties.getProperty("template"));
//Parse the XML query using the XML parser
Query q=builder.getQuery(doc.getDocumentElement());
@ -100,20 +101,6 @@ public class TestQueryTemplateManager extends TestCase {
}
}
private Source getTemplate(String templateName) throws ParserConfigurationException, SAXException, IOException
{
Source result=(Source) templates.get(templateName);
if(result==null)
{
//Not yet loaded - load the stylesheet
result=QueryTemplateManager.getDOMSource(getClass().getResourceAsStream(templateName));
templates.put(templateName,result);
}
return result;
}
//Helper method to construct Lucene query forms used in our test
Properties getPropsFromString(String nameValuePairs)
{