1 package org.apache.commons.jcs.auxiliary.disk.jdbc;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.sql.SQLException;
23 import java.util.Properties;
24 import java.util.concurrent.ConcurrentHashMap;
25 import java.util.concurrent.ConcurrentMap;
26 import java.util.concurrent.ScheduledExecutorService;
27 import java.util.concurrent.TimeUnit;
28 import java.util.concurrent.locks.ReentrantLock;
29
30 import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory;
31 import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
32 import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory;
33 import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.JndiDataSourceFactory;
34 import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.SharedPoolDataSourceFactory;
35 import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
36 import org.apache.commons.jcs.engine.behavior.IElementSerializer;
37 import org.apache.commons.jcs.engine.behavior.IRequireScheduler;
38 import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
39 import org.apache.commons.jcs.utils.config.PropertySetter;
40 import org.apache.commons.logging.Log;
41 import org.apache.commons.logging.LogFactory;
42
43
44
45
46
47
48 public class JDBCDiskCacheFactory
49 extends AbstractAuxiliaryCacheFactory
50 implements IRequireScheduler
51 {
52
53 private static final Log log = LogFactory.getLog( JDBCDiskCacheFactory.class );
54
55
56
57
58
59 private ConcurrentMap<String, TableState> tableStates;
60
61
62 protected ScheduledExecutorService scheduler;
63
64
65
66
67
68 private ConcurrentMap<String, ShrinkerThread> shrinkerThreadMap;
69
70
71 private ConcurrentMap<String, DataSourceFactory> dsFactories;
72
73
74 private ReentrantLock dsFactoryLock;
75
76
77 protected static final String POOL_CONFIGURATION_PREFIX = "jcs.jdbcconnectionpool.";
78
79
80 protected static final String ATTRIBUTE_PREFIX = ".attributes";
81
82
83
84
85
86
87
88
89
90
91
92 @Override
93 public <K, V> JDBCDiskCache<K, V> createCache( AuxiliaryCacheAttributes rawAttr,
94 ICompositeCacheManager compositeCacheManager,
95 ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
96 throws SQLException
97 {
98 JDBCDiskCacheAttributes cattr = (JDBCDiskCacheAttributes) rawAttr;
99 TableState tableState = getTableState( cattr.getTableName() );
100 DataSourceFactory dsFactory = getDataSourceFactory(cattr, compositeCacheManager.getConfigurationProperties());
101
102 JDBCDiskCache<K, V> cache = new JDBCDiskCache<K, V>( cattr, dsFactory, tableState, compositeCacheManager );
103 cache.setCacheEventLogger( cacheEventLogger );
104 cache.setElementSerializer( elementSerializer );
105
106
107 createShrinkerWhenNeeded( cattr, cache );
108
109 return cache;
110 }
111
112
113
114
115 @Override
116 public void initialize()
117 {
118 super.initialize();
119 this.tableStates = new ConcurrentHashMap<String, TableState>();
120 this.shrinkerThreadMap = new ConcurrentHashMap<String, ShrinkerThread>();
121 this.dsFactories = new ConcurrentHashMap<String, DataSourceFactory>();
122 this.dsFactoryLock = new ReentrantLock();
123 }
124
125
126
127
128 @Override
129 public void dispose()
130 {
131 this.tableStates.clear();
132
133 for (DataSourceFactory dsFactory : this.dsFactories.values())
134 {
135 try
136 {
137 dsFactory.close();
138 }
139 catch (SQLException e)
140 {
141 log.error("Could not close data source factory " + dsFactory.getName(), e);
142 }
143 }
144
145 this.dsFactories.clear();
146 this.shrinkerThreadMap.clear();
147 super.dispose();
148 }
149
150
151
152
153
154
155
156 protected TableState getTableState(String tableName)
157 {
158 TableState newTableState = new TableState( tableName );
159 TableState tableState = tableStates.putIfAbsent( tableName, newTableState );
160
161 if ( tableState == null )
162 {
163 tableState = newTableState;
164 }
165
166 return tableState;
167 }
168
169
170
171
172 @Override
173 public void setScheduledExecutorService(ScheduledExecutorService scheduledExecutor)
174 {
175 this.scheduler = scheduledExecutor;
176 }
177
178
179
180
181
182
183 protected ScheduledExecutorService getScheduledExecutorService()
184 {
185 return scheduler;
186 }
187
188
189
190
191
192
193
194 protected void createShrinkerWhenNeeded( JDBCDiskCacheAttributes cattr, JDBCDiskCache<?, ?> raf )
195 {
196
197 if ( cattr.isUseDiskShrinker() )
198 {
199 ScheduledExecutorService shrinkerService = getScheduledExecutorService();
200 ShrinkerThread newShrinkerThread = new ShrinkerThread();
201 ShrinkerThread shrinkerThread = shrinkerThreadMap.putIfAbsent( cattr.getTableName(), newShrinkerThread );
202
203 if ( shrinkerThread == null )
204 {
205 shrinkerThread = newShrinkerThread;
206
207 long intervalMillis = Math.max( 999, cattr.getShrinkerIntervalSeconds() * 1000 );
208 if ( log.isInfoEnabled() )
209 {
210 log.info( "Setting the shrinker to run every [" + intervalMillis + "] ms. for table ["
211 + cattr.getTableName() + "]" );
212 }
213 shrinkerService.scheduleAtFixedRate(shrinkerThread, 0, intervalMillis, TimeUnit.MILLISECONDS);
214 }
215
216 shrinkerThread.addDiskCacheToShrinkList( raf );
217 }
218 }
219
220
221
222
223
224
225
226
227
228 protected DataSourceFactory getDataSourceFactory( JDBCDiskCacheAttributes cattr,
229 Properties configProps ) throws SQLException
230 {
231 String poolName = null;
232
233 if (cattr.getConnectionPoolName() == null)
234 {
235 poolName = cattr.getCacheName() + "." + JDBCDiskCacheAttributes.DEFAULT_POOL_NAME;
236 }
237 else
238 {
239 poolName = cattr.getConnectionPoolName();
240 }
241
242
243 DataSourceFactory dsFactory = this.dsFactories.get(poolName);
244
245 if (dsFactory == null)
246 {
247 dsFactoryLock.lock();
248
249 try
250 {
251
252 dsFactory = this.dsFactories.get(poolName);
253
254 if (dsFactory == null)
255 {
256 JDBCDiskCacheAttributes dsConfig = null;
257
258 if (cattr.getConnectionPoolName() == null)
259 {
260 dsConfig = cattr;
261 }
262 else
263 {
264 dsConfig = new JDBCDiskCacheAttributes();
265 String dsConfigAttributePrefix = POOL_CONFIGURATION_PREFIX + poolName + ATTRIBUTE_PREFIX;
266 PropertySetter.setProperties( dsConfig,
267 configProps,
268 dsConfigAttributePrefix + "." );
269
270 dsConfig.setConnectionPoolName(poolName);
271 }
272
273 if ( dsConfig.getJndiPath() != null )
274 {
275 dsFactory = new JndiDataSourceFactory();
276 }
277 else
278 {
279 dsFactory = new SharedPoolDataSourceFactory();
280 }
281
282 dsFactory.initialize(dsConfig);
283 this.dsFactories.put(poolName, dsFactory);
284 }
285 }
286 finally
287 {
288 dsFactoryLock.unlock();
289 }
290 }
291
292 return dsFactory;
293 }
294 }