/*
* ScriptCache.java
*
* Created on July 18, 2007, 2:07 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package org.atomojo.www.util.script;
import org.atomojo.www.util.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URI;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.HttpsURLConnection;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamSource;
/**
*
* @author alex
*/
public class ScriptCache
{
static Logger LOG = Logger.getLogger(ScriptCache.class.getName());
class Location {
URI location;
String username;
String password;
String contentType;
Location(URI location,String username, String password)
{
this.location = location;
this.username = username;
this.password = password==null ? "" : password;
this.contentType = null;
}
String getContentType() {
return contentType;
}
Reader open()
throws IOException
{
URLConnection connection = location.toURL().openConnection();
if (connection instanceof HttpsURLConnection) {
HttpsURLConnection https = (HttpsURLConnection)connection;
https.setHostnameVerifier(org.apache.commons.ssl.HostnameVerifier.DEFAULT_AND_LOCALHOST);
}
if (username!=null) {
connection.setRequestProperty("Authorization", "Basic " + Base64Coder.encode(username+':'+password));
}
String charset = "UTF-8";
InputStream is = connection.getInputStream();
contentType = connection.getContentType();
if (contentType!=null) {
int semicolon = contentType.indexOf(';');
if (semicolon>=0) {
String type = contentType.substring(0,semicolon);
String rest = contentType.substring(semicolon+1);
int start = rest.indexOf("charset=");
if (start>=0) {
charset = rest.substring(start+8);
}
contentType = type;
}
}
return new InputStreamReader(is,charset);
}
}
Map<URI,Location> locations;
Map<URI,List<Transformer>> cache;
ScriptCompiler compiler;
/** Creates a new instance of ScriptCache */
public ScriptCache()
{
locations = new TreeMap<URI,Location>();
cache = new TreeMap<URI,List<Transformer>>();
compiler = new ScriptCompiler();
}
public void add(URI location)
{
add(location,null,null,true);
}
public void add(URI location,boolean replace)
{
add(location,null,null,replace);
}
public void add(URI location,String username,String password,boolean replace)
{
if (!replace && locations.get(location)!=null) {
return;
}
locations.put(location,new Location(location,username,password));
}
public boolean hasScript(URI uri) {
return locations.get(uri)!=null;
}
public Transformer get(URI uri)
throws IOException,TransformerConfigurationException,TransformerException
{
List<Transformer> cachedList = cache.get(uri);
if (cachedList==null || cachedList.size()==0) {
LOG.info("Loading new transformer "+uri);
Location location = locations.get(uri);
if (location==null) {
return null;
}
Reader reader = location.open();
Transformer transformer = transformer = compiler.compileToTransformer(new StreamSource(reader,location.location.toString()));
synchronized (cache) {
if (cachedList==null) {
cachedList = new ArrayList<Transformer>();
cache.put(uri,cachedList);
}
}
return transformer;
} else {
synchronized (cachedList) {
return cachedList.remove(0);
}
}
}
public void release(URI location,Transformer transformer)
{
List<Transformer> cachedList = cache.get(location);
if (cachedList==null) {
throw new RuntimeException("Cached list for template name "+location+" is null on release(). This shouldn't happen!");
}
LOG.info("Releasing "+location);
transformer.reset();
// Saxon doesn't reset the document pool. Boo!
try {
transformer.getClass().getMethod("clearDocumentPool").invoke(transformer);
} catch (NoSuchMethodException ex) {
// throw this away, not Saxon
} catch (Exception ex) {
LOG.log(Level.SEVERE,"Cannot reset the document pool.",ex);
}
cachedList.add(transformer);
}
public void remove(URI location) {
synchronized (cache) {
locations.remove(location);
cache.remove(location);
}
}
public void reload(URI location) {
List<Transformer> cachedList = cache.get(location);
if (cachedList!=null) {
cachedList.clear();
}
}
}