package org.transgalactica.batch.salaire.context; import java.time.LocalDate; import javax.persistence.EntityManagerFactory; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepScope; import org.springframework.batch.item.database.JpaPagingItemReader; import org.springframework.batch.item.file.FlatFileItemReader; import org.springframework.batch.item.file.FlatFileItemWriter; import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper; import org.springframework.batch.item.file.mapping.DefaultLineMapper; import org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor; import org.springframework.batch.item.file.transform.DelimitedLineTokenizer; import org.springframework.batch.item.file.transform.FormatterLineAggregator; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; import org.transgalactica.batch.salaire.bo.SalaireTo; import org.transgalactica.batch.salaire.item.BasicComputeSalaireItemProcessor; import org.transgalactica.batch.salaire.item.ITextFicheSalairePdfItemWriter; import org.transgalactica.management.data.people.bo.EmployeEntity; import com.google.common.collect.ImmutableMap; /** * Notes d'implementation : * <ul> * <li>Type de retour des "Items" : https://jira.spring.io/browse/BATCH-2097</li> * <li>Declaration des Beans avec <code>destroyMethod=""</code> pour eviter * l'auto-discover (cf javadoc)</li> * </ul> * * @author Thierry */ @Configuration @EnableBatchProcessing public class JobConfig { @Autowired private BeanFactory beanFactory; @Autowired private JobBuilderFactory jobs; @Autowired private StepBuilderFactory steps; @Autowired private EntityManagerFactory emf; @Bean public Job ficheSalaireJob() throws Exception { return jobs.get("ficheSalaireJob") // .start(computeSalaireStep()) // .next(editFicheSalaireStep()).build(); } @Bean public Step computeSalaireStep() throws Exception { return steps.get("computeSalaireStep") // .<EmployeEntity, SalaireTo> chunk(3) // .reader(employeEntityItemReader()) // .processor(computeSalaireItemProcessor(DATE_CALCUL)) // .writer(salaireToItemWriter(COMPUTE_OUTPUT_FILE)).build(); } @Bean(destroyMethod = "") public JpaPagingItemReader<EmployeEntity> employeEntityItemReader() throws Exception { JpaPagingItemReader<EmployeEntity> reader = new JpaPagingItemReader<>(); reader.setEntityManagerFactory(emf); // fetch join pour s'assurer du chargement des données necessaire lors // du process (em fermé) reader.setQueryString("select e from AbstractJpaEmployeEntity e left join fetch e.specialites order by id"); reader.afterPropertiesSet(); return reader; } @Bean @StepScope public BasicComputeSalaireItemProcessor computeSalaireItemProcessor( @Value("#{jobParameters['salaire.compute.date']}") LocalDate dateCalcul) { BasicComputeSalaireItemProcessor processor = BeanUtils.instantiateClass(BasicComputeSalaireItemProcessor.class); processor.setDateCalcul(dateCalcul); return processor; } @Bean(destroyMethod = "") @StepScope public FlatFileItemWriter<SalaireTo> salaireToItemWriter( @Value("#{jobParameters['salaire.compute.output.filename']}") Resource output) throws Exception { BeanWrapperFieldExtractor<SalaireTo> fieldExtractor = new BeanWrapperFieldExtractor<>(); fieldExtractor.setNames(SALAIRE_FIELD_NAMES); FormatterLineAggregator<SalaireTo> lineAggregator = new FormatterLineAggregator<>(); lineAggregator.setFormat("%s,%tF,%s,%.0f,%.0f,%.0f,%.0f"); lineAggregator.setFieldExtractor(fieldExtractor); FlatFileItemWriter<SalaireTo> writer = new FlatFileItemWriter<>(); writer.setResource(output); writer.setEncoding("UTF-8"); writer.setLineAggregator(lineAggregator); writer.afterPropertiesSet(); return writer; } @Bean public Step editFicheSalaireStep() throws Exception { return steps.get("editFicheSalaireStep") // .<SalaireTo, SalaireTo> chunk(3) // .reader(salaireToItemReader(COMPUTE_OUTPUT_FILE)) // .writer(salairePdfItemWriter(EDIT_OUTPUT_DIR, DATE_CALCUL)).build(); } @Bean(destroyMethod = "") @StepScope public FlatFileItemReader<SalaireTo> salaireToItemReader( @Value("#{jobParameters['salaire.compute.output.filename']}") Resource input) throws Exception { DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer(); tokenizer.setNames(SALAIRE_FIELD_NAMES); BeanWrapperFieldSetMapper<SalaireTo> fieldSetMapper = new BeanWrapperFieldSetMapper<>(); fieldSetMapper.setBeanFactory(beanFactory); fieldSetMapper.setPrototypeBeanName("org.transgalactica.batch.salaire.bo.SalaireTo"); fieldSetMapper.setCustomEditors(ImmutableMap.of(LocalDate.class, new LocalDatePropertyEditor())); BeanWrapperFieldExtractor<SalaireTo> fieldExtractor = new BeanWrapperFieldExtractor<>(); fieldExtractor.setNames(new String[] { "nomEmploye", "dateEmbaucheEmploye", "typeEmploye", "salaireBase", "primeAnciennete", "primeExperience", "salaire" }); DefaultLineMapper<SalaireTo> lineMapper = new DefaultLineMapper<>(); lineMapper.setLineTokenizer(tokenizer); lineMapper.setFieldSetMapper(fieldSetMapper); FlatFileItemReader<SalaireTo> reader = new FlatFileItemReader<>(); reader.setResource(input); reader.setEncoding("UTF-8"); reader.setLineMapper(lineMapper); reader.afterPropertiesSet(); return reader; } @Bean @StepScope public ITextFicheSalairePdfItemWriter salairePdfItemWriter( @Value("#{jobParameters['salaire.edit.output.directory']}") Resource output, @Value("#{jobParameters['salaire.compute.date']}") LocalDate dateCalcul) { ITextFicheSalairePdfItemWriter writer = BeanUtils.instantiateClass(ITextFicheSalairePdfItemWriter.class); writer.setOutputDirectory(output); writer.setDateCalcul(dateCalcul); return writer; } private static final String[] SALAIRE_FIELD_NAMES = new String[] { "nomEmploye", "dateEmbaucheEmploye", "typeEmploye", "salaireBase", "primeAnciennete", "primeExperience", "salaire" }; // overidden by expressions private final static LocalDate DATE_CALCUL = null; private final static Resource COMPUTE_OUTPUT_FILE = null; private final static Resource EDIT_OUTPUT_DIR = null; }