View Javadoc
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 }