diff options
Diffstat (limited to 'src/com/itmill/toolkit/terminal/web/UIDLTransformerFactory.java')
-rw-r--r-- | src/com/itmill/toolkit/terminal/web/UIDLTransformerFactory.java | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/src/com/itmill/toolkit/terminal/web/UIDLTransformerFactory.java b/src/com/itmill/toolkit/terminal/web/UIDLTransformerFactory.java new file mode 100644 index 0000000000..fc57b71a84 --- /dev/null +++ b/src/com/itmill/toolkit/terminal/web/UIDLTransformerFactory.java @@ -0,0 +1,302 @@ +/* ************************************************************************* + + IT Mill Toolkit + + Development of Browser User Intarfaces Made Easy + + Copyright (C) 2000-2006 IT Mill Ltd + + ************************************************************************* + + This product is distributed under commercial license that can be found + from the product package on license/license.txt. Use of this product might + require purchasing a commercial license from IT Mill Ltd. For guidelines + on usage, see license/licensing-guidelines.html + + ************************************************************************* + + For more information, contact: + + IT Mill Ltd phone: +358 2 4802 7180 + Ruukinkatu 2-4 fax: +358 2 4802 7181 + 20540, Turku email: info@itmill.com + Finland company www: www.itmill.com + + Primary source for information and releases: www.itmill.com + + ********************************************************************** */ + +package com.itmill.toolkit.terminal.web; + +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.Iterator; + +/** Class implementing the MillStone WebAdapter UIDLTransformer Factory. + * The factory creates and maintains a pool of transformers that are used + * for transforming UIDL to HTML. + * + * @author IT Mill Ltd. + * @version @VERSION@ + * @since 3.0 + */ + +public class UIDLTransformerFactory { + + /** Time between repository modified queries. */ + private static final int CACHE_CHECK_INTERVAL_MILLIS = 5 * 1000; + + /** The time transformers are cached by default*/ + private static final long DEFAULT_TRANSFORMER_CACHETIME = 60 * 60 * 1000; + + /** Maximum number of transformers in use */ + private int maxConcurrentTransformers = 1; + + /** Last time theme modification time was checked */ + private long lastModificationCheckTime = 0; + + /** Last time theme source was modified */ + private long themeSourceModificationTime = 0; + + /** How long to cache transformers. */ + private long cacheTime = DEFAULT_TRANSFORMER_CACHETIME; + + /** Spool manager thread */ + private SpoolManager spoolManager; + + private Map transformerSpool = new HashMap(); + private ThemeSource themeSource; + private WebAdapterServlet webAdapterServlet; + private int transformerCount = 0; + private int transformersInUse = 0; + + /** Constructor for transformer factory. + * Method UIDLTransformerFactory. + * @param themeSource Theme source to be used for themes. + * @param webAdapterServlet The Adapter servlet. + * @param maxConcurrentTransformers Maximum number of concurrent themes in use. + * @param cacheTime Time to cache the transformers. + */ + public UIDLTransformerFactory( + ThemeSource themeSource, + WebAdapterServlet webAdapterServlet, + int maxConcurrentTransformers, + long cacheTime) { + this.webAdapterServlet = webAdapterServlet; + if (themeSource == null) + throw new NullPointerException(); + this.themeSource = themeSource; + this.themeSourceModificationTime = themeSource.getModificationTime(); + this.maxConcurrentTransformers = maxConcurrentTransformers; + if (cacheTime >= 0) + this.cacheTime = cacheTime; + this.spoolManager = new SpoolManager(this.cacheTime); + this.spoolManager.setDaemon(true); + //Enable manager only if time > 0 + if (this.cacheTime > 0) + this.spoolManager.start(); + } + + /** Get new transformer of the specified type + * @param type Type of the requested transformer. + * @param variableMap WebVariable map used by the transformer + * @return Created new transformer. + */ + public synchronized UIDLTransformer getTransformer(UIDLTransformerType type) + throws UIDLTransformerException { + + while (transformersInUse >= maxConcurrentTransformers) { + try { + this.wait(); + } catch (InterruptedException e) { + return null; + } + } + + // Get list of transformers for this type + TransformerList list = + (TransformerList) this.transformerSpool.get(type); + + // Check the modification time between fixed intervals + long now = System.currentTimeMillis(); + if (now - CACHE_CHECK_INTERVAL_MILLIS + > this.lastModificationCheckTime) { + + this.lastModificationCheckTime = now; + + // Check if the theme source has been modified and flush + // list if necessary + long lastmod = this.themeSource.getModificationTime(); + if (list != null && this.themeSourceModificationTime < lastmod) { + if (webAdapterServlet.isDebugMode()) { + Log.info( + "Theme source modified since " + + new Date(this.themeSourceModificationTime) + .toString() + + ". Reloading..."); + } + // Force refresh by removing from spool + this.transformerSpool.clear(); + list = null; + this.transformerCount = 0; + this.themeSourceModificationTime = lastmod; + } + } + + UIDLTransformer t = null; + + if (list != null && !list.isEmpty()) { + // If available, return the first available transformer + t = (UIDLTransformer) list.removeFirst(); + if (webAdapterServlet.isDebugMode()) { + Log.info("Reserved existing transformer: " + type); + } + } else { + + // Create new transformer and return it. Transformers are added to + // spool when they are released. + t = new UIDLTransformer(type, themeSource, webAdapterServlet); + transformerCount++; + if (webAdapterServlet.isDebugMode()) { + Log.info( + "Created new transformer (" + + transformerCount + + "):" + + type); + } + + // Create new list, if not found + if (list == null) { + list = new TransformerList(type); + this.transformerSpool.put(type, list); + if (webAdapterServlet.isDebugMode()) { + Log.info("Created new type: " + type); + } + } + + } + transformersInUse++; + return t; + } + + /** Recycle a used transformer back to spool. + * One must guarantee not to use the transformer after it have been released. + * @param transformer UIDLTransformer to be recycled + */ + public synchronized void releaseTransformer(UIDLTransformer transformer) { + + try { + // Reset the transformer before returning it to spool + transformer.reset(); + + // Recycle the transformer back to spool + TransformerList list = + (TransformerList) this.transformerSpool.get( + transformer.getTransformerType()); + if (list != null) { + list.add(transformer); + if (webAdapterServlet.isDebugMode()) { + Log.info( + "Released transformer: " + + transformer.getTransformerType() + + "(In use: " + + transformersInUse + + ",Spooled: " + + list.size() + + ")"); + } + list.lastUsed = System.currentTimeMillis(); + } else { + Log.info( + "Tried to release non-existing transformer. Ignoring." + + " (Type:" + + transformer.getTransformerType() + + ")"); + } + } finally { + if (transformersInUse > 0) + transformersInUse--; + notifyAll(); + } + } + + private class TransformerList { + + private UIDLTransformerType type = null; + private LinkedList list = new LinkedList(); + private long lastUsed = 0; + + public TransformerList(UIDLTransformerType type) { + this.type = type; + } + + public void add(UIDLTransformer transformer) { + list.add(transformer); + } + + public UIDLTransformer removeFirst() { + return (UIDLTransformer) ((LinkedList) list).removeFirst(); + } + + public boolean isEmpty() { + return list.isEmpty(); + } + + public int size() { + return list.size(); + } + } + + private synchronized void removeUnusedTransformers() { + long currentTime = System.currentTimeMillis(); + HashSet keys = new HashSet(); + keys.addAll(this.transformerSpool.keySet()); + for (Iterator i = keys.iterator(); i.hasNext();) { + UIDLTransformerType type = (UIDLTransformerType) i.next(); + TransformerList l = + (TransformerList) this.transformerSpool.get(type); + if (l != null) { + if (l.lastUsed > 0 + && l.lastUsed < (currentTime - this.cacheTime)) { + if (webAdapterServlet.isDebugMode()) { + Log.info( + "Removed transformer: " + + type + + " Not used since " + + new Date(l.lastUsed)); + } + this.transformerSpool.remove(type); + } + } + } + } + + /** Class for periodically remove unused transformers from memory. + * @author IT Mill Ltd. + * @version @VERSION@ + * @since 3.0 + */ + protected class SpoolManager extends Thread { + + long refreshTime; + + public SpoolManager(long refreshTime) { + super("UIDLTransformerFactory.SpoolManager"); + this.refreshTime = refreshTime; + } + + public void run() { + while (true) { + try { + sleep(refreshTime); + } catch (Exception e) { + } + removeUnusedTransformers(); + } + } + } + +} |