1 /*
2 * Copyright 2007 The Kuali Foundation
3 *
4 * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
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 */
16 package org.kuali.ole.gl.batch.service.impl;
17
18 import java.io.BufferedReader;
19 import java.io.File;
20 import java.io.FileNotFoundException;
21 import java.io.FileReader;
22 import java.io.IOException;
23 import java.util.Iterator;
24 import java.util.NoSuchElementException;
25
26 import org.apache.log4j.Logger;
27 import org.kuali.ole.gl.businessobject.OriginEntryFull;
28 import org.kuali.ole.gl.exception.LoadException;
29
30 /**
31 * This class lazy loads the origin entries in a flat file. This implementation uses a limited amount of memory because it does not
32 * pre-load all of the origin entries at once. (Assuming that the Java garbage collector is working well). However, if the code that
33 * uses this iterator stores the contents of this iterator in a big list somewhere, then a lot of memory may be consumed, depending
34 * on the size of the file.
35 */
36 public class OriginEntryFileIterator implements Iterator<OriginEntryFull> {
37 private static Logger LOG = Logger.getLogger(OriginEntryFileIterator.class);
38
39 protected OriginEntryFull nextEntry;
40 protected BufferedReader reader;
41 protected int lineNumber;
42 protected boolean autoCloseReader;
43
44 /**
45 * Constructs a OriginEntryFileIterator
46 *
47 * @param reader a reader representing flat-file origin entries
48 * @param autoCloseReader whether to automatically close the reader when the end of origin entries has been reached (i.e. when
49 * hasNext() returns false)
50 */
51 public OriginEntryFileIterator(BufferedReader reader) {
52 this(reader, true);
53 }
54
55 /**
56 * Constructs a OriginEntryFileIterator
57 *
58 * @param reader a reader representing flat-file origin entries
59 * @param autoCloseReader whether to automatically close the reader when the end of origin entries has been reached (i.e. when
60 * hasNext() returns false)
61 */
62 public OriginEntryFileIterator(BufferedReader reader, boolean autoCloseReader) {
63 if (reader == null) {
64 LOG.error("reader is null in the OriginEntryFileIterator!");
65 throw new IllegalArgumentException("reader is null!");
66 }
67 this.reader = reader;
68 nextEntry = null;
69 lineNumber = 0;
70 this.autoCloseReader = autoCloseReader;
71 }
72
73 /**
74 * Constructs a OriginEntryFileIterator When constructed with this method, the file handle will be automatically closed when the
75 * end of origin entries has been reached (i.e. when hasNext() returns false)
76 *
77 * @param file the file
78 */
79 public OriginEntryFileIterator(File file) {
80 if (file == null) {
81 LOG.error("reader is null in the OriginEntryFileIterator!");
82 throw new IllegalArgumentException("reader is null!");
83 }
84 try {
85 this.reader = new BufferedReader(new FileReader(file));
86 this.autoCloseReader = true;
87 nextEntry = null;
88 lineNumber = 0;
89 }
90 catch (FileNotFoundException e) {
91 LOG.error("File not found for OriginEntryFileIterator! " + file.getAbsolutePath(), e);
92 throw new RuntimeException("File not found for OriginEntryFileIterator! " + file.getAbsolutePath());
93 }
94 }
95
96 /**
97 * @see java.util.Iterator#hasNext()
98 */
99 public boolean hasNext() {
100 if (nextEntry == null) {
101 fetchNextEntry();
102 return nextEntry != null;
103 }
104 else {
105 // we have the next entry loaded
106 return true;
107 }
108 }
109
110 /**
111 * @see java.util.Iterator#next()
112 */
113 public OriginEntryFull next() {
114 if (nextEntry != null) {
115 // an entry may have been fetched by hasNext()
116 OriginEntryFull temp = nextEntry;
117 nextEntry = null;
118 return temp;
119 }
120 else {
121 // maybe next() is called repeatedly w/o calling hasNext. This is a bad idea, but the
122 // interface allows it
123 fetchNextEntry();
124 if (nextEntry == null) {
125 throw new NoSuchElementException();
126 }
127
128 // clear out the nextEntry to signal that no record has been loaded
129 OriginEntryFull temp = nextEntry;
130 nextEntry = null;
131 return temp;
132 }
133 }
134
135 /**
136 * @see java.util.Iterator#remove()
137 */
138 public void remove() {
139 throw new UnsupportedOperationException("Cannot remove entry from collection");
140 }
141
142 /**
143 * This method returns the next line in origin entry file
144 */
145 protected void fetchNextEntry() {
146 try {
147 lineNumber++;
148 String line = reader.readLine();
149 if (line == null) {
150 nextEntry = null;
151 if (autoCloseReader) {
152 reader.close();
153 }
154 }
155 else {
156 nextEntry = new OriginEntryFull();
157 try {
158 nextEntry.setFromTextFileForBatch(line, lineNumber - 1);
159 }
160 catch (LoadException e) {
161 // wipe out the next entry so that the next call to hasNext or next will force a new row to be fetched
162 nextEntry = null;
163
164 // if there's an LoadException, then we'll just let it propagate up the call stack
165 throw e;
166 }
167 }
168 }
169 catch (IOException e) {
170 LOG.error("error in the CorrectionDocumentServiceImpl iterator", e);
171 nextEntry = null;
172 throw new RuntimeException("error retrieving origin entries");
173 }
174 }
175
176 /**
177 * @see java.lang.Object#finalize()
178 */
179 @Override
180 protected void finalize() throws Throwable {
181 super.finalize();
182 if (autoCloseReader && reader != null) {
183 reader.close();
184 }
185 }
186 }