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; 017 018import java.util.Properties; 019 020import javax.batch.runtime.StepExecution; 021import javax.batch.runtime.context.JobContext; 022 023import org.springframework.batch.core.JobExecution; 024import org.springframework.batch.core.jsr.configuration.support.BatchPropertyContext; 025import org.springframework.batch.core.scope.context.StepSynchronizationManager; 026import org.springframework.beans.factory.FactoryBean; 027import org.springframework.beans.factory.FactoryBeanNotInitializedException; 028import org.springframework.beans.factory.annotation.Autowired; 029import org.springframework.util.Assert; 030 031/** 032 * Provides a single {@link JobContext} for each thread in a running job. 033 * Subsequent calls to {@link FactoryBean#getObject()} on the same thread will 034 * return the same instance. The {@link JobContext} wraps a {@link JobExecution} 035 * which is obtained in one of two ways: 036 * <ul> 037 * <li>The current step scope (getting it from the current {@link StepExecution}</li> 038 * <li>The provided {@link JobExecution} via the {@link #setJobExecution(JobExecution)} 039 * </ul> 040 * 041 * @author Michael Minella 042 * @since 3.0 043 */ 044public class JsrJobContextFactoryBean implements FactoryBean<JobContext> { 045 046 private JobExecution jobExecution; 047 @Autowired 048 private BatchPropertyContext propertyContext; 049 050 private static final ThreadLocal<JobContext> contextHolder = new ThreadLocal<JobContext>(); 051 052 /* (non-Javadoc) 053 * @see org.springframework.beans.factory.FactoryBean#getObject() 054 */ 055 @Override 056 public JobContext getObject() throws Exception { 057 return getCurrent(); 058 } 059 060 /* (non-Javadoc) 061 * @see org.springframework.beans.factory.FactoryBean#getObjectType() 062 */ 063 @Override 064 public Class<?> getObjectType() { 065 return JobContext.class; 066 } 067 068 /* (non-Javadoc) 069 * @see org.springframework.beans.factory.FactoryBean#isSingleton() 070 */ 071 @Override 072 public boolean isSingleton() { 073 return false; 074 } 075 076 /** 077 * Used to provide {@link JobContext} instances to batch artifacts that 078 * are not within the scope of a given step. 079 * 080 * @param jobExecution set the current {@link JobExecution} 081 */ 082 public void setJobExecution(JobExecution jobExecution) { 083 Assert.notNull(jobExecution, "A JobExecution is required"); 084 this.jobExecution = jobExecution; 085 } 086 087 /** 088 * @param propertyContext the {@link BatchPropertyContext} to obtain job properties from 089 */ 090 public void setBatchPropertyContext(BatchPropertyContext propertyContext) { 091 this.propertyContext = propertyContext; 092 } 093 094 /** 095 * Used to remove the {@link JobContext} for the current thread. Not used via 096 * normal processing but useful for testing. 097 */ 098 public void close() { 099 if(contextHolder.get() != null) { 100 contextHolder.remove(); 101 } 102 } 103 104 private JobContext getCurrent() { 105 if(contextHolder.get() == null) { 106 JobExecution curJobExecution = null; 107 108 if(StepSynchronizationManager.getContext() != null) { 109 curJobExecution = StepSynchronizationManager.getContext().getStepExecution().getJobExecution(); 110 } 111 112 if(curJobExecution != null) { 113 jobExecution = curJobExecution; 114 } 115 116 if(jobExecution == null) { 117 throw new FactoryBeanNotInitializedException("A JobExecution is required"); 118 } 119 120 JsrJobContext jobContext = new JsrJobContext(); 121 jobContext.setJobExecution(jobExecution); 122 123 if(propertyContext != null) { 124 jobContext.setProperties(propertyContext.getJobProperties()); 125 } else { 126 jobContext.setProperties(new Properties()); 127 } 128 129 contextHolder.set(jobContext); 130 } 131 132 return contextHolder.get(); 133 } 134}