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    }