/* * 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.aop.config.SerializableProxyFactoryBean; import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.framework.autoproxy.AutoProxyUtils; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.DependencyDescriptor; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.RootBeanDefinition; /** * Utility class for creating proxy bean definitions. * <p> * Note: This class includes code from {@link org.springframework.aop.scope.ScopedProxyUtils} * </p> * @author Jose Luis Martin * @since 2.0 */ public class SerializableProxyUtils { public static Log log = LogFactory.getLog(SerializableProxyUtils.class); public static final String TARGET_NAME_PREFIX = "jdalSerializableProxy."; public static BeanDefinitionHolder createSerializableProxy(BeanDefinitionHolder definition, BeanDefinitionRegistry registry, boolean proxyTargetClass) { String originalBeanName = definition.getBeanName(); BeanDefinition targetDefinition = definition.getBeanDefinition(); // Create a scoped proxy definition for the original bean name, // "hiding" the target bean in an internal target definition. RootBeanDefinition proxyDefinition = new RootBeanDefinition(SerializableProxyFactoryBean.class); proxyDefinition.setOriginatingBeanDefinition(definition.getBeanDefinition()); proxyDefinition.setSource(definition.getSource()); proxyDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); String targetBeanName = getTargetBeanName(originalBeanName); proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName); if (proxyTargetClass) { targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE); } else { proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE); } // Copy autowire settings from original bean definition. proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate()); proxyDefinition.setPrimary(targetDefinition.isPrimary()); if (targetDefinition instanceof AbstractBeanDefinition) { proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition); } // Set singleton property of FactoryBean proxyDefinition.getPropertyValues().add("singleton", !targetDefinition.isPrototype()); // The target bean should be ignored in favor of the scoped proxy. targetDefinition.setAutowireCandidate(false); targetDefinition.setPrimary(false); // Register the target bean as separate bean in the factory. registry.registerBeanDefinition(targetBeanName, targetDefinition); // Return the scoped proxy definition as primary bean definition // (potentially an inner bean). return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases()); } public static String getTargetBeanName(String originalBeanName) { return TARGET_NAME_PREFIX + originalBeanName; } /** * Create a new Serializable proxy for the given target * @param target target to proxy * @param proxyTargetClass true to force CGLIB proxies * @param useMemoryCache if true keep a reference to target object in memory * @param beanFactory beanFactory to use. * @param descriptor Dependency descriptor * @param beanName name of bean holding the dependency * @return a new serializable proxy */ public static Object createSerializableProxy(Object target, boolean proxyTargetClass, boolean useMemoryCache, ConfigurableListableBeanFactory beanFactory, DependencyDescriptor descriptor, String beanName) { if (target instanceof SerializableAopProxy) return target; if (log.isDebugEnabled()) log.debug("Creating serializable proxy for [" + descriptor.getDependencyName() + "]" + " in bean [" + beanName + "]"); SerializableReference reference = new SerializableReference(target, proxyTargetClass, useMemoryCache, beanFactory, descriptor, beanName); return createSerializableProxy(target, reference); } /** * Create a new Serializable proxy for the given target * @param target target to proxy * @param proxyTargetClass true to force CGLIB proxies * @param useMemoryCache if true keep a reference to target object in memory * @param beanFactory beanFactory to use. * @param targetBeanName name of target bean * @return a new serializable proxy * */ public static Object createSerializableProxy(Object target, boolean proxyTargetClass, boolean useMemoryCache, ConfigurableListableBeanFactory beanFactory, String targetBeanName) { if (target instanceof SerializableAopProxy) return target; if (log.isDebugEnabled()) log.debug("Creating serializable proxy for target bean [" + targetBeanName + "]"); SerializableReference reference = new SerializableReference(target, proxyTargetClass, useMemoryCache, beanFactory, targetBeanName); return createSerializableProxy(target, reference); } /** * Creates a new serializable proxy for given target holding it in memory * until deserialization. * * @param target object to proxy * @return a serialziable proxy for target. */ public static Object createCachedSerializableProxy(Object target) { return createSerializableProxy(target, true, true, null, null); } /** * Create a new Serializable proxy for the given target * @param target target to proxy * @param beanFactory beanFactory to use. * @param targetBeanName name of the target bean. * @return a new serializable proxy */ public static Object createSerializableProxy(Object target, ConfigurableListableBeanFactory beanFactory, String targetBeanName) { return createSerializableProxy(target, false, false, beanFactory, targetBeanName); } /** * Create a new Serializable proxy for the given target. * @param target target to proxy * @param reference serializable reference * @return a new serializable proxy */ public static Object createSerializableProxy(Object target, SerializableReference reference) { ProxyFactory pf = new ProxyFactory(target); pf.setExposeProxy(true); pf.setProxyTargetClass(reference.isProxyTargetClass()); pf.addInterface(SerializableObject.class); pf.addAdvice(new SerializableIntroductionInterceptor(reference)); return pf.getProxy(reference.getBeanFactory().getBeanClassLoader()); } }