001 /* 002 @license.text@ 003 */ 004 package biz.hammurapi.persistence; 005 006 import java.util.Timer; 007 008 import javax.sql.DataSource; 009 010 import biz.hammurapi.cache.AppendableMemoryCache; 011 import biz.hammurapi.cache.Entry; 012 import biz.hammurapi.cache.MemoryCache; 013 import biz.hammurapi.config.ComponentBase; 014 import biz.hammurapi.config.ConfigurationException; 015 import biz.hammurapi.config.Context; 016 import biz.hammurapi.metrics.MeasurementCategory; 017 import biz.hammurapi.metrics.MeasurementCategoryFactory; 018 import biz.hammurapi.sql.IdentityManager; 019 import biz.hammurapi.sql.SQLProcessor; 020 021 022 /** 023 * This class manages storage and retrieval of strings to and from relational database. 024 * Strings can be of arbitrary size, long strings are cut into chunks. Strings are keyed by integers. 025 * Often used strings are cached in memory using soft references. 026 * @author Pavel Vlasov 027 * @revision $Revision$ 028 */ 029 public class ChunkingStringStorage extends ComponentBase implements StringStorage { 030 private static final MeasurementCategory mc=MeasurementCategoryFactory.getCategory(ChunkingStringStorage.class); 031 032 private Timer timer; 033 034 /** 035 * Timer for cleaning up memory entries, can be null. 036 * @param timer 037 */ 038 public void setTimer(Timer timer) { 039 this.timer = timer; 040 } 041 042 private DataSource datasource; 043 044 /** 045 * Data source 046 * @param datasource 047 */ 048 public void setDatasource(DataSource datasource) { 049 this.datasource = datasource; 050 } 051 052 private AppendableMemoryCache sharedTextCache; 053 054 /* (non-Javadoc) 055 * @see biz.hammurapi.persistence.StringStorage#getText(java.lang.Integer) 056 */ 057 public String getText(Integer key) { 058 Entry entry = sharedTextCache.get(key); 059 return (String) (entry==null ? null : entry.get()); 060 } 061 062 /* (non-Javadoc) 063 * @see biz.hammurapi.persistence.StringStorage#addText(java.lang.String) 064 */ 065 public Integer addText(String text) { 066 return (Integer) (text==null ? null : sharedTextCache.add(text, 0, 0)); 067 } 068 069 private boolean isOwnTimer; 070 071 /** 072 * Stops memory cache and times. 073 */ 074 public void stop() { 075 sharedTextCache.stop(); 076 if (isOwnTimer) { 077 timer.cancel(); 078 } 079 } 080 081 private Context nameMap; 082 083 private IdentityManager identityManager; 084 085 private int chunkSize; 086 087 /** 088 * Set nameMap if database object names are different from default. 089 * @param nameMap 090 */ 091 void setNameMap(Context nameMap) { 092 this.nameMap = nameMap; 093 } 094 095 /** 096 * Identity manager is used to generate/retrieve identity of newely inserted entries. 097 * @param identityManager 098 */ 099 public void setIdentityManager(IdentityManager identityManager) { 100 this.identityManager = identityManager; 101 } 102 103 /** 104 * Size of individual text chunk. 105 * @param chunkSize 106 */ 107 public void setChunkSize(int chunkSize) { 108 this.chunkSize = chunkSize; 109 } 110 111 /** 112 * Starts timer and cache. 113 */ 114 public void start() throws ConfigurationException { 115 if (timer==null) { 116 timer=new Timer(); 117 isOwnTimer=true; 118 } 119 120 SQLProcessor sqlProcessor = new SQLProcessor(datasource, nameMap); 121 SharedTextAppendableProducer stap = new SharedTextAppendableProducer( 122 sqlProcessor, 123 identityManager, 124 chunkSize); 125 126 sharedTextCache=new AppendableMemoryCache( 127 stap, 128 null, 129 mc, 130 timer, 131 MemoryCache.CLEANUP_INTERVAL); 132 } 133 134 /** 135 * Alternative way to access text entries. 136 */ 137 protected Object getChild(String name) { 138 return getText(new Integer(name)); 139 } 140 141 142 }