Java tutorial
/** * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.arkadiko.bean; import com.liferay.arkadiko.internal.Constants; import com.liferay.arkadiko.reflect.Introspector; import com.liferay.arkadiko.sr.ServiceRegistry; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Collections; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.BeanPostProcessor; 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.AutowireCandidateResolver; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.support.SimpleInstantiationStrategy; import org.springframework.core.Ordered; /** * @author Raymond Aug */ public class AKBeanPostProcessor extends SimpleInstantiationStrategy implements BeanFactoryPostProcessor, BeanPostProcessor, Ordered { public void afterPropertiesSet() { if (_serviceRegistry == null) { throw new IllegalArgumentException("serviceRegistry is required"); } if (_excludeBeanNames == null) { _excludeBeanNames = Collections.emptyList(); } if (_excludeClassNames == null) { _excludeClassNames = Collections.emptyList(); } if (_includeBeanNames == null) { _includeBeanNames = Collections.emptyList(); } if (_includeClassNames == null) { _includeClassNames = Collections.emptyList(); } } /** * Gets the order. * * @return the order */ public int getOrder() { return _order; } /** * Gets the service registry (an abstraction of the OSGi framework service * registry). * * @return the service registry */ public ServiceRegistry getServiceRegistry() { return _serviceRegistry; } @Override public Object instantiate(RootBeanDefinition rootBeanDefinition, String beanName, BeanFactory owner) { Object bean = getServiceBean(rootBeanDefinition, beanName); if (bean != null) { return bean; } return super.instantiate(rootBeanDefinition, beanName, owner); } @Override public Object instantiate(RootBeanDefinition rootBeanDefinition, String beanName, BeanFactory owner, Constructor<?> constructor, Object[] arguments) { Object bean = getServiceBean(rootBeanDefinition, beanName); if (bean != null) { return bean; } return super.instantiate(rootBeanDefinition, beanName, owner, constructor, arguments); } @Override public Object instantiate(RootBeanDefinition rootBeanDefinition, String beanName, BeanFactory owner, Object factoryBean, Method factoryMethod, Object[] arguments) { Object bean = getServiceBean(rootBeanDefinition, beanName); if (bean != null) { return bean; } return super.instantiate(rootBeanDefinition, beanName, owner, factoryBean, factoryMethod, arguments); } /** * Post process after initialization. * * @param bean the bean * @param beanName the bean id * @return the object * @throws BeansException the beans exception */ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { Class<?>[] interfaces = Introspector.getInterfaces(bean); if (ignoreBean(bean.getClass().getName(), beanName, interfaces)) { return bean; } _serviceRegistry.registerBeanService(bean, beanName, interfaces); try { return _serviceRegistry.createTrackingProxy(bean, beanName, interfaces); } catch (Exception e) { throw new AKBeansException(e.getMessage(), e); } } /** * Post process bean factory. * * @param beanFactory the bean factory * @throws BeansException the beans exception */ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { if (!(beanFactory instanceof DefaultListableBeanFactory)) { return; } DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory; defaultListableBeanFactory.setInstantiationStrategy(this); AutowireCandidateResolver autowireCandidateResolver = defaultListableBeanFactory .getAutowireCandidateResolver(); defaultListableBeanFactory .setAutowireCandidateResolver(new AKAutowireCandidateResolver(autowireCandidateResolver)); for (String beanName : defaultListableBeanFactory.getBeanDefinitionNames()) { BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName); if (!(beanDefinition instanceof AbstractBeanDefinition)) { continue; } String className = beanDefinition.getBeanClassName(); if (className == null) { continue; } try { AKBeanDefinition akBeanDefinition = new AKBeanDefinition(this, (AbstractBeanDefinition) beanDefinition, beanName, getServiceRegistry()); defaultListableBeanFactory.removeBeanDefinition(beanName); defaultListableBeanFactory.registerBeanDefinition(beanName, akBeanDefinition); } catch (Exception e) { if (_log.isLoggable(Level.SEVERE)) { _log.log(Level.SEVERE, e.getMessage(), e); } } } } /** * Post process before initialization. * * @param bean the bean * @param beanName the bean id * @return the object * @throws BeansException the beans exception */ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } /** * excludeBeanNames (Optional): * * Provide a list of bean names that should be excluded. Names may be * prefixed OR suffixed with a * for simple matching. * * @param excludeBeanNames the new ignored bean names */ public void setExcludeBeanNames(List<String> excludeBeanNames) { _excludeBeanNames = excludeBeanNames; } /** * excludeClassNames (Optional): * * Provide a list of class names that should be excluded. Names may be * prefixed OR suffixed with a * for simple matching. * * @param excludeClassNames the new ignored class names */ public void setExcludeClassNames(List<String> excludeClassNames) { _excludeClassNames = excludeClassNames; } /** * includeBeanNames (Optional): * * Provide a list of bean names that should be included. Names may be * prefixed OR suffixed with a * for simple matching. The default * behavior, if no list is provided, is to include no beans. * * @param includeBeanNames the new include bean names */ public void setIncludeBeanNames(List<String> includeBeanNames) { _includeBeanNames = includeBeanNames; } /** * includeClassNames (Optional): * * Provide a list of class names that should be included. Names may be * prefixed OR suffixed with a * for simple matching. The default * behavior, if no list is provided, is to include no beans. * * @param includeClassNames the new include class names */ public void setIncludeClassNames(List<String> includeClassNames) { _includeClassNames = includeClassNames; } /** * order (Optional): * * As a BeanPostProcessor, we may have to play nicely with other * BeanPostProcessors also included in the spring context. Use the * order property to adjust the order in which BeanPostProcessors are * invoked by spring. When BeanPostProcessors don't set an order, the * ordering of invocation is indeterminate which may lead to unexpected * behavior and possibly errors. Therefore setting the specific order is * recommended. The most common case for Arkadiko is to be invoked last. * The default value is 20. * * @param order the new order */ public void setOrder(int order) { _order = order; } /** * serviceRegistry (Required): * * Provide an instance of com.liferay.arkadiko.sr.ServiceRegistry into which * the spring beans, matching the rules below, will be published. In * turn, from the service registry, it will be possible to provide services * that implement or override beans that are needed or used in this spring * context. * * @param serviceRegistry the service registry */ public void setServiceRegistry(ServiceRegistry serviceRegistry) { _serviceRegistry = serviceRegistry; } /** * Exclude bean by bean name. * * @param beanName the bean id * @return true, if successful */ protected boolean excludeBeanByBeanName(String beanName) { for (String excludedbeanName : _excludeBeanNames) { if (beanName.equals(excludedbeanName)) { return true; } else if (excludedbeanName.startsWith(Constants.STAR) && beanName.endsWith(excludedbeanName.substring(1))) { return true; } else if (excludedbeanName.endsWith(Constants.STAR) && beanName.startsWith(excludedbeanName.substring(0, excludedbeanName.length() - 1))) { return true; } } return false; } /** * Exclude bean by class name. * * @param className the class name * @return true, if successful */ protected boolean excludeBeanByClassName(String className) { for (String excludedClassName : _excludeClassNames) { if (className.equals(excludedClassName)) { return true; } else if (excludedClassName.startsWith(Constants.STAR) && className.endsWith(excludedClassName.substring(1))) { return true; } else if (excludedClassName.endsWith(Constants.STAR) && className.startsWith(excludedClassName.substring(0, excludedClassName.length() - 1))) { return true; } } return false; } /** * Try to get an Arkadiko bean which is a proxy backed by an OSGi service * tracker which is either going to wrap an existing spring bean, or wait * for one to be registered. This only happens when the bean is declared to * be wrapped by name or by class/interface. * * @param rootBeanDefinition * @param beanName * @return a bean or null */ protected Object getServiceBean(RootBeanDefinition rootBeanDefinition, String beanName) { BeanDefinition originatingBeanDefinition = rootBeanDefinition.getOriginatingBeanDefinition(); if ((originatingBeanDefinition != null) && (originatingBeanDefinition instanceof AKBeanDefinition)) { AKBeanDefinition akBeanDefinition = (AKBeanDefinition) originatingBeanDefinition; return akBeanDefinition.getProxy(); } else if (rootBeanDefinition.hasBeanClass()) { Class<?> clazz = rootBeanDefinition.getBeanClass(); if (clazz.isInterface()) { AKBeanDefinition akBeanDefinition = new AKBeanDefinition(this, rootBeanDefinition, beanName, getServiceRegistry()); return akBeanDefinition.getProxy(); } } return null; } /** * Include bean by bean name. * * @param beanName the bean id * @return true, if successful */ protected boolean includeBeanByBeanName(String beanName) { for (String includedBeanName : _includeBeanNames) { if (beanName.equals(includedBeanName)) { return true; } else if (includedBeanName.startsWith(Constants.STAR) && beanName.endsWith(includedBeanName.substring(1))) { return true; } else if (includedBeanName.endsWith(Constants.STAR) && beanName.startsWith(includedBeanName.substring(0, includedBeanName.length() - 1))) { return true; } } return false; } /** * Include bean by class name. * * @param className the class name * @return true, if successful */ protected boolean includeBeanByClassName(String className) { for (String includedClassName : _includeClassNames) { if (className.equals(includedClassName)) { return true; } else if (includedClassName.startsWith(Constants.STAR) && className.endsWith(includedClassName.substring(1))) { return true; } else if (includedClassName.endsWith(Constants.STAR) && className.startsWith(includedClassName.substring(0, includedClassName.length() - 1))) { return true; } } return false; } /** * Ignore bean. * * @param bean the bean * @param beanName the bean id * @param interfaces the interfaces * @return true, if successful */ protected boolean ignoreBean(String beanClass, String beanName, Class<?>[] interfaces) { // Automatically exclude anonymous beans or beans that don't implement // any interfaces if ((beanName.indexOf(Constants.POUND) != -1) || (beanName.equals(Constants.INNER_BEAN)) || (interfaces.length <= 0)) { return true; } if (!excludeBeanByBeanName(beanName) && !excludeBeanByClassName(beanClass) && (includeBeanByBeanName(beanName) || includeBeanByClassName(beanClass))) { return false; } return true; } private static Logger _log = Logger.getLogger(AKBeanPostProcessor.class.getName()); private List<String> _excludeBeanNames; private List<String> _excludeClassNames; private List<String> _includeBeanNames; private List<String> _includeClassNames; private int _order = 20; private ServiceRegistry _serviceRegistry; private class AKAutowireCandidateResolver implements AutowireCandidateResolver { AKAutowireCandidateResolver(AutowireCandidateResolver autowireCandidateResolver) { _autowireCandidateResolver = autowireCandidateResolver; } @Override public boolean isAutowireCandidate(BeanDefinitionHolder beanDefinitionHolder, DependencyDescriptor descriptor) { return _autowireCandidateResolver.isAutowireCandidate(beanDefinitionHolder, descriptor); } @Override public Object getSuggestedValue(DependencyDescriptor descriptor) { Object service = _autowireCandidateResolver.getSuggestedValue(descriptor); if (service != null) { return service; } try { return _serviceRegistry.createTrackingProxy(null, descriptor.getDependencyName(), new Class<?>[] { descriptor.getDependencyType() }); } catch (Exception e) { if (_log.isLoggable(Level.SEVERE)) { _log.log(Level.SEVERE, e.getMessage(), e); } } return null; } private AutowireCandidateResolver _autowireCandidateResolver; } }