openwfe.org.xml.XmlDocumentCache Maven / Gradle / Ivy
/*
* Copyright (c) 2006, John Mettraux, OpenWFE.org
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* . Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* . Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* . Neither the name of the "OpenWFE" nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $Id: AbstractService.java 2673 2006-05-26 21:08:46Z jmettraux $
*/
//
// XmlDocumentCache.java
//
// [email protected]
//
// generated with
// jtmpl 1.1.01 2004/05/19 ([email protected])
//
package openwfe.org.xml;
import openwfe.org.Utils;
import openwfe.org.FileUtils;
import openwfe.org.misc.Cache;
/**
* Caching XML documents (especially if they haven't been modified
* recently).
* The main motivation behind this implementation is a serie of
* benchmarks by Nicolas Modryzk.
*
* CVS Info :
*
$Author$
*
$Id$
*
* @author [email protected]
*/
public class XmlDocumentCache
{
private final static org.apache.log4j.Logger log = org.apache.log4j.Logger
.getLogger(XmlDocumentCache.class.getName());
//
// CONSTANTS & co
/**
* This System Property (SP) 'openwfe.org.xml.XmlDocumentCache' may
* take the values 'true', 'false', 'on', 'off';
* When turned off or set to false, it means that no XML caching
* will take place.
*/
public final static String SP_XML_DOCUMENT_CACHE
= XmlDocumentCache.class.getName();
//
// FIELDS
private Cache cache = null;
//
// CONSTRUCTORS
/**
* Prepares a cache
*/
public XmlDocumentCache ()
{
this(77);
}
/**
* Prepares a cache (with a given max number of cached elements).
*/
public XmlDocumentCache (final int maxSize)
{
super();
// is caching turned off ?
if ( ! Utils.toBoolean
(System.getProperty(SP_XML_DOCUMENT_CACHE), true))
{
log.info("() XML caching is disabled.");
return;
}
this.cache = new Cache(maxSize);
}
//
// METHODS
/**
* Returns the XML org.jdom.Element corresponding to the given url
* (or the XML contained in the string).
* Will attempt to fetch it from the cache, if what's in the cache
* is not fresh, will reload the doc and cache it (again).
* If it's not present in the cache, will load it and cache it.
*/
public org.jdom.Document get
(final String urlOrXmlString, final boolean shouldValidate)
throws
org.jdom.JDOMException, java.io.IOException
{
//if (url.startsWith(XmlUtils.RESOURCE_URL_PREFIX))
// return XmlUtils.extractXml(url, shouldValidate);
if (log.isDebugEnabled())
log.debug("get() for |"+urlOrXmlString.substring(0, 10)+"|");
if ( ! urlOrXmlString.trim().startsWith("<"))
return get(new java.net.URL(urlOrXmlString), shouldValidate);
final String key =
"s__" + urlOrXmlString.hashCode() + "__" + urlOrXmlString.length();
//final DocumentEntry de = (DocumentEntry)this.cache.get(key);
final DocumentEntry de = getFromCache(key);
//log.debug("get() xml is\n"+urlOrXmlString);
if (de != null)
{
if (log.isDebugEnabled())
log.debug("get() doc '"+key+"' already in cache");
return de.cloneDoc();
}
final long start = System.currentTimeMillis();
final org.jdom.Document doc = XmlUtils.doExtractXmlDocument
(urlOrXmlString, shouldValidate);
//this.cache.put
// (key,
// new DocumentEntry(key, -1, doc));
putInCache(key, -1, doc);
if (log.isDebugEnabled())
{
log.debug
("get() "+
"had to parse doc '"+key+
"' (took "+(System.currentTimeMillis()-start)+" ms)");
}
return doc;
}
/**
* Like get(s, sv) but directly returns the root element.
*/
public org.jdom.Element getElement
(final String urlOrXmlString, final boolean shouldValidate)
throws
org.jdom.JDOMException, java.io.IOException
{
final org.jdom.Document doc = get(urlOrXmlString, shouldValidate);
if (doc == null) return null;
return doc.getRootElement();
//
// should we detach() ?
}
/**
* Returns the XML org.jdom.Element corresponding to the given url.
* Will attempt to fetch it from the cache, if what's in the cache
* is not fresh, will reload the doc and cache it (again).
* If it's not present in the cache, will load it and cache it.
*/
public org.jdom.Document get
(final java.net.URL url, final boolean shouldValidate)
throws
org.jdom.JDOMException, java.io.IOException
{
final String sUrl = url.toString();
if (log.isDebugEnabled())
log.debug("get() cs"+this.cacheSize()+" for "+sUrl);
//final DocumentEntry de = (DocumentEntry)this.cache.get(sUrl);
final DocumentEntry de = getFromCache(sUrl);
long newLastModified = -1;
if (de != null)
{
newLastModified = FileUtils.getLastModified(url);
if (log.isDebugEnabled())
{
//log.debug("get() cached "+de.getLastModified());
//log.debug("get() server "+newLastModified);
if (newLastModified == 0)
log.debug("get() last-modified is 0, have to reload");
}
if (newLastModified != 0 &&
newLastModified <= de.getLastModified())
{
return de.cloneDoc();
}
// a '0' reply means the server doesn't know when the
// ressource was modified. Possibly some CGI / JSP
}
//
// have to reload
long start = System.currentTimeMillis();
if (newLastModified < 0)
newLastModified = FileUtils.getLastModified(url);
//final org.jdom.Element doc = XmlUtils.extractXml(url, shouldValidate);
final org.jdom.input.SAXBuilder builder =
XmlUtils.getSAXBuilder(shouldValidate);
final org.jdom.Document doc = builder.build(url);
if (doc == null) return null;
//this.cache.put
// (sUrl,
// new DocumentEntry(sUrl, newLastModified, doc));
putInCache(sUrl, newLastModified, doc);
if (log.isDebugEnabled())
{
final long duration = System.currentTimeMillis() - start;
log.debug
("get() cs"+cacheSize()+
" loading the doc at "+sUrl+" took "+duration+" ms");
}
return doc;
// note : the Cache class is synchronized
}
/**
* Like get(url, sv) but directly returns the root element.
*/
public org.jdom.Element getElement
(final java.net.URL url, final boolean shouldValidate)
throws
org.jdom.JDOMException, java.io.IOException
{
final org.jdom.Document doc = get(url, shouldValidate);
if (doc == null) return null;
return doc.getRootElement();
//
// should we detach() ?
}
/**
* Puts the document and its info into the cache.
* If caching is disabled, nothing will get done.
*/
protected void putInCache
(final String key,
final long lastModified,
final org.jdom.Document doc)
{
if (this.cache == null) return;
this.cache.put
(key,
new DocumentEntry(key, lastModified, doc));
}
/**
* Raw get from the cache.
* If caching is disabled, will immediately return null.
*/
protected DocumentEntry getFromCache (final String key)
{
if (this.cache == null) return null;
return (DocumentEntry)this.cache.get(key);
}
/**
* Returns the current size of the cache or null if the caching
* of XML documents is disabled.
*/
protected int cacheSize ()
{
if (this.cache == null) return -1;
return this.cache.size();
}
//
// STATIC METHODS
//
// INNER CLASSES
private class DocumentEntry
{
private String key = null;
private long lastModified = -1;
private org.jdom.Document doc = null;
public DocumentEntry
(final String key,
final long lastModified,
final org.jdom.Document doc)
{
super();
this.key = key;
this.lastModified = lastModified;
this.doc = (org.jdom.Document)doc.clone();
}
public long getLastModified ()
{
return this.lastModified;
}
public org.jdom.Document cloneDoc ()
{
final long start = System.currentTimeMillis();
final org.jdom.Document result =
(org.jdom.Document)this.doc.clone();
if (log.isDebugEnabled())
{
final long duration = System.currentTimeMillis() - start;
log.debug
("cloneDoc() (cs"+XmlDocumentCache.this.cacheSize()+
") took "+duration+" ms for "+this.key);
}
// remove me as soon as problem fixed !!!
//
//if (result == null)
// log.warn("cloneDoc() null result !!!");
//else if (result.getRootElement() == null)
// log.warn("cloneDoc() null root element !!!");
return result;
}
}
}