001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.solr.util.xslt;
017:
018: import java.io.IOException;
019: import java.io.InputStream;
020: import java.util.logging.Level;
021: import java.util.logging.Logger;
022:
023: import javax.servlet.ServletException;
024: import javax.xml.transform.Templates;
025: import javax.xml.transform.Transformer;
026: import javax.xml.transform.TransformerConfigurationException;
027: import javax.xml.transform.TransformerFactory;
028: import javax.xml.transform.stream.StreamSource;
029:
030: import org.apache.solr.core.Config;
031: import org.apache.solr.core.SolrConfig;
032: import org.apache.solr.request.XSLTResponseWriter;
033:
034: /** Singleton that creates a Transformer for the XSLTServletFilter.
035: * For now, only caches the last created Transformer, but
036: * could evolve to use an LRU cache of Transformers.
037: *
038: * See http://www.javaworld.com/javaworld/jw-05-2003/jw-0502-xsl_p.html for
039: * one possible way of improving caching.
040: */
041:
042: public class TransformerProvider {
043: public static TransformerProvider instance = new TransformerProvider();
044:
045: private final TransformerFactory tFactory = TransformerFactory
046: .newInstance();
047: private String lastFilename;
048: private Templates lastTemplates = null;
049: private long cacheExpires = 0;
050:
051: private static Logger log;
052:
053: /** singleton */
054: private TransformerProvider() {
055: log = Logger.getLogger(TransformerProvider.class.getName());
056:
057: // tell'em: currently, we only cache the last used XSLT transform, and blindly recompile it
058: // once cacheLifetimeSeconds expires
059: log
060: .warning("The TransformerProvider's simplistic XSLT caching mechanism is not appropriate "
061: + "for high load scenarios, unless a single XSLT transform is used"
062: + " and xsltCacheLifetimeSeconds is set to a sufficiently high value.");
063: }
064:
065: /** Return a new Transformer, possibly created from our cached Templates object
066: * @throws TransformerConfigurationException
067: */
068: public synchronized Transformer getTransformer(String filename,
069: int cacheLifetimeSeconds) throws IOException {
070: // For now, the Templates are blindly reloaded once cacheExpires is over.
071: // It'd be better to check the file modification time to reload only if needed.
072: if (lastTemplates != null && filename.equals(lastFilename)
073: && System.currentTimeMillis() < cacheExpires) {
074: if (log.isLoggable(Level.FINE)) {
075: log.fine("Using cached Templates:" + filename);
076: }
077: } else {
078: lastTemplates = getTemplates(filename, cacheLifetimeSeconds);
079: }
080:
081: Transformer result = null;
082:
083: try {
084: result = lastTemplates.newTransformer();
085: } catch (TransformerConfigurationException tce) {
086: log.throwing(getClass().getName(), "getTransformer", tce);
087: final IOException ioe = new IOException(
088: "newTransformer fails ( " + lastFilename + ")");
089: ioe.initCause(tce);
090: throw ioe;
091: }
092:
093: return result;
094: }
095:
096: /** Return a Templates object for the given filename */
097: private Templates getTemplates(String filename,
098: int cacheLifetimeSeconds) throws IOException {
099:
100: Templates result = null;
101: lastFilename = null;
102: try {
103: if (log.isLoggable(Level.FINE)) {
104: log.fine("compiling XSLT templates:" + filename);
105: }
106: final InputStream xsltStream = Config.openResource("xslt/"
107: + filename);
108: result = tFactory
109: .newTemplates(new StreamSource(xsltStream));
110: } catch (Exception e) {
111: log.throwing(getClass().getName(), "newTemplates", e);
112: final IOException ioe = new IOException(
113: "Unable to initialize Templates '" + filename + "'");
114: ioe.initCause(e);
115: throw ioe;
116: }
117:
118: lastFilename = filename;
119: lastTemplates = result;
120: cacheExpires = System.currentTimeMillis()
121: + (cacheLifetimeSeconds * 1000);
122:
123: return result;
124: }
125: }
|