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