1 | |
package org.apache.ojb.broker.cache; |
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
import java.util.ArrayList; |
19 | |
import java.util.HashMap; |
20 | |
import java.util.Iterator; |
21 | |
import java.util.List; |
22 | |
import java.util.Map; |
23 | |
import java.util.Properties; |
24 | |
import java.util.StringTokenizer; |
25 | |
|
26 | |
import org.apache.commons.lang.SystemUtils; |
27 | |
import org.apache.commons.lang.builder.ToStringBuilder; |
28 | |
import org.apache.commons.lang.builder.ToStringStyle; |
29 | |
import org.apache.ojb.broker.Identity; |
30 | |
import org.apache.ojb.broker.OJBRuntimeException; |
31 | |
import org.apache.ojb.broker.PersistenceBroker; |
32 | |
import org.apache.ojb.broker.metadata.ObjectCacheDescriptor; |
33 | |
import org.apache.ojb.broker.util.ClassHelper; |
34 | |
import org.apache.ojb.broker.util.configuration.impl.OjbConfigurator; |
35 | |
import org.apache.ojb.broker.util.logging.Logger; |
36 | |
import org.apache.ojb.broker.util.logging.LoggerFactory; |
37 | |
|
38 | |
|
39 | |
|
40 | |
|
41 | |
|
42 | |
|
43 | |
|
44 | |
|
45 | |
|
46 | |
|
47 | |
|
48 | |
|
49 | |
|
50 | |
|
51 | |
|
52 | |
|
53 | |
|
54 | |
|
55 | |
|
56 | |
|
57 | |
class CacheDistributor implements ObjectCacheInternal |
58 | |
{ |
59 | |
private static Logger log = LoggerFactory.getLogger(CacheDistributor.class); |
60 | |
private static final String DESCRIPTOR_BASED_CACHES = "descriptorBasedCaches"; |
61 | |
public static final String CACHE_EXCLUDES_STRING = "cacheExcludes"; |
62 | |
private static final String DELIMITER_FOR_EXCLUDE = ","; |
63 | |
private static final ObjectCacheInternal DUMMY_CACHE = |
64 | |
new ObjectCacheInternalWrapper(new ObjectCacheEmptyImpl(null, null)); |
65 | |
|
66 | |
|
67 | |
|
68 | |
|
69 | |
private Map caches = new HashMap(); |
70 | |
private List excludedPackages; |
71 | |
|
72 | |
private final PersistenceBroker broker; |
73 | |
|
74 | |
|
75 | |
|
76 | |
|
77 | |
|
78 | |
|
79 | |
private boolean descriptorBasedCaches; |
80 | |
|
81 | |
|
82 | |
|
83 | |
|
84 | |
public CacheDistributor(final PersistenceBroker broker) |
85 | |
{ |
86 | |
this.broker = broker; |
87 | |
this.descriptorBasedCaches = OjbConfigurator.getInstance().getConfigurationFor(null) |
88 | |
.getBoolean(DESCRIPTOR_BASED_CACHES, false); |
89 | |
String exclude = broker.serviceConnectionManager().getConnectionDescriptor().getAttribute(CACHE_EXCLUDES_STRING); |
90 | |
if(exclude != null) |
91 | |
{ |
92 | |
exclude = exclude.trim(); |
93 | |
if(exclude.length() > 0) |
94 | |
{ |
95 | |
excludedPackages = createExcludedPackagesList(exclude); |
96 | |
log.info("Packages to exclude from caching: " + excludedPackages); |
97 | |
} |
98 | |
} |
99 | |
} |
100 | |
|
101 | |
public void cache(Identity oid, Object obj) |
102 | |
{ |
103 | |
getCache(oid.getObjectsTopLevelClass()).cache(oid, obj); |
104 | |
} |
105 | |
|
106 | |
|
107 | |
|
108 | |
|
109 | |
public boolean cacheIfNew(Identity oid, Object obj) |
110 | |
{ |
111 | |
return getCache(oid.getObjectsTopLevelClass()).cacheIfNew(oid, obj); |
112 | |
} |
113 | |
|
114 | |
public Object lookup(Identity oid) |
115 | |
{ |
116 | |
return getCache(oid.getObjectsTopLevelClass()).lookup(oid); |
117 | |
} |
118 | |
|
119 | |
public void remove(Identity oid) |
120 | |
{ |
121 | |
getCache(oid.getObjectsTopLevelClass()).remove(oid); |
122 | |
} |
123 | |
|
124 | |
public void clear() |
125 | |
{ |
126 | |
synchronized(caches) |
127 | |
{ |
128 | |
Iterator it = caches.values().iterator(); |
129 | |
ObjectCache oc = null; |
130 | |
while(it.hasNext()) |
131 | |
{ |
132 | |
oc = (ObjectCache) it.next(); |
133 | |
try |
134 | |
{ |
135 | |
oc.clear(); |
136 | |
} |
137 | |
catch(Exception e) |
138 | |
{ |
139 | |
log.error("Error while call method 'clear()' on '" + oc + "'", e); |
140 | |
} |
141 | |
} |
142 | |
} |
143 | |
} |
144 | |
|
145 | |
public void doInternalCache(Identity oid, Object obj, int type) |
146 | |
{ |
147 | |
getCache(oid.getObjectsTopLevelClass()).doInternalCache(oid, obj, type); |
148 | |
} |
149 | |
|
150 | |
public ObjectCacheInternal getCache(Class targetClass) |
151 | |
{ |
152 | |
|
153 | |
|
154 | |
|
155 | |
|
156 | |
|
157 | |
boolean useConnectionLevelCache = false; |
158 | |
ObjectCacheInternal retval = null; |
159 | |
|
160 | |
|
161 | |
|
162 | |
|
163 | |
ObjectCacheDescriptor ocd = searchInClassDescriptor(targetClass); |
164 | |
if(ocd == null) |
165 | |
{ |
166 | |
ocd = searchInJdbcConnectionDescriptor(); |
167 | |
useConnectionLevelCache = true; |
168 | |
} |
169 | |
if(ocd == null) |
170 | |
{ |
171 | |
throw new OJBRuntimeException("No object cache descriptor found for " + targetClass + ", using PBKey " + broker.getPBKey() |
172 | |
+ ". Please set a cache descriptor in jdbc-connection-descriptor or in class-descriptor"); |
173 | |
} |
174 | |
else |
175 | |
{ |
176 | |
|
177 | |
if(!useConnectionLevelCache) |
178 | |
{ |
179 | |
if(!descriptorBasedCaches) |
180 | |
{ |
181 | |
synchronized(caches) |
182 | |
{ |
183 | |
retval = lookupCache(targetClass); |
184 | |
|
185 | |
if(retval == null) |
186 | |
{ |
187 | |
if(log.isEnabledFor(Logger.INFO)) |
188 | |
{ |
189 | |
String eol = SystemUtils.LINE_SEPARATOR; |
190 | |
log.info(eol + "<====" + eol + "Setup new object cache instance on CLASS LEVEL for" + eol |
191 | |
+ "PersistenceBroker: " + broker + eol |
192 | |
+ "descriptorBasedCache: " + descriptorBasedCaches + eol |
193 | |
+ "Class: " + targetClass + eol |
194 | |
+ "ObjectCache: " + ocd + eol + "====>"); |
195 | |
} |
196 | |
retval = prepareAndAddCache(targetClass, ocd); |
197 | |
} |
198 | |
} |
199 | |
} |
200 | |
else |
201 | |
{ |
202 | |
synchronized(caches) |
203 | |
{ |
204 | |
retval = lookupCache(ocd); |
205 | |
|
206 | |
if(retval == null) |
207 | |
{ |
208 | |
if(log.isEnabledFor(Logger.INFO)) |
209 | |
{ |
210 | |
String eol = SystemUtils.LINE_SEPARATOR; |
211 | |
log.info(eol + "<====" + eol + "Setup new object cache instance on CLASS LEVEL for" + eol |
212 | |
+ "PersistenceBroker: " + broker + eol |
213 | |
+ "descriptorBasedCache: " + descriptorBasedCaches + eol |
214 | |
+ "class: " + targetClass + eol |
215 | |
+ "ObjectCache: " + ocd + eol + "====>"); |
216 | |
} |
217 | |
retval = prepareAndAddCache(ocd, ocd); |
218 | |
} |
219 | |
} |
220 | |
} |
221 | |
} |
222 | |
|
223 | |
else |
224 | |
{ |
225 | |
if(isExcluded(targetClass)) |
226 | |
{ |
227 | |
if(log.isDebugEnabled()) log.debug("Class '" + targetClass.getName() + "' is excluded from being cached"); |
228 | |
retval = DUMMY_CACHE; |
229 | |
} |
230 | |
else |
231 | |
{ |
232 | |
String jcdAlias = broker.serviceConnectionManager().getConnectionDescriptor().getJcdAlias(); |
233 | |
synchronized(caches) |
234 | |
{ |
235 | |
retval = lookupCache(jcdAlias); |
236 | |
|
237 | |
if(retval == null) |
238 | |
{ |
239 | |
if(log.isEnabledFor(Logger.INFO)) |
240 | |
{ |
241 | |
String eol = SystemUtils.LINE_SEPARATOR; |
242 | |
log.info(eol + "<====" + eol + "Setup new object cache instance on CONNECTION LEVEL for" + eol |
243 | |
+ "PersistenceBroker: " + broker + eol |
244 | |
+ "descriptorBasedCache: " + descriptorBasedCaches + eol |
245 | |
+ "Connection jcdAlias: " + jcdAlias + eol |
246 | |
+ "Calling class: " + targetClass |
247 | |
+ "ObjectCache: " + ocd + eol + "====>"); |
248 | |
} |
249 | |
retval = prepareAndAddCache(jcdAlias, ocd); |
250 | |
} |
251 | |
} |
252 | |
} |
253 | |
} |
254 | |
} |
255 | |
return retval; |
256 | |
} |
257 | |
|
258 | |
private ObjectCacheInternal prepareAndAddCache(Object key, ObjectCacheDescriptor ocd) |
259 | |
{ |
260 | |
ObjectCacheInternal cache; |
261 | |
|
262 | |
|
263 | |
if((cache = lookupCache(key)) != null) |
264 | |
{ |
265 | |
log.info("Key '" + key + "' was already in use no need to create the ObjectCache instance again"); |
266 | |
} |
267 | |
else |
268 | |
{ |
269 | |
if(log.isDebugEnabled()) log.debug("Create new ObjectCache implementation for " + key); |
270 | |
try |
271 | |
{ |
272 | |
ObjectCache temp = (ObjectCache) ClassHelper.newInstance(ocd.getObjectCache(), |
273 | |
new Class[]{PersistenceBroker.class, Properties.class}, |
274 | |
new Object[]{broker, ocd.getConfigurationProperties()}); |
275 | |
if(temp instanceof ObjectCacheInternal) |
276 | |
{ |
277 | |
cache = (ObjectCacheInternal) temp; |
278 | |
} |
279 | |
else |
280 | |
{ |
281 | |
log.info("Specified cache " + ocd.getObjectCache() + " does not implement " |
282 | |
+ ObjectCacheInternal.class + " and will be wrapped by a helper class"); |
283 | |
cache = new ObjectCacheInternalWrapper(temp); |
284 | |
} |
285 | |
} |
286 | |
catch(Exception e) |
287 | |
{ |
288 | |
log.error("Can not create ObjectCache instance using class " + ocd.getObjectCache(), e); |
289 | |
throw new OJBRuntimeException(e); |
290 | |
} |
291 | |
caches.put(key, cache); |
292 | |
} |
293 | |
return cache; |
294 | |
} |
295 | |
|
296 | |
private ObjectCacheInternal lookupCache(Object key) |
297 | |
{ |
298 | |
return (ObjectCacheInternal) caches.get(key); |
299 | |
} |
300 | |
|
301 | |
private List createExcludedPackagesList(String theList) |
302 | |
{ |
303 | |
StringTokenizer tok = new StringTokenizer(theList, DELIMITER_FOR_EXCLUDE); |
304 | |
String token = null; |
305 | |
ArrayList result = new ArrayList(); |
306 | |
while(tok.hasMoreTokens()) |
307 | |
{ |
308 | |
token = tok.nextToken().trim(); |
309 | |
if(token.length() > 0) result.add(token); |
310 | |
} |
311 | |
return result; |
312 | |
} |
313 | |
|
314 | |
private boolean isExcluded(Class targetClass) |
315 | |
{ |
316 | |
if(excludedPackages != null) |
317 | |
{ |
318 | |
String name = targetClass.getName(); |
319 | |
for(int i = 0; i < excludedPackages.size(); i++) |
320 | |
{ |
321 | |
String exclude = (String) excludedPackages.get(i); |
322 | |
if(name.startsWith(exclude)) |
323 | |
{ |
324 | |
return true; |
325 | |
} |
326 | |
} |
327 | |
} |
328 | |
return false; |
329 | |
} |
330 | |
|
331 | |
|
332 | |
|
333 | |
|
334 | |
|
335 | |
|
336 | |
|
337 | |
|
338 | |
|
339 | |
protected ObjectCacheDescriptor searchInClassDescriptor(Class targetClass) |
340 | |
{ |
341 | |
return targetClass != null ? broker.getClassDescriptor(targetClass).getObjectCacheDescriptor() : null; |
342 | |
} |
343 | |
|
344 | |
|
345 | |
|
346 | |
|
347 | |
|
348 | |
|
349 | |
|
350 | |
|
351 | |
protected ObjectCacheDescriptor searchInJdbcConnectionDescriptor() |
352 | |
{ |
353 | |
return broker.serviceConnectionManager().getConnectionDescriptor().getObjectCacheDescriptor(); |
354 | |
} |
355 | |
|
356 | |
public String toString() |
357 | |
{ |
358 | |
ToStringBuilder buf = new ToStringBuilder(this, ToStringStyle.DEFAULT_STYLE); |
359 | |
return buf.append("Associated PB", broker) |
360 | |
.append("Mapped caches", caches).toString(); |
361 | |
} |
362 | |
|
363 | |
|
364 | |
|
365 | |
|
366 | |
|
367 | |
|
368 | |
|
369 | |
|
370 | |
static final class ObjectCacheInternalWrapper implements ObjectCacheInternal |
371 | |
{ |
372 | |
ObjectCache cache = null; |
373 | |
|
374 | |
public ObjectCacheInternalWrapper(ObjectCache cache) |
375 | |
{ |
376 | |
this.cache = cache; |
377 | |
} |
378 | |
|
379 | |
public void doInternalCache(Identity oid, Object obj, int type) |
380 | |
{ |
381 | |
cache(oid, obj); |
382 | |
} |
383 | |
|
384 | |
public void doInternalClear() |
385 | |
{ |
386 | |
|
387 | |
} |
388 | |
|
389 | |
public boolean contains(Identity oid) |
390 | |
{ |
391 | |
return cache.lookup(oid) != null; |
392 | |
} |
393 | |
|
394 | |
public void cache(Identity oid, Object obj) |
395 | |
{ |
396 | |
cache.cache(oid, obj); |
397 | |
} |
398 | |
|
399 | |
public boolean cacheIfNew(Identity oid, Object obj) |
400 | |
{ |
401 | |
cache.cache(oid, obj); |
402 | |
return true; |
403 | |
} |
404 | |
|
405 | |
public Object lookup(Identity oid) |
406 | |
{ |
407 | |
return cache.lookup(oid); |
408 | |
} |
409 | |
|
410 | |
public void remove(Identity oid) |
411 | |
{ |
412 | |
cache.remove(oid); |
413 | |
} |
414 | |
|
415 | |
public void clear() |
416 | |
{ |
417 | |
cache.clear(); |
418 | |
} |
419 | |
} |
420 | |
|
421 | |
} |