001: /*
002: * Copyright 2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.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: * http://www.opensource.org/licenses/ecl1.php
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: package org.kuali.module.labor.util;
017:
018: import java.io.BufferedReader;
019: import java.io.File;
020: import java.io.FileNotFoundException;
021: import java.io.FileReader;
022: import java.io.IOException;
023: import java.util.Iterator;
024: import java.util.NoSuchElementException;
025:
026: import org.apache.log4j.Logger;
027: import org.kuali.module.gl.exception.LoadException;
028: import org.kuali.module.labor.bo.LaborOriginEntry;
029:
030: /**
031: * This class lazy loads the origin entries in a flat file. This implementation uses a limited amount of memory because it does not
032: * pre-load all of the origin entries at once. (Assuming that the Java garbage collector is working well). However, if the code that
033: * uses this iterator stores the contents of this iterator in a big list somewhere, then a lot of memory may be consumed, depending
034: * on the size of the file.
035: */
036: public class LaborOriginEntryFileIterator implements
037: Iterator<LaborOriginEntry> {
038: private static Logger LOG = Logger
039: .getLogger(LaborOriginEntryFileIterator.class);
040:
041: protected LaborOriginEntry nextEntry;
042: protected BufferedReader reader;
043: protected int lineNumber;
044: protected boolean autoCloseReader;
045:
046: /**
047: * Constructs a LaborOriginEntryFileIterator
048: *
049: * @param reader a reader representing flat-file origin entries
050: * @param autoCloseReader whether to automatically close the reader when the end of origin entries has been reached (i.e. when
051: * hasNext() returns false)
052: */
053: public LaborOriginEntryFileIterator(BufferedReader reader) {
054: this (reader, true);
055: }
056:
057: /**
058: * Constructs a LaborOriginEntryFileIterator
059: *
060: * @param reader a reader representing flat-file origin entries
061: * @param autoCloseReader whether to automatically close the reader when the end of origin entries has been reached (i.e. when
062: * hasNext() returns false)
063: */
064: public LaborOriginEntryFileIterator(BufferedReader reader,
065: boolean autoCloseReader) {
066:
067: if (reader == null) {
068: LOG
069: .error("reader is null in the LaborOriginEntryFileIterator!");
070: throw new IllegalArgumentException("reader is null!");
071: }
072: this .reader = reader;
073: nextEntry = null;
074: lineNumber = 0;
075: this .autoCloseReader = autoCloseReader;
076: }
077:
078: /**
079: * Constructs a LaborOriginEntryFileIterator When constructed with this method, the file handle will be automatically closed
080: * when the end of origin entries has been reached (i.e. when hasNext() returns false)
081: *
082: * @param file the file
083: */
084: public LaborOriginEntryFileIterator(File file) {
085: if (file == null) {
086: LOG
087: .error("reader is null in the LaborOriginEntryFileIterator!");
088: throw new IllegalArgumentException("reader is null!");
089: }
090: try {
091: this .reader = new BufferedReader(new FileReader(file));
092: this .autoCloseReader = true;
093: nextEntry = null;
094: lineNumber = 0;
095: } catch (FileNotFoundException e) {
096: LOG.error(
097: "File not found for LaborOriginEntryFileIterator! "
098: + file.getAbsolutePath(), e);
099: throw new RuntimeException(
100: "File not found for LaborOriginEntryFileIterator! "
101: + file.getAbsolutePath());
102: }
103: }
104:
105: /**
106: * @see java.util.Iterator#hasNext()
107: */
108: public boolean hasNext() {
109: if (nextEntry == null) {
110: fetchNextEntry();
111: return nextEntry != null;
112: } else {
113: // we have the next entry loaded
114: return true;
115: }
116: }
117:
118: /**
119: * @see java.util.Iterator#next()
120: */
121: public LaborOriginEntry next() {
122: if (nextEntry != null) {
123: // an entry may have been fetched by hasNext()
124: LaborOriginEntry temp = nextEntry;
125: nextEntry = null;
126: return temp;
127: } else {
128: // maybe next() is called repeatedly w/o calling hasNext. This is a bad idea, but the
129: // interface allows it
130: fetchNextEntry();
131: if (nextEntry == null) {
132: throw new NoSuchElementException();
133: }
134:
135: // clear out the nextEntry to signal that no record has been loaded
136: LaborOriginEntry temp = nextEntry;
137: nextEntry = null;
138: return temp;
139: }
140: }
141:
142: /**
143: * @see java.util.Iterator#remove()
144: */
145: public void remove() {
146: throw new UnsupportedOperationException(
147: "Cannot remove entry from collection");
148: }
149:
150: protected void fetchNextEntry() {
151: try {
152: lineNumber++;
153: String line = reader.readLine();
154: if (line == null) {
155: nextEntry = null;
156: if (autoCloseReader) {
157: reader.close();
158: }
159: } else {
160: nextEntry = new LaborOriginEntry();
161: try {
162: nextEntry.setFromTextFile(line, lineNumber - 1);
163: } catch (LoadException e) {
164: // wipe out the next entry so that the next call to hasNext or next will force a new row to be fetched
165: nextEntry = null;
166:
167: // if there's an LoadException, then we'll just let it propagate up the call stack
168: throw e;
169: }
170: }
171: } catch (IOException e) {
172: LOG
173: .error(
174: "error in the CorrectionDocumentServiceImpl iterator",
175: e);
176: nextEntry = null;
177: throw new RuntimeException(
178: "error retrieving origin entries");
179: }
180: }
181:
182: /**
183: * @see java.lang.Object#finalize()
184: */
185: @Override
186: protected void finalize() throws Throwable {
187: super.finalize();
188: if (autoCloseReader && reader != null) {
189: reader.close();
190: }
191: }
192: }
|