/*
* Created on Oct 21, 2004
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* Copyright @2004 the original author or authors.
*/
package org.springmodules.cache.interceptor.flush;
import java.beans.PropertyEditor;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.StringUtils;
import org.springmodules.cache.FatalCacheException;
import org.springmodules.cache.FlushingModel;
import org.springmodules.cache.provider.CacheModelValidator;
import org.springmodules.cache.provider.CacheProviderFacade;
/**
* <p>
* Template for advices that flush a cache when the intercepted method is
* executed.
* </p>
*
* @author Alex Ruiz
*/
public abstract class AbstractFlushingInterceptor implements MethodInterceptor,
InitializingBean {
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
private CacheProviderFacade cacheProviderFacade;
/**
* Map of <code>{@link FlushingModel}</code>s that specify how to flush the
* cache. Each cache model is stored under a unique id (a String).
*/
private Map flushingModels;
/**
* @throws FatalCacheException
* if the cache provider facade is <code>null</code>.
*
* @see InitializingBean#afterPropertiesSet()
* @see #onAfterPropertiesSet()
*/
public final void afterPropertiesSet() throws FatalCacheException {
if (cacheProviderFacade == null) {
throw new FatalCacheException(
"The cache provider facade should not be null");
}
if (flushingModels == null || flushingModels.isEmpty()) {
return;
}
CacheModelValidator validator = cacheProviderFacade
.modelValidator();
if (flushingModels instanceof Properties) {
PropertyEditor editor = cacheProviderFacade.getFlushingModelEditor();
Properties properties = (Properties) flushingModels;
Map newFlushingModels = new HashMap();
String id = null;
try {
for (Iterator i = properties.keySet().iterator(); i.hasNext();) {
id = (String) i.next();
String property = properties.getProperty(id);
editor.setAsText(property);
Object flushingModel = editor.getValue();
validator.validateFlushingModel(flushingModel);
newFlushingModels.put(id, flushingModel);
}
} catch (Exception exception) {
throw new FatalCacheException(
"Unable to create the flushing model with id "
+ StringUtils.quote(id), exception);
}
setFlushingModels(newFlushingModels);
} else {
String id = null;
try {
for (Iterator i = flushingModels.keySet().iterator(); i.hasNext();) {
id = (String) i.next();
Object flushingModel = flushingModels.get(id);
validator.validateFlushingModel(flushingModel);
}
} catch (Exception exception) {
throw new FatalCacheException(
"Unable to validate flushing model with id "
+ StringUtils.quote(id), exception);
}
}
onAfterPropertiesSet();
}
/**
* Flushes the cache.
*
* @param methodInvocation
* the description of the intercepted method.
* @return the return value of the intercepted method.
* @throws Throwable
* any exception thrown when executing the intercepted method
*/
public final Object invoke(MethodInvocation methodInvocation)
throws Throwable {
FlushingModel model = getModel(methodInvocation);
if (null == model) {
logger.info("Unable to flush cache. "
+ "No model is associated to the intercepted method");
return methodInvocation.proceed();
}
Object proceedReturnValue = null;
if (model.flushBeforeMethodExecution()) {
cacheProviderFacade.flushCache(model);
proceedReturnValue = methodInvocation.proceed();
} else {
proceedReturnValue = methodInvocation.proceed();
cacheProviderFacade.flushCache(model);
}
return proceedReturnValue;
}
/**
* Sets the facade for the cache provider to use.
*
* @param newCacheProviderFacade
* the new cache provider facade
*/
public final void setCacheProviderFacade(
CacheProviderFacade newCacheProviderFacade) {
cacheProviderFacade = newCacheProviderFacade;
}
/**
* Sets the flushing models to use.
*
* @param newFlushingModels
* the new flushing models
*/
public final void setFlushingModels(Map newFlushingModels) {
flushingModels = newFlushingModels;
}
/**
* @return the map that specifies how caching models should be bound to class
* methods
*/
protected final Map getFlushingModels() {
return flushingModels;
}
/**
* Returns the flushing model bound to an intercepted method.
*
* @param methodInvocation
* the description of the invocation to the intercepted method
* @return the flushing model boudn to the given intercepted method
*/
protected abstract FlushingModel getModel(MethodInvocation methodInvocation);
/**
* Gives subclasses the opportunity to set up their own properties.
*
* @throws FatalCacheException
* if one or more properties of this interceptor contain invalid
* values or have an illegal state.
*/
protected void onAfterPropertiesSet() throws FatalCacheException {
// no implementation.
}
}