/* * Copyright 2006-2013 the original author or authors. * * 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.springframework.batch.core.configuration.annotation; import static org.junit.Assert.assertEquals; import java.util.concurrent.Callable; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobInstance; import org.springframework.batch.core.StepContribution; import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.batch.core.scope.context.JobSynchronizationManager; import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ImportResource; import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.ScopedProxyMode; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author Dave Syer * @author Michael Minella * */ public class JobScopeConfigurationTests { private ConfigurableApplicationContext context; private JobExecution jobExecution; @Rule public ExpectedException expected = ExpectedException.none(); @Test public void testXmlJobScopeWithProxyTargetClass() throws Exception { context = new ClassPathXmlApplicationContext( "org/springframework/batch/core/configuration/annotation/JobScopeConfigurationTestsProxyTargetClass-context.xml"); JobSynchronizationManager.register(jobExecution); SimpleHolder value = context.getBean(SimpleHolder.class); assertEquals("JOB", value.call()); } @Test public void testXmlJobScopeWithInterface() throws Exception { context = new ClassPathXmlApplicationContext( "org/springframework/batch/core/configuration/annotation/JobScopeConfigurationTestsInterface-context.xml"); JobSynchronizationManager.register(jobExecution); @SuppressWarnings("unchecked") Callable<String> value = context.getBean(Callable.class); assertEquals("JOB", value.call()); } @Test public void testXmlJobScopeWithInheritence() throws Exception { context = new ClassPathXmlApplicationContext( "org/springframework/batch/core/configuration/annotation/JobScopeConfigurationTestsInheritence-context.xml"); JobSynchronizationManager.register(jobExecution); SimpleHolder value = (SimpleHolder) context.getBean("child"); assertEquals("JOB", value.call()); } @Test public void testJobScopeWithProxyTargetClass() throws Exception { init(JobScopeConfigurationRequiringProxyTargetClass.class); SimpleHolder value = context.getBean(SimpleHolder.class); assertEquals("JOB", value.call()); } @Test public void testStepScopeXmlImportUsingNamespace() throws Exception { init(JobScopeConfigurationXmlImportUsingNamespace.class); SimpleHolder value = (SimpleHolder) context.getBean("xmlValue"); assertEquals("JOB", value.call()); value = (SimpleHolder) context.getBean("javaValue"); assertEquals("JOB", value.call()); } @Test public void testJobScopeWithProxyTargetClassInjected() throws Exception { init(JobScopeConfigurationInjectingProxy.class); SimpleHolder value = context.getBean(Wrapper.class).getValue(); assertEquals("JOB", value.call()); } @Test public void testIntentionallyBlowUpOnMissingContextWithProxyTargetClass() throws Exception { init(JobScopeConfigurationRequiringProxyTargetClass.class); JobSynchronizationManager.release(); expected.expect(BeanCreationException.class); expected.expectMessage("job scope"); SimpleHolder value = context.getBean(SimpleHolder.class); assertEquals("JOB", value.call()); } @Test public void testIntentionallyBlowupWithForcedInterface() throws Exception { init(JobScopeConfigurationForcingInterfaceProxy.class); JobSynchronizationManager.release(); expected.expect(BeanCreationException.class); expected.expectMessage("job scope"); SimpleHolder value = context.getBean(SimpleHolder.class); assertEquals("JOB", value.call()); } @Test public void testJobScopeWithDefaults() throws Exception { init(JobScopeConfigurationWithDefaults.class); @SuppressWarnings("unchecked") Callable<String> value = context.getBean(Callable.class); assertEquals("JOB", value.call()); } @Test public void testIntentionallyBlowUpOnMissingContextWithInterface() throws Exception { init(JobScopeConfigurationWithDefaults.class); JobSynchronizationManager.release(); expected.expect(BeanCreationException.class); expected.expectMessage("job scope"); @SuppressWarnings("unchecked") Callable<String> value = context.getBean(Callable.class); assertEquals("JOB", value.call()); } public void init(Class<?>... config) throws Exception { Class<?>[] configs = new Class<?>[config.length + 1]; System.arraycopy(config, 0, configs, 1, config.length); configs[0] = DataSourceConfiguration.class; AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(configs); context.refresh(); this.context = context; JobSynchronizationManager.register(jobExecution); } @Before public void setup() { JobSynchronizationManager.release(); jobExecution = new JobExecution(new JobInstance(5l, "JOB"), null, null); } @After public void close() { JobSynchronizationManager.release(); if (context != null) { context.close(); } } public static class SimpleCallable implements Callable<String> { private final String value; private SimpleCallable(String value) { this.value = value; } @Override public String call() throws Exception { return value; } } public static class SimpleHolder { private final String value; protected SimpleHolder() { value = "<WRONG>"; } public SimpleHolder(String value) { this.value = value; } public String call() throws Exception { return value; } } public static class Wrapper { private SimpleHolder value; public Wrapper(SimpleHolder value) { this.value = value; } public SimpleHolder getValue() { return value; } } public static class TaskletSupport implements Tasklet { @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { return RepeatStatus.FINISHED; } } @Configuration @ImportResource("org/springframework/batch/core/configuration/annotation/JobScopeConfigurationTestsXmlImportUsingNamespace-context.xml") @EnableBatchProcessing public static class JobScopeConfigurationXmlImportUsingNamespace { @Bean @JobScope protected SimpleHolder javaValue(@Value("#{jobName}") final String value) { return new SimpleHolder(value); } } @Configuration @EnableBatchProcessing public static class JobScopeConfigurationInjectingProxy { @Bean public Wrapper wrapper(SimpleHolder value) { return new Wrapper(value); } @Bean @Scope(value="job", proxyMode = ScopedProxyMode.TARGET_CLASS) protected SimpleHolder value(@Value("#{jobName}") final String value) { return new SimpleHolder(value); } } @Configuration @EnableBatchProcessing public static class JobScopeConfigurationRequiringProxyTargetClass { @Bean @Scope(value="job", proxyMode = ScopedProxyMode.TARGET_CLASS) protected SimpleHolder value(@Value("#{jobName}") final String value) { return new SimpleHolder(value); } } @Configuration @EnableBatchProcessing public static class JobScopeConfigurationWithDefaults { @Bean @JobScope protected Callable<String> value(@Value("#{jobName}") final String value) { return new SimpleCallable(value); } } @Configuration @EnableBatchProcessing public static class JobScopeConfigurationForcingInterfaceProxy { @Bean @Scope(value="job", proxyMode = ScopedProxyMode.INTERFACES) protected SimpleHolder value(@Value("#{jobName}") final String value) { return new SimpleHolder(value); } } }