1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.net.ftp;
18 import java.util.List;
19
20 /**
21 * This class implements a bidirectional iterator over an FTPFileList.
22 * Elements may be retrieved one at at time using the hasNext() - next()
23 * syntax familiar from Java 2 collections. Alternatively, entries may
24 * be receieved as an array of any requested number of entries or all of them.
25 *
26 * @author <a href="mailto:scohen@apache.org">Steve Cohen</a>
27 * @version $Id: FTPFileIterator.java 480420 2006-11-29 05:46:24Z bayard $
28 * @see org.apache.commons.net.ftp.FTPFileList
29 * @see org.apache.commons.net.ftp.FTPFileEntryParser
30 * @see org.apache.commons.net.ftp.FTPListParseEngine
31 * @deprecated This class is deprecated as of version 1.2 and will be
32 * removed in version 2.0 - use FTPFileParseEngine instead
33 */
34 public class FTPFileIterator
35 {
36 /**
37 * a vector of strings, each representing a possibly valid ftp file
38 * entry
39 */
40 private List rawlines;
41
42 /**
43 * the parser to which this iterator delegates its parsing duties
44 */
45 private FTPFileEntryParser parser;
46
47 /**
48 * constant shorthand for the situation where the raw listing has not
49 * yet been scanned
50 */
51 private static final int UNINIT = -1;
52
53 /**
54 * constant shorthand for the situation where the raw listing has been
55 * scanned and found to have no valid entry.
56 */
57 private static final int DIREMPTY = -2;
58
59 /**
60 * this iterator's current position within <code>rawlines</code>.
61 */
62 private int itemptr = 0;
63
64 /**
65 * number within <code>rawlines</code> of the first valid file entry.
66 */
67 private int firstGoodEntry = UNINIT;
68
69 /**
70 * "Package-private" constructor. Only the FTPFileList can
71 * create an iterator, using it's iterator() method. The list
72 * will be iterated with the list's default parser.
73 *
74 * @param rawlist the FTPFileList to be iterated
75 */
76 FTPFileIterator (FTPFileList rawlist)
77 {
78 this(rawlist, rawlist.getParser());
79 }
80
81 /**
82 * "Package-private" constructor. Only the FTPFileList can
83 * create an iterator, using it's iterator() method. The list will be
84 * iterated with a supplied parser
85 *
86 * @param rawlist the FTPFileList to be iterated
87 * @param parser the system specific parser for raw FTP entries.
88 */
89 FTPFileIterator (FTPFileList rawlist,
90 FTPFileEntryParser parser)
91 {
92 this.rawlines = rawlist.getLines();
93 this.parser = parser;
94 }
95
96 /**
97 * Delegates to this object's parser member the job of parsing an
98 * entry.
99 *
100 * @param entry A string containing one entry, as determined by the
101 * parser's getNextEntry() method.
102 *
103 * @return an FTPFile object representing this entry or null if it can't be
104 * parsed as a file
105 */
106 private FTPFile parseFTPEntry(String entry)
107 {
108 return this.parser.parseFTPEntry(entry);
109 }
110
111 /**
112 * Skips over any introductory lines and stuff in the listing that does
113 * not represent files, returning the line number of the first entry
114 * that does represent a file.
115 *
116 * @return the line number within <code>rawlines</code> of the first good
117 * entry in the array or DIREMPTY if there are no good entries.
118 */
119 private int getFirstGoodEntry()
120 {
121 FTPFile entry = null;
122 for (int iter = 0; iter < this.rawlines.size(); iter++)
123 {
124 String line = (String) this.rawlines.get(iter);
125 entry = parseFTPEntry(line);
126 if (null != entry)
127 {
128 return iter;
129 }
130 }
131 return DIREMPTY;
132 }
133
134 /**
135 * resets iterator to the beginning of the list.
136 */
137 private void init()
138 {
139 this.itemptr = 0;
140 this.firstGoodEntry = UNINIT;
141 }
142
143 /**
144 * shorthand for an empty return value.
145 */
146 private static final FTPFile[] EMPTY = new FTPFile[0];
147
148 /**
149 * Returns a list of FTPFile objects for ALL files listed in the server's
150 * LIST output.
151 *
152 * @return a list of FTPFile objects for ALL files listed in the server's
153 * LIST output.
154 */
155 public FTPFile[] getFiles()
156 {
157 if (this.itemptr != DIREMPTY)
158 {
159 init();
160 }
161 return getNext(0);
162 }
163
164 /**
165 * Returns an array of at most <code>quantityRequested</code> FTPFile
166 * objects starting at this iterator's current position within its
167 * associated list. If fewer than <code>quantityRequested</code> such
168 * elements are available, the returned array will have a length equal
169 * to the number of entries at and after after the current position.
170 * If no such entries are found, this array will have a length of 0.
171 *
172 * After this method is called the current position is advanced by
173 * either <code>quantityRequested</code> or the number of entries
174 * available after the iterator, whichever is fewer.
175 *
176 * @param quantityRequested
177 * the maximum number of entries we want to get. A 0
178 * passed here is a signal to get ALL the entries.
179 *
180 * @return an array of at most <code>quantityRequested</code> FTPFile
181 * objects starting at the current position of this iterator within its
182 * list and at least the number of elements which exist in the list at
183 * and after its current position.
184 */
185 public FTPFile[] getNext(int quantityRequested)
186 {
187
188 // if we haven't gotten past the initial junk do so.
189 if (this.firstGoodEntry == UNINIT)
190 {
191 this.firstGoodEntry = getFirstGoodEntry();
192 }
193 if (this.firstGoodEntry == DIREMPTY)
194 {
195 return EMPTY;
196 }
197
198 int max = this.rawlines.size() - this.firstGoodEntry;
199
200 // now that we know the maximum we can possibly get,
201 // resolve a 0 request to ask for that many.
202
203 int howMany = (quantityRequested == 0) ? max : quantityRequested;
204 howMany = (howMany + this.itemptr < this.rawlines.size())
205 ? howMany
206 : this.rawlines.size() - this.itemptr;
207
208 FTPFile[] output = new FTPFile[howMany];
209
210 for (int i = 0, e = this.firstGoodEntry + this.itemptr ;
211 i < howMany; i++, e++)
212 {
213 output[i] = parseFTPEntry((String) this.rawlines.get(e));
214 this.itemptr++;
215 }
216 return output;
217 }
218
219 /**
220 * Method for determining whether getNext() will successfully return a
221 * non-null value.
222 *
223 * @return true if there exist any files after the one currently pointed
224 * to by the internal iterator, false otherwise.
225 */
226 public boolean hasNext()
227 {
228 int fge = this.firstGoodEntry;
229 if (fge == DIREMPTY)
230 {
231 //directory previously found empty - return false
232 return false;
233 }
234 else if (fge < 0)
235 {
236 // we haven't scanned the list yet so do it first
237 fge = getFirstGoodEntry();
238 }
239 return fge + this.itemptr < this.rawlines.size();
240 }
241
242 /**
243 * Returns a single parsed FTPFile object corresponding to the raw input
244 * line at this iterator's current position.
245 *
246 * After this method is called the internal iterator is advanced by one
247 * element (unless already at end of list).
248 *
249 * @return a single FTPFile object corresponding to the raw input line
250 * at the position of the internal iterator over the list of raw input
251 * lines maintained by this object or null if no such object exists.
252 */
253 public FTPFile next()
254 {
255 FTPFile[] file = getNext(1);
256 if (file.length > 0)
257 {
258 return file[0];
259 }
260 else
261 {
262 return null;
263 }
264 }
265
266 /**
267 * Returns an array of at most <code>quantityRequested</code> FTPFile
268 * objects starting at the position preceding this iterator's current
269 * position within its associated list. If fewer than
270 * <code>quantityRequested</code> such elements are available, the
271 * returned array will have a length equal to the number of entries after
272 * the iterator. If no such entries are found, this array will have a
273 * length of 0. The entries will be ordered in the same order as the
274 * list, not reversed.
275 *
276 * After this method is called the current position is moved back by
277 * either <code>quantityRequested</code> or the number of entries
278 * available before the current position, whichever is fewer.
279 * @param quantityRequested the maximum number of entries we want to get.
280 * A 0 passed here is a signal to get ALL the entries.
281 * @return an array of at most <code>quantityRequested</code> FTPFile
282 * objects starting at the position preceding the current position of
283 * this iterator within its list and at least the number of elements which
284 * exist in the list prior to its current position.
285 */
286 public FTPFile[] getPrevious(int quantityRequested)
287 {
288 int howMany = quantityRequested;
289 // can't retreat further than we've previously advanced
290 if (howMany > this.itemptr)
291 {
292 howMany = this.itemptr;
293 }
294 FTPFile[] output = new FTPFile[howMany];
295 for (int i = howMany, e = this.firstGoodEntry + this.itemptr; i > 0;)
296 {
297 output[--i] = parseFTPEntry((String) this.rawlines.get(--e));
298 this.itemptr--;
299 }
300 return output;
301 }
302
303 /**
304 * Method for determining whether getPrevious() will successfully return a
305 * non-null value.
306 *
307 * @return true if there exist any files before the one currently pointed
308 * to by the internal iterator, false otherwise.
309 */
310 public boolean hasPrevious()
311 {
312 int fge = this.firstGoodEntry;
313 if (fge == DIREMPTY)
314 {
315 //directory previously found empty - return false
316 return false;
317 }
318 else if (fge < 0)
319 {
320 // we haven't scanned the list yet so do it first
321 fge = getFirstGoodEntry();
322 }
323
324 return this.itemptr > fge;
325 }
326
327 /**
328 * Returns a single parsed FTPFile object corresponding to the raw input
329 * line at the position preceding that of the internal iterator over
330 * the list of raw lines maintained by this object
331 *
332 * After this method is called the internal iterator is retreated by one
333 * element (unless it is already at beginning of list).
334 * @return a single FTPFile object corresponding to the raw input line
335 * at the position immediately preceding that of the internal iterator
336 * over the list of raw input lines maintained by this object.
337 */
338 public FTPFile previous()
339 {
340 FTPFile[] file = getPrevious(1);
341 if (file.length > 0)
342 {
343 return file[0];
344 }
345 else
346 {
347 return null;
348 }
349 }
350 }
351
352 /* Emacs configuration
353 * Local variables: **
354 * mode: java **
355 * c-basic-offset: 4 **
356 * indent-tabs-mode: nil **
357 * End: **
358 */