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}