You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UIDLTransformerFactory.java 8.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. /* *************************************************************************
  2. IT Mill Toolkit
  3. Development of Browser User Intarfaces Made Easy
  4. Copyright (C) 2000-2006 IT Mill Ltd
  5. *************************************************************************
  6. This product is distributed under commercial license that can be found
  7. from the product package on license/license.txt. Use of this product might
  8. require purchasing a commercial license from IT Mill Ltd. For guidelines
  9. on usage, see license/licensing-guidelines.html
  10. *************************************************************************
  11. For more information, contact:
  12. IT Mill Ltd phone: +358 2 4802 7180
  13. Ruukinkatu 2-4 fax: +358 2 4802 7181
  14. 20540, Turku email: info@itmill.com
  15. Finland company www: www.itmill.com
  16. Primary source for information and releases: www.itmill.com
  17. ********************************************************************** */
  18. package com.itmill.toolkit.terminal.web;
  19. import java.util.Date;
  20. import java.util.HashMap;
  21. import java.util.HashSet;
  22. import java.util.LinkedList;
  23. import java.util.Map;
  24. import java.util.Iterator;
  25. /** Class implementing the UIDLTransformer Factory.
  26. * The factory creates and maintains a pool of transformers that are used
  27. * for transforming UIDL to HTML.
  28. *
  29. * @author IT Mill Ltd.
  30. * @version @VERSION@
  31. * @since 3.0
  32. */
  33. public class UIDLTransformerFactory {
  34. /** Time between repository modified queries. */
  35. private static final int CACHE_CHECK_INTERVAL_MILLIS = 5 * 1000;
  36. /** The time transformers are cached by default*/
  37. private static final long DEFAULT_TRANSFORMER_CACHETIME = 60 * 60 * 1000;
  38. /** Maximum number of transformers in use */
  39. private int maxConcurrentTransformers = 1;
  40. /** Last time theme modification time was checked */
  41. private long lastModificationCheckTime = 0;
  42. /** Last time theme source was modified */
  43. private long themeSourceModificationTime = 0;
  44. /** How long to cache transformers. */
  45. private long cacheTime = DEFAULT_TRANSFORMER_CACHETIME;
  46. /** Spool manager thread */
  47. private SpoolManager spoolManager;
  48. private Map transformerSpool = new HashMap();
  49. private ThemeSource themeSource;
  50. private ApplicationServlet webAdapterServlet;
  51. private int transformerCount = 0;
  52. private int transformersInUse = 0;
  53. /** Constructor for transformer factory.
  54. * Method UIDLTransformerFactory.
  55. * @param themeSource Theme source to be used for themes.
  56. * @param webAdapterServlet The Adapter servlet.
  57. * @param maxConcurrentTransformers Maximum number of concurrent themes in use.
  58. * @param cacheTime Time to cache the transformers.
  59. */
  60. public UIDLTransformerFactory(
  61. ThemeSource themeSource,
  62. ApplicationServlet webAdapterServlet,
  63. int maxConcurrentTransformers,
  64. long cacheTime) {
  65. this.webAdapterServlet = webAdapterServlet;
  66. if (themeSource == null)
  67. throw new NullPointerException();
  68. this.themeSource = themeSource;
  69. this.themeSourceModificationTime = themeSource.getModificationTime();
  70. this.maxConcurrentTransformers = maxConcurrentTransformers;
  71. if (cacheTime >= 0)
  72. this.cacheTime = cacheTime;
  73. this.spoolManager = new SpoolManager(this.cacheTime);
  74. this.spoolManager.setDaemon(true);
  75. //Enable manager only if time > 0
  76. if (this.cacheTime > 0)
  77. this.spoolManager.start();
  78. }
  79. /** Get new transformer of the specified type
  80. * @param type Type of the requested transformer.
  81. * @param variableMap WebVariable map used by the transformer
  82. * @return Created new transformer.
  83. */
  84. public synchronized UIDLTransformer getTransformer(UIDLTransformerType type)
  85. throws UIDLTransformerException {
  86. while (transformersInUse >= maxConcurrentTransformers) {
  87. try {
  88. this.wait();
  89. } catch (InterruptedException e) {
  90. return null;
  91. }
  92. }
  93. // Get list of transformers for this type
  94. TransformerList list =
  95. (TransformerList) this.transformerSpool.get(type);
  96. // Check the modification time between fixed intervals
  97. long now = System.currentTimeMillis();
  98. if (now - CACHE_CHECK_INTERVAL_MILLIS
  99. > this.lastModificationCheckTime) {
  100. this.lastModificationCheckTime = now;
  101. // Check if the theme source has been modified and flush
  102. // list if necessary
  103. long lastmod = this.themeSource.getModificationTime();
  104. if (list != null && this.themeSourceModificationTime < lastmod) {
  105. if (webAdapterServlet.isDebugMode(null)) {
  106. Log.info(
  107. "Theme source modified since "
  108. + new Date(this.themeSourceModificationTime)
  109. .toString()
  110. + ". Reloading...");
  111. }
  112. // Force refresh by removing from spool
  113. this.transformerSpool.clear();
  114. list = null;
  115. this.transformerCount = 0;
  116. this.themeSourceModificationTime = lastmod;
  117. }
  118. }
  119. UIDLTransformer t = null;
  120. if (list != null && !list.isEmpty()) {
  121. // If available, return the first available transformer
  122. t = (UIDLTransformer) list.removeFirst();
  123. if (webAdapterServlet.isDebugMode(null)) {
  124. Log.info("Reserved existing transformer: " + type);
  125. }
  126. } else {
  127. // Create new transformer and return it. Transformers are added to
  128. // spool when they are released.
  129. t = new UIDLTransformer(type, themeSource, webAdapterServlet);
  130. transformerCount++;
  131. if (webAdapterServlet.isDebugMode(null)) {
  132. Log.info(
  133. "Created new transformer ("
  134. + transformerCount
  135. + "):"
  136. + type);
  137. }
  138. // Create new list, if not found
  139. if (list == null) {
  140. list = new TransformerList();
  141. this.transformerSpool.put(type, list);
  142. if (webAdapterServlet.isDebugMode(null)) {
  143. Log.info("Created new type: " + type);
  144. }
  145. }
  146. }
  147. transformersInUse++;
  148. return t;
  149. }
  150. /** Recycle a used transformer back to spool.
  151. * One must guarantee not to use the transformer after it have been released.
  152. * @param transformer UIDLTransformer to be recycled
  153. */
  154. public synchronized void releaseTransformer(UIDLTransformer transformer) {
  155. try {
  156. // Reset the transformer before returning it to spool
  157. transformer.reset();
  158. // Recycle the transformer back to spool
  159. TransformerList list =
  160. (TransformerList) this.transformerSpool.get(
  161. transformer.getTransformerType());
  162. if (list != null) {
  163. list.add(transformer);
  164. if (webAdapterServlet.isDebugMode(null)) {
  165. Log.info(
  166. "Released transformer: "
  167. + transformer.getTransformerType()
  168. + "(In use: "
  169. + transformersInUse
  170. + ",Spooled: "
  171. + list.size()
  172. + ")");
  173. }
  174. list.lastUsed = System.currentTimeMillis();
  175. } else {
  176. Log.info(
  177. "Tried to release non-existing transformer. Ignoring."
  178. + " (Type:"
  179. + transformer.getTransformerType()
  180. + ")");
  181. }
  182. } finally {
  183. if (transformersInUse > 0)
  184. transformersInUse--;
  185. notifyAll();
  186. }
  187. }
  188. private class TransformerList {
  189. private LinkedList list = new LinkedList();
  190. private long lastUsed = 0;
  191. public void add(UIDLTransformer transformer) {
  192. list.add(transformer);
  193. }
  194. public UIDLTransformer removeFirst() {
  195. return (UIDLTransformer) ((LinkedList) list).removeFirst();
  196. }
  197. public boolean isEmpty() {
  198. return list.isEmpty();
  199. }
  200. public int size() {
  201. return list.size();
  202. }
  203. }
  204. private synchronized void removeUnusedTransformers() {
  205. long currentTime = System.currentTimeMillis();
  206. HashSet keys = new HashSet();
  207. keys.addAll(this.transformerSpool.keySet());
  208. for (Iterator i = keys.iterator(); i.hasNext();) {
  209. UIDLTransformerType type = (UIDLTransformerType) i.next();
  210. TransformerList l =
  211. (TransformerList) this.transformerSpool.get(type);
  212. if (l != null) {
  213. if (l.lastUsed > 0
  214. && l.lastUsed < (currentTime - this.cacheTime)) {
  215. if (webAdapterServlet.isDebugMode(null)) {
  216. Log.info(
  217. "Removed transformer: "
  218. + type
  219. + " Not used since "
  220. + new Date(l.lastUsed));
  221. }
  222. this.transformerSpool.remove(type);
  223. }
  224. }
  225. }
  226. }
  227. /** Class for periodically remove unused transformers from memory.
  228. * @author IT Mill Ltd.
  229. * @version @VERSION@
  230. * @since 3.0
  231. */
  232. protected class SpoolManager extends Thread {
  233. long refreshTime;
  234. public SpoolManager(long refreshTime) {
  235. super("UIDLTransformerFactory.SpoolManager");
  236. this.refreshTime = refreshTime;
  237. }
  238. public void run() {
  239. while (true) {
  240. try {
  241. sleep(refreshTime);
  242. } catch (Exception e) {
  243. }
  244. removeUnusedTransformers();
  245. }
  246. }
  247. }
  248. }