001/*
002 * Copyright 2013 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.springframework.batch.core.jsr.partition.support;
017
018import org.springframework.batch.core.jsr.configuration.xml.StepFactoryBean;
019import org.springframework.batch.core.jsr.partition.JsrPartitionHandler;
020import org.springframework.beans.BeansException;
021import org.springframework.beans.PropertyValue;
022import org.springframework.beans.factory.config.BeanDefinition;
023import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
024import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
025import org.springframework.beans.factory.config.RuntimeBeanReference;
026
027import javax.batch.api.partition.PartitionAnalyzer;
028import javax.batch.api.partition.PartitionMapper;
029import javax.batch.api.partition.PartitionReducer;
030
031/**
032 * In order for property resolution to occur correctly within the scope of a JSR-352
033 * batch job, initialization of job level artifacts must occur on the same thread that
034 * the job is executing.  To allow this to occur, {@link PartitionMapper},
035 * {@link PartitionReducer}, and {@link PartitionAnalyzer} are all configured to
036 * lazy initialization (equivalent to lazy-init="true").
037 *
038 * @author Michael Minella
039 * @since 3.0
040 */
041public class JsrBeanScopeBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
042
043        private JobLevelBeanLazyInitializer initializer;
044
045        /* (non-Javadoc)
046         * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory)
047         */
048        @Override
049        public void postProcessBeanFactory(
050                        ConfigurableListableBeanFactory beanFactory) throws BeansException {
051                if (initializer == null) {
052                        this.initializer = new JobLevelBeanLazyInitializer(beanFactory);
053                }
054
055                String[] beanNames = beanFactory.getBeanDefinitionNames();
056
057                for (String curName : beanNames) {
058                        initializer.visitBeanDefinition(beanFactory.getBeanDefinition(curName));
059                }
060        }
061
062        /**
063         * Looks for beans that may have dependencies that need to be lazily initialized and
064         * configures the corresponding {@link BeanDefinition} accordingly.
065         *
066         * @author Michael Minella
067         * @since 3.0
068         */
069        public static class JobLevelBeanLazyInitializer {
070
071                private ConfigurableListableBeanFactory beanFactory;
072
073                public JobLevelBeanLazyInitializer(ConfigurableListableBeanFactory beanFactory) {
074                        this.beanFactory = beanFactory;
075                }
076
077                public void visitBeanDefinition(BeanDefinition beanDefinition) {
078                        String beanClassName = beanDefinition.getBeanClassName();
079
080                        if(StepFactoryBean.class.getName().equals(beanClassName)) {
081                                PropertyValue [] values = beanDefinition.getPropertyValues().getPropertyValues();
082                                for (PropertyValue propertyValue : values) {
083                                        if(propertyValue.getName().equalsIgnoreCase("partitionReducer")) {
084                                                RuntimeBeanReference ref = (RuntimeBeanReference) propertyValue.getValue();
085                                                beanFactory.getBeanDefinition(ref.getBeanName()).setLazyInit(true);
086                                        }
087                                }
088                        }
089
090                        if(JsrPartitionHandler.class.getName().equals(beanClassName)) {
091                                PropertyValue [] values = beanDefinition.getPropertyValues().getPropertyValues();
092                                for (PropertyValue propertyValue : values) {
093                                        String propertyName = propertyValue.getName();
094                                        if(propertyName.equalsIgnoreCase("partitionMapper") || propertyName.equalsIgnoreCase("partitionAnalyzer")) {
095                                                RuntimeBeanReference ref = (RuntimeBeanReference) propertyValue.getValue();
096                                                beanFactory.getBeanDefinition(ref.getBeanName()).setLazyInit(true);
097                                        }
098                                }
099                        }
100                }
101        }
102}