Relying on NeedsRefreshException
Stefano Santoro <[email protected]>
| Newsgroups | gmane.comp.java.open-symphony.os-cache |
|---|---|
| Message-ID | <[email protected]> |
Hi,
First thank you for creating such a great package. I was thrilled
when some one told me about OS Cache, and I have been, for the last
couple of months, a big advocate for it in my company.
One thing though has left me puzzled: the requirement to catch and
handle NeedsRefreshException, as described in the
GeneralCacheAdministrator java doc. A cache miss is expected during
normal operations, and has nothing 'exceptional' about it. All the
java best practices indicate that Exception handling is an 'exceptional'
event, and it should not be part of the normal and expected execution
path of a program.
I can envision, though, the use of a intermediary data structure to
achieve the same results:
SampleCache cache = // com.opensymphony.oscache.base.Cache extension
SampleCache.Probe probe = null;
String content = null;
try {
probe = cache.getProbe( cacheKey);
if( ! probe.isFresh()) {
// get the content to be cached
content = getContent();
cache.putInCache( cacheKey, content);
}
else {
content = probe.getContent();
}
probe = null;
}
finally {
if( probe != null) {
cache.cancelUpdate();
}
}
Perhaps I have not read the documentation thoroughly enough, and I most
likely missing the point somewhere. Please let me know if there is a way
to use the GeneralCacheAdmimistrator without having to catch
NeedsRefreshException.
I am enclosing my SampleCache implementation for your consideration:
Ciao
Stefano
SampleCache.java
(text/plain, 3.7 KB)
import com.opensymphony.oscache.base.Cache;
import com.opensymphony.oscache.base.CacheEntry;
import com.opensymphony.oscache.base.EntryRefreshPolicy;
import com.opensymphony.oscache.base.EntryUpdateState;
import com.opensymphony.oscache.base.events.CacheMapAccessEvent;
import com.opensymphony.oscache.base.events.CacheMapAccessEventType;
import com.opensymphony.oscache.base.events.CacheMapAccessEventListener;
import com.opensymphony.oscache.base.events.CacheEntryEvent;
public class SampleCache extends Cache {
private boolean blocking;
public SampleCache(boolean useMemoryCaching, boolean unlimitedDiskCache) {
super(useMemoryCaching, unlimitedDiskCache, false, null, 0);
}
public SampleCache
(boolean useMemoryCaching, boolean unlimitedDiskCache,
boolean blocking, String algoClass, int capacity)
{
super(useMemoryCaching,unlimitedDiskCache,blocking,algoClass,capacity);
this.blocking = blocking;
}
public final static class Probe {
private CacheMapAccessEventType state_;
private Object content_;
public Probe( CacheMapAccessEventType aState, Object aContent) {
state_ = aState;
content_ = aContent;
}
public boolean isFresh() {
return state_ == CacheMapAccessEventType.HIT;
}
public boolean isNew() {
return state_ == CacheMapAccessEventType.MISS;
}
public Object getContent() throws IllegalStateException {
return content_;
}
}
public Object getProbe(String key) {
return getProbe(key, CacheEntry.INDEFINITE_EXPIRY, null);
}
public Probe getProbe
( String key, int refreshPeriod, String cronExpiry)
{
CacheEntry cacheEntry = getCacheEntry(key, null, null);
CacheMapAccessEventType accessEventType = CacheMapAccessEventType.HIT;
boolean reload = false;
if( isStale(cacheEntry, refreshPeriod, cronExpiry)) {
EntryUpdateState updateState = null;
boolean canUpdate = false;
while( updateState == null) {
updateState = getUpdateState(key);
synchronized( updateState) {
if( cacheEntry.isNew() || blocking) {
while( updateState.isUpdating()) {
try {
updateState.wait();
}
catch( InterruptedException iex) {
iex = null;
}
}
if( updateState.isComplete()) {
reload = true;
}
else if( updateState.isCancelled()) {
updateState = null;
}
}
if( updateState != null && updateState.isAwaitingUpdate()) {
updateState.startUpdate();
}
}
}
accessEventType = CacheMapAccessEventType.STALE_HIT;
if( reload) {
CacheEntry reloadEntry = getCacheEntry(key, null, null);
if( reloadEntry != null) {
cacheEntry = reloadEntry;
accessEventType = CacheMapAccessEventType.HIT;
}
}
if( cacheEntry.isNew()) {
accessEventType = CacheMapAccessEventType.MISS;
}
}
dispatchCacheMapAccessEvent(accessEventType, cacheEntry, null);
return new Probe( accessEventType, cacheEntry.getContent());
}
private void dispatchCacheMapAccessEvent
(CacheMapAccessEventType eventType, CacheEntry entry, String origin)
{
CacheMapAccessEvent event =
new CacheMapAccessEvent (eventType, entry, origin);
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == CacheMapAccessEventListener.class) {
((CacheMapAccessEventListener) listeners[i + 1]).accessed(event);
}
}
}
}