001/* 002 * Copyright 2009-2018 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.item.file; 017 018import org.springframework.batch.item.ExecutionContext; 019import org.springframework.batch.item.ItemReader; 020import org.springframework.batch.item.ItemStreamException; 021import org.springframework.batch.item.support.AbstractItemStreamItemReader; 022import org.springframework.core.io.Resource; 023import org.springframework.core.io.support.ResourceArrayPropertyEditor; 024import org.springframework.lang.Nullable; 025 026import java.util.Arrays; 027import java.util.concurrent.atomic.AtomicInteger; 028 029/** 030 * {@link ItemReader} which produces {@link Resource} instances from an array. 031 * This can be used conveniently with a configuration entry that injects a 032 * pattern (e.g. <code>mydir/*.txt</code>, which can then be converted by Spring 033 * to an array of Resources by the ApplicationContext. 034 * 035 * <br> 036 * <br> 037 * 038 * Thread-safe between calls to {@link #open(ExecutionContext)}. The 039 * {@link ExecutionContext} is not accurate in a multi-threaded environment, so 040 * do not rely on that data for restart (i.e. always open with a fresh context). 041 * 042 * @author Dave Syer 043 * @author Mahmoud Ben Hassine 044 * 045 * @see ResourceArrayPropertyEditor 046 * 047 * @since 2.1 048 */ 049public class ResourcesItemReader extends AbstractItemStreamItemReader<Resource> { 050 051 private Resource[] resources = new Resource[0]; 052 053 private AtomicInteger counter = new AtomicInteger(0); 054 055 public ResourcesItemReader() { 056 /* 057 * Initialize the name for the key in the execution context. 058 */ 059 this.setExecutionContextName(getClass().getName()); 060 } 061 062 /** 063 * The resources to serve up as items. Hint: use a pattern to configure. 064 * 065 * @param resources the resources 066 */ 067 public void setResources(Resource[] resources) { 068 this.resources = Arrays.asList(resources).toArray(new Resource[resources.length]); 069 } 070 071 /** 072 * Increments a counter and returns the next {@link Resource} instance from 073 * the input, or {@code null} if none remain. 074 */ 075 @Override 076 @Nullable 077 public synchronized Resource read() throws Exception { 078 int index = counter.incrementAndGet() - 1; 079 if (index >= resources.length) { 080 return null; 081 } 082 return resources[index]; 083 } 084 085 @Override 086 public void open(ExecutionContext executionContext) throws ItemStreamException { 087 super.open(executionContext); 088 counter.set(executionContext.getInt(getExecutionContextKey("COUNT"), 0)); 089 } 090 091 @Override 092 public void update(ExecutionContext executionContext) throws ItemStreamException { 093 super.update(executionContext); 094 executionContext.putInt(getExecutionContextKey("COUNT"), counter.get()); 095 } 096 097}