286N/A/*
286N/A * reserved comment block
286N/A * DO NOT REMOVE OR ALTER!
286N/A */
286N/A/*
286N/A * Copyright 2001-2004 The Apache Software Foundation.
286N/A *
286N/A * Licensed under the Apache License, Version 2.0 (the "License");
286N/A * you may not use this file except in compliance with the License.
286N/A * You may obtain a copy of the License at
286N/A *
286N/A * http://www.apache.org/licenses/LICENSE-2.0
286N/A *
286N/A * Unless required by applicable law or agreed to in writing, software
286N/A * distributed under the License is distributed on an "AS IS" BASIS,
286N/A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
286N/A * See the License for the specific language governing permissions and
286N/A * limitations under the License.
286N/A */
286N/A/*
286N/A * $Id: DocumentCache.java,v 1.2.4.1 2005/09/06 06:15:22 pvedula Exp $
286N/A */
286N/A
286N/Apackage com.sun.org.apache.xalan.internal.xsltc.dom;
286N/A
286N/Aimport java.io.File;
286N/Aimport java.io.PrintWriter;
286N/Aimport java.net.URL;
286N/Aimport java.net.URLConnection;
286N/Aimport java.net.URLDecoder;
286N/Aimport java.util.Date;
286N/Aimport java.util.Hashtable;
286N/A
286N/Aimport javax.xml.parsers.ParserConfigurationException;
286N/Aimport javax.xml.parsers.SAXParser;
286N/Aimport javax.xml.parsers.SAXParserFactory;
286N/Aimport javax.xml.transform.TransformerException;
286N/Aimport javax.xml.transform.sax.SAXSource;
286N/A
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.DOM;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.DOMCache;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.DOMEnhancedForDTM;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.Translet;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.runtime.Constants;
286N/Aimport com.sun.org.apache.xml.internal.utils.SystemIDResolver;
286N/A
286N/Aimport org.xml.sax.InputSource;
286N/Aimport org.xml.sax.SAXException;
286N/Aimport org.xml.sax.XMLReader;
286N/A
286N/A/**
286N/A * @author Morten Jorgensen
286N/A */
286N/Apublic final class DocumentCache implements DOMCache {
286N/A
286N/A private int _size;
286N/A private Hashtable _references;
286N/A private String[] _URIs;
286N/A private int _count;
286N/A private int _current;
286N/A private SAXParser _parser;
286N/A private XMLReader _reader;
286N/A private XSLTCDTMManager _dtmManager;
286N/A
286N/A private static final int REFRESH_INTERVAL = 1000;
286N/A
286N/A /*
286N/A * Inner class containing a DOMImpl object and DTD handler
286N/A */
286N/A public final class CachedDocument {
286N/A
286N/A // Statistics data
286N/A private long _firstReferenced;
286N/A private long _lastReferenced;
286N/A private long _accessCount;
286N/A private long _lastModified;
286N/A private long _lastChecked;
286N/A private long _buildTime;
286N/A
286N/A // DOM and DTD handler references
286N/A private DOMEnhancedForDTM _dom = null;
286N/A
286N/A /**
286N/A * Constructor - load document and initialise statistics
286N/A */
286N/A public CachedDocument(String uri) {
286N/A // Initialise statistics variables
286N/A final long stamp = System.currentTimeMillis();
286N/A _firstReferenced = stamp;
286N/A _lastReferenced = stamp;
286N/A _accessCount = 0;
286N/A loadDocument(uri);
286N/A
286N/A _buildTime = System.currentTimeMillis() - stamp;
286N/A }
286N/A
286N/A /**
286N/A * Loads the document and updates build-time (latency) statistics
286N/A */
286N/A public void loadDocument(String uri) {
286N/A
286N/A try {
286N/A final long stamp = System.currentTimeMillis();
286N/A _dom = (DOMEnhancedForDTM)_dtmManager.getDTM(
286N/A new SAXSource(_reader, new InputSource(uri)),
286N/A false, null, true, false);
286N/A _dom.setDocumentURI(uri);
286N/A
286N/A // The build time can be used for statistics for a better
286N/A // priority algorithm (currently round robin).
286N/A final long thisTime = System.currentTimeMillis() - stamp;
286N/A if (_buildTime > 0)
286N/A _buildTime = (_buildTime + thisTime) >>> 1;
286N/A else
286N/A _buildTime = thisTime;
286N/A }
286N/A catch (Exception e) {
286N/A _dom = null;
286N/A }
286N/A }
286N/A
286N/A public DOM getDocument() { return(_dom); }
286N/A
286N/A public long getFirstReferenced() { return(_firstReferenced); }
286N/A
286N/A public long getLastReferenced() { return(_lastReferenced); }
286N/A
286N/A public long getAccessCount() { return(_accessCount); }
286N/A
286N/A public void incAccessCount() { _accessCount++; }
286N/A
286N/A public long getLastModified() { return(_lastModified); }
286N/A
286N/A public void setLastModified(long t){ _lastModified = t; }
286N/A
286N/A public long getLatency() { return(_buildTime); }
286N/A
286N/A public long getLastChecked() { return(_lastChecked); }
286N/A
286N/A public void setLastChecked(long t) { _lastChecked = t; }
286N/A
286N/A public long getEstimatedSize() {
286N/A if (_dom != null)
286N/A return(_dom.getSize() << 5); // ???
286N/A else
286N/A return(0);
286N/A }
286N/A
286N/A }
286N/A
286N/A /**
286N/A * DocumentCache constructor
286N/A */
286N/A public DocumentCache(int size) throws SAXException {
286N/A this(size, null);
286N/A try {
286N/A _dtmManager = (XSLTCDTMManager)XSLTCDTMManager.getDTMManagerClass()
286N/A .newInstance();
286N/A } catch (Exception e) {
286N/A throw new SAXException(e);
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * DocumentCache constructor
286N/A */
286N/A public DocumentCache(int size, XSLTCDTMManager dtmManager) throws SAXException {
286N/A _dtmManager = dtmManager;
286N/A _count = 0;
286N/A _current = 0;
286N/A _size = size;
286N/A _references = new Hashtable(_size+2);
286N/A _URIs = new String[_size];
286N/A
286N/A try {
286N/A // Create a SAX parser and get the XMLReader object it uses
286N/A final SAXParserFactory factory = SAXParserFactory.newInstance();
286N/A try {
286N/A factory.setFeature(Constants.NAMESPACE_FEATURE,true);
286N/A }
286N/A catch (Exception e) {
286N/A factory.setNamespaceAware(true);
286N/A }
286N/A _parser = factory.newSAXParser();
286N/A _reader = _parser.getXMLReader();
286N/A }
286N/A catch (ParserConfigurationException e) {
286N/A BasisLibrary.runTimeError(BasisLibrary.NAMESPACES_SUPPORT_ERR);
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * Returns the time-stamp for a document's last update
286N/A */
286N/A private final long getLastModified(String uri) {
286N/A try {
286N/A URL url = new URL(uri);
286N/A URLConnection connection = url.openConnection();
286N/A long timestamp = connection.getLastModified();
286N/A // Check for a "file:" URI (courtesy of Brian Ewins)
286N/A if (timestamp == 0){ // get 0 for local URI
286N/A if ("file".equals(url.getProtocol())){
286N/A File localfile = new File(URLDecoder.decode(url.getFile()));
286N/A timestamp = localfile.lastModified();
286N/A }
286N/A }
286N/A return(timestamp);
286N/A }
286N/A // Brutal handling of all exceptions
286N/A catch (Exception e) {
286N/A return(System.currentTimeMillis());
286N/A }
286N/A }
286N/A
286N/A /**
286N/A *
286N/A */
286N/A private CachedDocument lookupDocument(String uri) {
286N/A return((CachedDocument)_references.get(uri));
286N/A }
286N/A
286N/A /**
286N/A *
286N/A */
286N/A private synchronized void insertDocument(String uri, CachedDocument doc) {
286N/A if (_count < _size) {
286N/A // Insert out URI in circular buffer
286N/A _URIs[_count++] = uri;
286N/A _current = 0;
286N/A }
286N/A else {
286N/A // Remove oldest URI from reference Hashtable
286N/A _references.remove(_URIs[_current]);
286N/A // Insert our URI in circular buffer
286N/A _URIs[_current] = uri;
286N/A if (++_current >= _size) _current = 0;
286N/A }
286N/A _references.put(uri, doc);
286N/A }
286N/A
286N/A /**
286N/A *
286N/A */
286N/A private synchronized void replaceDocument(String uri, CachedDocument doc) {
286N/A CachedDocument old = (CachedDocument)_references.get(uri);
286N/A if (doc == null)
286N/A insertDocument(uri, doc);
286N/A else
286N/A _references.put(uri, doc);
286N/A }
286N/A
286N/A /**
286N/A * Returns a document either by finding it in the cache or
286N/A * downloading it and putting it in the cache.
286N/A */
286N/A public DOM retrieveDocument(String baseURI, String href, Translet trs) {
286N/A CachedDocument doc;
286N/A
286N/A String uri = href;
286N/A if (baseURI != null && !baseURI.equals("")) {
286N/A try {
286N/A uri = SystemIDResolver.getAbsoluteURI(uri, baseURI);
286N/A } catch (TransformerException te) {
286N/A // ignore
286N/A }
286N/A }
286N/A
286N/A // Try to get the document from the cache first
286N/A if ((doc = lookupDocument(uri)) == null) {
286N/A doc = new CachedDocument(uri);
286N/A if (doc == null) return null; // better error handling needed!!!
286N/A doc.setLastModified(getLastModified(uri));
286N/A insertDocument(uri, doc);
286N/A }
286N/A // If the document is in the cache we must check if it is still valid
286N/A else {
286N/A long now = System.currentTimeMillis();
286N/A long chk = doc.getLastChecked();
286N/A doc.setLastChecked(now);
286N/A // Has the modification time for this file been checked lately?
286N/A if (now > (chk + REFRESH_INTERVAL)) {
286N/A doc.setLastChecked(now);
286N/A long last = getLastModified(uri);
286N/A // Reload document if it has been modified since last download
286N/A if (last > doc.getLastModified()) {
286N/A doc = new CachedDocument(uri);
286N/A if (doc == null) return null;
286N/A doc.setLastModified(getLastModified(uri));
286N/A replaceDocument(uri, doc);
286N/A }
286N/A }
286N/A
286N/A }
286N/A
286N/A // Get the references to the actual DOM and DTD handler
286N/A final DOM dom = doc.getDocument();
286N/A
286N/A // The dom reference may be null if the URL pointed to a
286N/A // non-existing document
286N/A if (dom == null) return null;
286N/A
286N/A doc.incAccessCount(); // For statistics
286N/A
286N/A final AbstractTranslet translet = (AbstractTranslet)trs;
286N/A
286N/A // Give the translet an early opportunity to extract any
286N/A // information from the DOM object that it would like.
286N/A translet.prepassDocument(dom);
286N/A
286N/A return(doc.getDocument());
286N/A }
286N/A
286N/A /**
286N/A * Outputs the cache statistics
286N/A */
286N/A public void getStatistics(PrintWriter out) {
286N/A out.println("<h2>DOM cache statistics</h2><center><table border=\"2\">"+
286N/A "<tr><td><b>Document URI</b></td>"+
286N/A "<td><center><b>Build time</b></center></td>"+
286N/A "<td><center><b>Access count</b></center></td>"+
286N/A "<td><center><b>Last accessed</b></center></td>"+
286N/A "<td><center><b>Last modified</b></center></td></tr>");
286N/A
286N/A for (int i=0; i<_count; i++) {
286N/A CachedDocument doc = (CachedDocument)_references.get(_URIs[i]);
286N/A out.print("<tr><td><a href=\""+_URIs[i]+"\">"+
286N/A "<font size=-1>"+_URIs[i]+"</font></a></td>");
286N/A out.print("<td><center>"+doc.getLatency()+"ms</center></td>");
286N/A out.print("<td><center>"+doc.getAccessCount()+"</center></td>");
286N/A out.print("<td><center>"+(new Date(doc.getLastReferenced()))+
286N/A "</center></td>");
286N/A out.print("<td><center>"+(new Date(doc.getLastModified()))+
286N/A "</center></td>");
286N/A out.println("</tr>");
286N/A }
286N/A
286N/A out.println("</table></center>");
286N/A }
286N/A}