package org.apache.lucene.xmlparser; 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; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Result; 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; import javax.xml.transform.dom.DOMSource; 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 * 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. */ /** * Provides utilities for turning query form input (such as from a web page or Swing gui) into * Lucene XML queries by using XSL templates. This approach offers a convenient way of externalizing * 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) */ public class QueryTemplateManager { static DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance (); static TransformerFactory tFactory = TransformerFactory.newInstance(); HashMap<String,Templates> compiledTemplatesCache=new HashMap<String,Templates>(); Templates defaultCompiledTemplates=null; public QueryTemplateManager() { } 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= compiledTemplatesCache.get(queryTemplateName); return getQueryAsXmlString(formProperties, ts); } public Document getQueryAsDOM(Properties formProperties,String queryTemplateName) throws SAXException, IOException, ParserConfigurationException, TransformerException { Templates ts= 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,template,result); return baos.toString(); } /** * 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 { ByteArrayOutputStream baos=new ByteArrayOutputStream(); StreamResult result=new StreamResult(baos); transformCriteria(formProperties,xslIs,result); return baos.toString(); } /** * 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,template,result); return (Document)result.getNode(); } /** * 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); //Create an XML document representing the search index document. DocumentBuilder db = dbf.newDocumentBuilder (); org.w3c.dom.Document doc = db.newDocument (); Element root = doc.createElement ("Document"); doc.appendChild (root); Enumeration keysEnum = formProperties.keys(); while(keysEnum.hasMoreElements()) { String propName=(String) keysEnum.nextElement(); String value=formProperties.getProperty(propName); if((value!=null)&&(value.length()>0)) { DOMUtils.insertChild(root,propName,value); } } //Use XSLT to to transform into an XML query string using the queryTemplate DOMSource xml=new DOMSource(doc); transformer.transform(xml,result); } /** * 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); DOMSource ds = new DOMSource(xslDoc); return tFactory.newTemplates(ds); } }