001/*
002 * Copyright 2006-2007 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 */
016
017package org.springframework.batch.repeat.context;
018
019import java.util.concurrent.atomic.AtomicInteger;
020
021import org.springframework.batch.repeat.RepeatContext;
022import org.springframework.util.Assert;
023
024/**
025 * Helper class for policies that need to count the number of occurrences of
026 * some event (e.g. an exception type in the context) in the scope of a batch.
027 * The value of the counter can be stored between batches in a nested context,
028 * so that the termination decision is based on the aggregate of a number of
029 * sibling batches.
030 * 
031 * @author Dave Syer
032 * 
033 */
034public class RepeatContextCounter {
035
036        final private String countKey;
037
038        /**
039         * Flag to indicate whether the count is stored at the level of the parent
040         * context, or just local to the current context. Default value is false.
041         */
042        final private boolean useParent;
043
044        final private RepeatContext context;
045
046        /**
047         * Increment the counter.
048         * 
049         * @param delta the amount by which to increment the counter.
050         */
051        final public void increment(int delta) {
052                AtomicInteger count = getCounter();
053                count.addAndGet(delta);
054        }
055        
056        /**
057         * Increment by 1.
058         */
059        final public void increment() {
060                increment(1);
061        }
062
063        /**
064         * Convenience constructor with useParent=false.
065         * @param context the current context.
066         * @param countKey the key to use to store the counter in the context.
067         */
068        public RepeatContextCounter(RepeatContext context, String countKey) {
069                this(context, countKey, false);
070        }
071
072        /**
073         * Construct a new {@link RepeatContextCounter}.
074         * 
075         * @param context the current context.
076         * @param countKey the key to use to store the counter in the context.
077         * @param useParent true if the counter is to be shared between siblings.
078         * The state will be stored in the parent of the context (if it exists)
079         * instead of the context itself.
080         */
081        public RepeatContextCounter(RepeatContext context, String countKey, boolean useParent) {
082
083                super();
084                
085                Assert.notNull(context, "The context must be provided to initialize a counter");
086
087                this.countKey = countKey;
088                this.useParent = useParent;
089
090                RepeatContext parent = context.getParent();
091
092                if (this.useParent && parent != null) {
093                        this.context = parent;
094                }
095                else {
096                        this.context = context;
097                }
098                if (!this.context.hasAttribute(countKey)) {
099                        this.context.setAttribute(countKey, new AtomicInteger());
100                }
101
102        }
103
104        /**
105         * @return the current value of the counter
106         */
107        public int getCount() {
108                return getCounter().intValue();
109        }
110
111        private AtomicInteger getCounter() {
112                return ((AtomicInteger) context.getAttribute(countKey));
113        }
114
115}