EMMA Coverage Report (generated Fri Jan 30 13:20:29 EST 2009)
[all classes][org.springframework.batch.item.database]

COVERAGE SUMMARY FOR SOURCE FILE [DrivingQueryItemReader.java]

nameclass, %method, %block, %line, %
DrivingQueryItemReader.java100% (1/1)92%  (11/12)86%  (139/161)86%  (38.6/45)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class DrivingQueryItemReader100% (1/1)92%  (11/12)86%  (139/161)86%  (38.6/45)
DrivingQueryItemReader (List): void 0%   (0/1)0%   (0/22)0%   (0/8)
DrivingQueryItemReader (): void 100% (1/1)100% (15/15)100% (6/6)
afterPropertiesSet (): void 100% (1/1)100% (5/5)100% (2/2)
close (ExecutionContext): void 100% (1/1)100% (16/16)100% (6/6)
getCurrentKey (): Object 100% (1/1)100% (16/16)100% (3/3)
mark (): void 100% (1/1)100% (5/5)100% (2/2)
open (ExecutionContext): void 100% (1/1)100% (30/30)100% (6/6)
read (): Object 100% (1/1)100% (16/16)100% (4/4)
reset (): void 100% (1/1)100% (12/12)100% (3/3)
setKeyCollector (KeyCollector): void 100% (1/1)100% (4/4)100% (2/2)
setSaveState (boolean): void 100% (1/1)100% (4/4)100% (2/2)
update (ExecutionContext): void 100% (1/1)100% (16/16)100% (5/5)

1/*
2 * Copyright 2006-2007 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.springframework.batch.item.database;
17 
18import java.util.Iterator;
19import java.util.List;
20 
21import org.springframework.batch.item.ExecutionContext;
22import org.springframework.batch.item.ItemReader;
23import org.springframework.batch.item.ItemStream;
24import org.springframework.beans.factory.InitializingBean;
25import org.springframework.util.Assert;
26 
27/**
28 * <p>
29 * Convenience class for driving query item readers. Item readers of this type
30 * use a 'driving query' to return back a list of keys. A key can be defined as
31 * anything that can uniquely identify a record so that a more detailed record
32 * can be retrieved for each object. This allows a much smaller footprint to be
33 * stored in memory for processing. The following 'Customer' example table will
34 * help illustrate this:
35 * 
36 * <pre>
37 * CREATE TABLE CUSTOMER (
38 *   ID BIGINT IDENTITY PRIMARY KEY,  
39 *   NAME VARCHAR(45),
40 *   CREDIT FLOAT
41 * );
42 * </pre>
43 * 
44 * <p>
45 * A cursor based solution would simply open up a cursor over ID, NAME, and
46 * CREDIT, and move it from one to the next. This can cause issues on databases
47 * with pessimistic locking strategies. A 'driving query' approach would be to
48 * return only the ID of the customer, then use a separate DAO to retrieve the
49 * name and credit for each ID. This means that there will be a call to a
50 * separate DAO for each call to {@link ItemReader#read()}.
51 * </p>
52 * 
53 * <p>
54 * Mutability: Because this base class cannot guarantee that the keys returned
55 * by subclasses are immutable, care should be taken to not modify a key value.
56 * Doing so would cause issues if a rollback occurs. For example, if a call to
57 * read() is made, and the returned key is modified, a rollback will cause the
58 * next call to read() to return the same object that was originally returned,
59 * since there is no way to create a defensive copy, and re-querying the
60 * database for all the keys would be too resource intensive.
61 * </p>
62 * 
63 * The implementation is *not* thread-safe.
64 * 
65 * 
66 * @author Lucas Ward
67 */
68public class DrivingQueryItemReader implements ItemReader, InitializingBean, ItemStream {
69 
70        private boolean initialized = false;
71 
72        private List keys;
73 
74        private Iterator keysIterator;
75 
76        private int currentIndex = 0;
77 
78        private int lastCommitIndex = 0;
79 
80        private KeyCollector keyCollector;
81 
82        private boolean saveState = false;
83 
84        public DrivingQueryItemReader() {
85 
86        }
87 
88        /**
89         * Initialize the input source with the provided keys list.
90         * 
91         * @param keys
92         */
93        public DrivingQueryItemReader(List keys) {
94                this.keys = keys;
95                this.keysIterator = keys.iterator();
96        }
97 
98        /**
99         * Return the next key in the List.
100         * 
101         * @return next key in the list if not index is not at the last element,
102         * null otherwise.
103         */
104        public Object read() {
105 
106                if (keysIterator.hasNext()) {
107                        currentIndex++;
108                        return keysIterator.next();
109                }
110 
111                return null;
112        }
113 
114        /**
115         * Get the current key. This method will return the same object returned by
116         * the last read() method. If no items have been read yet the ItemReader
117         * yet, then null will be returned.
118         * 
119         * @return the current key.
120         */
121        protected Object getCurrentKey() {
122                if (initialized && currentIndex > 0) {
123                        return keys.get(currentIndex - 1);
124                }
125 
126                return null;
127        }
128 
129        /**
130         * Close the resource by setting the list of keys to null, allowing them to
131         * be garbage collected.
132         */
133        public void close(ExecutionContext executionContext) {
134                initialized = false;
135                currentIndex = 0;
136                lastCommitIndex = 0;
137                keys = null;
138                keysIterator = null;
139        }
140 
141        /**
142         * Initialize the item reader by delegating to the subclass in order to
143         * retrieve the keys.
144         * 
145         * @throws IllegalStateException if the keys list is null or initialized is
146         * true.
147         */
148        public void open(ExecutionContext executionContext) {
149 
150                Assert.state(keys == null && !initialized, "Cannot open an already opened item reader"
151                                + ", call close() first.");
152                keys = keyCollector.retrieveKeys(executionContext);
153                Assert.notNull(keys, "Keys must not be null");
154                keysIterator = keys.listIterator();
155                initialized = true;
156        }
157 
158        public void update(ExecutionContext executionContext) {
159                if (saveState) {
160                        Assert.notNull(executionContext, "ExecutionContext must not be null");
161                        if (getCurrentKey() != null) {
162                                keyCollector.updateContext(getCurrentKey(), executionContext);
163                        }
164                }
165        }
166 
167        public void afterPropertiesSet() throws Exception {
168                Assert.notNull(keyCollector, "The KeyGenerator must not be null.");
169        }
170 
171        /**
172         * Set the key generation strategy to use for this input source.
173         * 
174         * @param keyCollector
175         */
176        public void setKeyCollector(KeyCollector keyCollector) {
177                this.keyCollector = keyCollector;
178        }
179 
180        /**
181         * Mark is supported as long as this {@link ItemStream} is used in a
182         * single-threaded environment. The state backing the mark is a single
183         * counter, keeping track of the current position, so multiple threads
184         * cannot be accommodated.
185         * 
186         * @see org.springframework.batch.item.ItemReader#mark()
187         */
188        public void mark() {
189                lastCommitIndex = currentIndex;
190        }
191 
192        /*
193         * (non-Javadoc)
194         * 
195         * @see
196         * org.springframework.batch.io.support.AbstractTransactionalIoSource#reset
197         * (org.springframework.batch.item.ExecutionContext)
198         */
199        public void reset() {
200                keysIterator = keys.listIterator(lastCommitIndex);
201                currentIndex = lastCommitIndex;
202        }
203 
204        public void setSaveState(boolean saveState) {
205                this.saveState = saveState;
206        }
207}

[all classes][org.springframework.batch.item.database]
EMMA 2.0.5312 (C) Vladimir Roubtsov