001: package org.apache.lucene.xmlparser;
002:
003: import java.io.ByteArrayOutputStream;
004: import java.io.IOException;
005: import java.io.InputStream;
006: import java.util.Enumeration;
007: import java.util.HashMap;
008: import java.util.Properties;
009:
010: import javax.xml.parsers.DocumentBuilder;
011: import javax.xml.parsers.DocumentBuilderFactory;
012: import javax.xml.parsers.ParserConfigurationException;
013: import javax.xml.transform.Result;
014: import javax.xml.transform.Source;
015: import javax.xml.transform.Templates;
016: import javax.xml.transform.Transformer;
017: import javax.xml.transform.TransformerConfigurationException;
018: import javax.xml.transform.TransformerException;
019: import javax.xml.transform.TransformerFactory;
020: import javax.xml.transform.dom.DOMResult;
021: import javax.xml.transform.dom.DOMSource;
022: import javax.xml.transform.stream.StreamResult;
023:
024: import org.w3c.dom.Document;
025: import org.w3c.dom.Element;
026: import org.xml.sax.SAXException;
027:
028: /**
029: * Licensed to the Apache Software Foundation (ASF) under one or more
030: * contributor license agreements. See the NOTICE file distributed with
031: * this work for additional information regarding copyright ownership.
032: * The ASF licenses this file to You under the Apache License, Version 2.0
033: * (the "License"); you may not use this file except in compliance with
034: * the License. You may obtain a copy of the License at
035: *
036: * http://www.apache.org/licenses/LICENSE-2.0
037: *
038: * Unless required by applicable law or agreed to in writing, software
039: * distributed under the License is distributed on an "AS IS" BASIS,
040: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
041: * See the License for the specific language governing permissions and
042: * limitations under the License.
043: */
044: /**
045: * Provides utilities for turning query form input (such as from a web page or Swing gui) into
046: * Lucene XML queries by using XSL templates. This approach offers a convenient way of externalizing
047: * and changing how user input is turned into Lucene queries.
048: * Database applications often adopt similar practices by externalizing SQL in template files that can
049: * be easily changed/optimized by a DBA.
050: * The static methods can be used on their own or by creating an instance of this class you can store and
051: * re-use compiled stylesheets for fast use (e.g. in a server environment)
052: * @author Mark Harwood
053: */
054: public class QueryTemplateManager {
055: static DocumentBuilderFactory dbf = DocumentBuilderFactory
056: .newInstance();
057: static TransformerFactory tFactory = TransformerFactory
058: .newInstance();
059:
060: HashMap compiledTemplatesCache = new HashMap();
061: Templates defaultCompiledTemplates = null;
062:
063: public QueryTemplateManager() {
064:
065: }
066:
067: public QueryTemplateManager(InputStream xslIs)
068: throws TransformerConfigurationException,
069: ParserConfigurationException, SAXException, IOException {
070: addDefaultQueryTemplate(xslIs);
071: }
072:
073: public void addDefaultQueryTemplate(InputStream xslIs)
074: throws TransformerConfigurationException,
075: ParserConfigurationException, SAXException, IOException {
076: defaultCompiledTemplates = getTemplates(xslIs);
077: }
078:
079: public void addQueryTemplate(String name, InputStream xslIs)
080: throws TransformerConfigurationException,
081: ParserConfigurationException, SAXException, IOException {
082: compiledTemplatesCache.put(name, getTemplates(xslIs));
083: }
084:
085: public String getQueryAsXmlString(Properties formProperties,
086: String queryTemplateName) throws SAXException, IOException,
087: ParserConfigurationException, TransformerException {
088: Templates ts = (Templates) compiledTemplatesCache
089: .get(queryTemplateName);
090: return getQueryAsXmlString(formProperties, ts);
091: }
092:
093: public Document getQueryAsDOM(Properties formProperties,
094: String queryTemplateName) throws SAXException, IOException,
095: ParserConfigurationException, TransformerException {
096: Templates ts = (Templates) compiledTemplatesCache
097: .get(queryTemplateName);
098: return getQueryAsDOM(formProperties, ts);
099: }
100:
101: public String getQueryAsXmlString(Properties formProperties)
102: throws SAXException, IOException,
103: ParserConfigurationException, TransformerException {
104: return getQueryAsXmlString(formProperties,
105: defaultCompiledTemplates);
106: }
107:
108: public Document getQueryAsDOM(Properties formProperties)
109: throws SAXException, IOException,
110: ParserConfigurationException, TransformerException {
111: return getQueryAsDOM(formProperties, defaultCompiledTemplates);
112: }
113:
114: /**
115: * Fast means of constructing query using a precompiled stylesheet
116: */
117: public static String getQueryAsXmlString(Properties formProperties,
118: Templates template) throws SAXException, IOException,
119: ParserConfigurationException, TransformerException {
120: ByteArrayOutputStream baos = new ByteArrayOutputStream();
121: StreamResult result = new StreamResult(baos);
122: transformCriteria(formProperties, template, result);
123: return baos.toString();
124: }
125:
126: /**
127: * Slow means of constructing query parsing a stylesheet from an input stream
128: */
129: public static String getQueryAsXmlString(Properties formProperties,
130: InputStream xslIs) throws SAXException, IOException,
131: ParserConfigurationException, TransformerException {
132: ByteArrayOutputStream baos = new ByteArrayOutputStream();
133: StreamResult result = new StreamResult(baos);
134: transformCriteria(formProperties, xslIs, result);
135: return baos.toString();
136: }
137:
138: /**
139: * Fast means of constructing query using a cached,precompiled stylesheet
140: */
141: public static Document getQueryAsDOM(Properties formProperties,
142: Templates template) throws SAXException, IOException,
143: ParserConfigurationException, TransformerException {
144: DOMResult result = new DOMResult();
145: transformCriteria(formProperties, template, result);
146: return (Document) result.getNode();
147: }
148:
149: /**
150: * Slow means of constructing query - parses stylesheet from input stream
151: */
152: public static Document getQueryAsDOM(Properties formProperties,
153: InputStream xslIs) throws SAXException, IOException,
154: ParserConfigurationException, TransformerException {
155: DOMResult result = new DOMResult();
156: transformCriteria(formProperties, xslIs, result);
157: return (Document) result.getNode();
158: }
159:
160: /**
161: * Slower transformation using an uncompiled stylesheet (suitable for development environment)
162: */
163: public static void transformCriteria(Properties formProperties,
164: InputStream xslIs, Result result) throws SAXException,
165: IOException, ParserConfigurationException,
166: TransformerException {
167: dbf.setNamespaceAware(true);
168: DocumentBuilder builder = dbf.newDocumentBuilder();
169: org.w3c.dom.Document xslDoc = builder.parse(xslIs);
170: DOMSource ds = new DOMSource(xslDoc);
171:
172: Transformer transformer = null;
173: synchronized (tFactory) {
174: transformer = tFactory.newTransformer(ds);
175: }
176: transformCriteria(formProperties, transformer, result);
177: }
178:
179: /**
180: * Fast transformation using a pre-compiled stylesheet (suitable for production environments)
181: */
182: public static void transformCriteria(Properties formProperties,
183: Templates template, Result result) throws SAXException,
184: IOException, ParserConfigurationException,
185: TransformerException {
186: transformCriteria(formProperties, template.newTransformer(),
187: result);
188: }
189:
190: public static void transformCriteria(Properties formProperties,
191: Transformer transformer, Result result)
192: throws SAXException, IOException,
193: ParserConfigurationException, TransformerException {
194: dbf.setNamespaceAware(true);
195:
196: //Create an XML document representing the search index document.
197: DocumentBuilder db = dbf.newDocumentBuilder();
198: org.w3c.dom.Document doc = db.newDocument();
199: Element root = doc.createElement("Document");
200: doc.appendChild(root);
201:
202: Enumeration keysEnum = formProperties.keys();
203: while (keysEnum.hasMoreElements()) {
204: String propName = (String) keysEnum.nextElement();
205: String value = formProperties.getProperty(propName);
206: if ((value != null) && (value.length() > 0)) {
207: DOMUtils.insertChild(root, propName, value);
208: }
209: }
210: //Use XSLT to to transform into an XML query string using the queryTemplate
211: DOMSource xml = new DOMSource(doc);
212: transformer.transform(xml, result);
213: }
214:
215: /**
216: * Parses a query stylesheet for repeated use
217: */
218: public static Templates getTemplates(InputStream xslIs)
219: throws ParserConfigurationException, SAXException,
220: IOException, TransformerConfigurationException {
221: dbf.setNamespaceAware(true);
222: DocumentBuilder builder = dbf.newDocumentBuilder();
223: org.w3c.dom.Document xslDoc = builder.parse(xslIs);
224: DOMSource ds = new DOMSource(xslDoc);
225: return tFactory.newTemplates(ds);
226: }
227: }
|