/*
* Copyright 2009-2014 Jose Luis Martin.
*
* 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.
*/
package org.jdal.aop;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdal.annotation.SerializableProxy;
import org.springframework.aop.aspectj.TypePatternClassFilter;
import org.springframework.aop.framework.autoproxy.ProxyCreationContext;
import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.annotation.AnnotationUtils;
/**
* Advisor for SerializableProxy annotation on types.
*
* @author Jose Luis Martin.
* @since 2.0
*/
public class SerializableProxyAdvisor extends DefaultIntroductionAdvisor
implements BeanFactoryAware {
private static final Log log = LogFactory.getLog(SerializableProxyAdvisor.class);
private ConfigurableListableBeanFactory beanFactory;
private TypePatternClassFilter typePatternClassFilter = new TypePatternClassFilter();
public SerializableProxyAdvisor() {
super(new SerializableIntroductionInterceptor());
}
/**
* Checks for {@link SerializableProxy} annotation at type level.
* @return true if annotation found.
*/
@Override
public boolean matches(Class<?> clazz) {
String beanName = ProxyCreationContext.getCurrentProxiedBeanName();
// skip serializable proxies and targets
if (SerializableAopProxy.class.isAssignableFrom(clazz) || isTargetSerializableProxyBean(beanName) )
return false;
// check annotation
SerializableProxy ann = AnnotationUtils.findAnnotation(clazz, SerializableProxy.class);
if (ann != null) {
if (isProxyInCreation(beanName)) {
configureReference(ann, beanName);
}
return true;
}
// check type pattern
if (getTypePattern() != null && this.typePatternClassFilter.matches(clazz)) {
if (isProxyInCreation(beanName))
configureReference(beanName);
return true;
}
return false;
}
/**
* Configure reference with target bean name
* @param beanName target bean name
*/
private void configureReference(String beanName) {
if (log.isDebugEnabled())
log.debug("Configuring serializable reference for bean [" + beanName +"]");
SerializableReference reference = getReference();
reference.setTargetBeanName(beanName);
reference.setBeanFactory(this.beanFactory);
}
/**
* Test if autoproxy creator is creating the proxy.
* @param beanName bean name
* @return true if beanName is not null
*/
private boolean isProxyInCreation(String beanName) {
return beanName != null;
}
/**
* Test if beanName match a serializable proxy target bean created by {@link SerializableProxyUtils}
* @param beanName the name to check
* @return true if is a target bean of a serializable proxy
*/
private boolean isTargetSerializableProxyBean(String beanName) {
return beanName != null && beanName.startsWith(SerializableProxyUtils.TARGET_NAME_PREFIX);
}
/**
* Configure the serializable reference with annotation parameters and target bean name.
* @param ann annotation.
*/
private void configureReference(SerializableProxy ann, String beanName) {
SerializableReference reference = getReference();
reference.setProxyTargetClass(ann.proxyTargetClass());
reference.setUseMemoryCache(ann.useCache());
configureReference(beanName);
}
/**
* @return the serializable reference
*/
private SerializableReference getReference() {
SerializableIntroductionInterceptor advice = (SerializableIntroductionInterceptor) getAdvice();
return advice.getReference();
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
public String getTypePattern() {
return this.typePatternClassFilter.getTypePattern();
}
public void setTypePattern(String typePattern) {
this.typePatternClassFilter.setTypePattern(typePattern);
}
public boolean isUseMemoryCache() {
return getReference().isUseMemoryCache();
}
public void setUseMemoryCache(boolean useMemoryCache) {
getReference().setUseMemoryCache(useMemoryCache);
}
}