001    /*
002     * Copyright 2001-2005 The Apache Software Foundation
003     *
004     * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
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.apache.commons.net.ftp;
017    import java.util.List;
018    
019    /**
020     * This class implements a bidirectional iterator over an FTPFileList.
021     * Elements may be retrieved one at at time using the hasNext() - next()
022     * syntax familiar from Java 2 collections.  Alternatively, entries may
023     * be receieved as an array of any requested number of entries or all of them.
024     *
025     * @author <a href="mailto:scohen@apache.org">Steve Cohen</a>
026     * @version $Id: FTPFileIterator.java 165675 2005-05-02 20:09:55Z rwinston $
027     * @see org.apache.commons.net.ftp.FTPFileList
028     * @see org.apache.commons.net.ftp.FTPFileEntryParser
029     * @see org.apache.commons.net.ftp.FTPListParseEngine
030     * @deprecated This class is deprecated as of version 1.2 and will be
031     * removed in version 2.0 - use FTPFileParseEngine instead
032     */
033    public class FTPFileIterator
034    {
035        /**
036         * a vector of strings, each representing a possibly valid ftp file
037         * entry
038         */
039        private List rawlines;
040    
041        /**
042         * the parser to which this iterator delegates its parsing duties
043         */
044        private FTPFileEntryParser parser;
045    
046        /**
047         * constant shorthand for the situation where the raw listing has not
048         * yet been scanned
049         */
050        private static final int UNINIT = -1;
051    
052        /**
053         * constant shorthand for the situation where the raw listing has been
054         * scanned and found to have no valid entry.
055         */
056        private static final int DIREMPTY = -2;
057    
058        /**
059         * this iterator's current position within <code>rawlines</code>.
060         */
061        private int itemptr = 0;
062    
063        /**
064         * number within <code>rawlines</code> of the first valid file entry.
065         */
066        private int firstGoodEntry = UNINIT;
067    
068        /**
069         * "Package-private" constructor.  Only the FTPFileList can
070         * create an iterator, using it's iterator() method.  The list
071         * will be iterated with the list's default parser.
072         *
073         * @param rawlist the FTPFileList to be iterated
074         */
075        FTPFileIterator (FTPFileList rawlist)
076        {
077            this(rawlist, rawlist.getParser());
078        }
079    
080        /**
081         * "Package-private" constructor.  Only the FTPFileList can
082         * create an iterator, using it's iterator() method.  The list will be
083         * iterated with a supplied parser
084         *
085         * @param rawlist the FTPFileList to be iterated
086         * @param parser the system specific parser for raw FTP entries.
087         */
088        FTPFileIterator (FTPFileList rawlist,
089                                FTPFileEntryParser parser)
090        {
091            this.rawlines = rawlist.getLines();
092            this.parser = parser;
093        }
094    
095        /**
096         * Delegates to this object's parser member the job of parsing an
097         * entry.
098         *
099         * @param entry  A string containing one entry, as determined by the
100         * parser's getNextEntry() method.
101         *
102         * @return an FTPFile object representing this entry or null if it can't be
103         *         parsed as a file
104         */
105        private FTPFile parseFTPEntry(String entry)
106        {
107            return this.parser.parseFTPEntry(entry);
108        }
109    
110        /**
111         * Skips over any introductory lines and stuff in the listing that does
112         * not represent files, returning the line number of the first entry
113         * that does represent a file.
114         *
115         * @return the line number within <code>rawlines</code> of the first good
116         * entry in the array or DIREMPTY if there are no good entries.
117         */
118        private int getFirstGoodEntry()
119        {
120            FTPFile entry = null;
121            for (int iter = 0; iter < this.rawlines.size(); iter++)
122            {
123                String line = (String) this.rawlines.get(iter);
124                entry = parseFTPEntry(line);
125                if (null != entry)
126                {
127                    return iter;
128                }
129            }
130            return DIREMPTY;
131        }
132    
133        /**
134         * resets iterator to the beginning of the list.
135         */
136        private void init()
137        {
138            this.itemptr = 0;
139            this.firstGoodEntry = UNINIT;
140        }
141    
142        /**
143         * shorthand for an empty return value.
144         */
145        private static final FTPFile[] EMPTY = new FTPFile[0];
146    
147        /**
148         * Returns a list of FTPFile objects for ALL files listed in the server's
149         * LIST output.
150         *
151         * @return a list of FTPFile objects for ALL files listed in the server's
152         * LIST output.
153         */
154        public FTPFile[] getFiles()
155        {
156            if (this.itemptr != DIREMPTY)
157            {
158                init();
159            }
160            return getNext(0);
161        }
162    
163        /**
164         * Returns an array of at most <code>quantityRequested</code> FTPFile
165         * objects starting at this iterator's current position  within its
166         * associated list. If fewer than <code>quantityRequested</code> such
167         * elements are available, the returned array will have a length equal
168         * to the number of entries at and after after the current position.
169         * If no such entries are found, this array will have a length of 0.
170         *
171         * After this method is called the current position is advanced by
172         * either <code>quantityRequested</code> or the number of entries
173         * available after the iterator, whichever is fewer.
174         *
175         * @param quantityRequested
176         * the maximum number of entries we want to get.  A 0
177         * passed here is a signal to get ALL the entries.
178         *
179         * @return an array of at most <code>quantityRequested</code> FTPFile
180         * objects starting at the current position of this iterator within its
181         * list and at least the number of elements which  exist in the list at
182         * and after its current position.
183         */
184        public FTPFile[] getNext(int quantityRequested)
185        {
186    
187            // if we haven't gotten past the initial junk do so.
188            if (this.firstGoodEntry == UNINIT)
189            {
190                this.firstGoodEntry = getFirstGoodEntry();
191            }
192            if (this.firstGoodEntry == DIREMPTY)
193            {
194                return EMPTY;
195            }
196    
197            int max = this.rawlines.size() - this.firstGoodEntry;
198    
199            // now that we know the maximum we can possibly get,
200            // resolve a 0 request to ask for that many.
201    
202            int howMany = (quantityRequested == 0) ? max : quantityRequested;
203            howMany = (howMany + this.itemptr < this.rawlines.size())
204                       ? howMany
205                       : this.rawlines.size() - this.itemptr;
206    
207            FTPFile[] output = new FTPFile[howMany];
208    
209            for (int i = 0, e = this.firstGoodEntry + this.itemptr ;
210                    i < howMany; i++, e++)
211            {
212                output[i] = parseFTPEntry((String) this.rawlines.get(e));
213                this.itemptr++;
214            }
215            return output;
216        }
217    
218        /**
219         * Method for determining whether getNext() will successfully return a
220         * non-null value.
221         *
222         * @return true if there exist any files after the one currently pointed
223         * to by the internal iterator, false otherwise.
224         */
225        public boolean hasNext()
226        {
227            int fge = this.firstGoodEntry;
228            if (fge == DIREMPTY)
229            {
230                //directory previously found empty - return false
231                return false;
232            }
233            else if (fge < 0)
234            {
235                // we haven't scanned the list yet so do it first
236                fge = getFirstGoodEntry();
237            }
238            return fge + this.itemptr < this.rawlines.size();
239        }
240    
241        /**
242         * Returns a single parsed FTPFile object corresponding to the raw input
243         * line at this iterator's current position.
244         *
245         * After this method is called the internal iterator is advanced by one
246         * element (unless already at end of list).
247         *
248         * @return a single FTPFile object corresponding to the raw input line
249         * at the position of the internal iterator over the list of raw input
250         * lines maintained by this object or null if no such object exists.
251         */
252        public FTPFile next()
253        {
254            FTPFile[] file = getNext(1);
255            if (file.length > 0)
256            {
257                return file[0];
258            }
259            else
260            {
261                return null;
262            }
263        }
264    
265        /**
266         * Returns an array of at most <code>quantityRequested</code> FTPFile
267         * objects starting at the position preceding this iterator's current
268         * position within its associated list. If fewer than
269         * <code>quantityRequested</code> such elements are available, the
270         * returned array will have a length equal to the number of entries after
271         * the iterator.  If no such entries are found, this array will have a
272         * length of 0.  The entries will be ordered in the same order as the
273         * list, not reversed.
274         *
275         * After this method is called the current position is moved back by
276         * either <code>quantityRequested</code> or the number of entries
277         * available before the current position, whichever is fewer.
278         * @param quantityRequested the maximum number of entries we want to get.
279         * A 0 passed here is a signal to get ALL the entries.
280         * @return  an array of at most <code>quantityRequested</code> FTPFile
281         * objects starting at the position preceding the current position of
282         * this iterator within its list and at least the number of elements which
283         * exist in the list prior to its current position.
284         */
285        public FTPFile[] getPrevious(int quantityRequested)
286        {
287            int howMany = quantityRequested;
288            // can't retreat further than we've previously advanced
289            if (howMany > this.itemptr)
290            {
291                howMany = this.itemptr;
292            }
293            FTPFile[] output = new FTPFile[howMany];
294            for (int i = howMany, e = this.firstGoodEntry + this.itemptr; i > 0;)
295            {
296                output[--i] = parseFTPEntry((String) this.rawlines.get(--e));
297                this.itemptr--;
298            }
299            return output;
300        }
301    
302        /**
303         * Method for determining whether getPrevious() will successfully return a
304         * non-null value.
305         *
306         * @return true if there exist any files before the one currently pointed
307         * to by the internal iterator, false otherwise.
308         */
309        public boolean hasPrevious()
310        {
311            int fge = this.firstGoodEntry;
312            if (fge == DIREMPTY)
313            {
314                //directory previously found empty - return false
315                return false;
316            }
317            else if (fge < 0)
318            {
319                // we haven't scanned the list yet so do it first
320                fge = getFirstGoodEntry();
321            }
322    
323            return this.itemptr > fge;
324        }
325    
326        /**
327         * Returns a single parsed FTPFile object corresponding to the raw input
328         * line at the position preceding that of the internal iterator over
329         * the list of raw lines maintained by this object
330         *
331         * After this method is called the internal iterator is retreated by one
332         * element (unless it is already at beginning of list).
333         * @return a single FTPFile object corresponding to the raw input line
334         * at the position immediately preceding that of the internal iterator
335         * over the list of raw input lines maintained by this object.
336         */
337        public FTPFile previous()
338        {
339            FTPFile[] file = getPrevious(1);
340            if (file.length > 0)
341            {
342                return file[0];
343            }
344            else
345            {
346                return null;
347            }
348        }
349    }
350    
351    /* Emacs configuration
352     * Local variables:        **
353     * mode:             java  **
354     * c-basic-offset:   4     **
355     * indent-tabs-mode: nil   **
356     * End:                    **
357     */