1. /*
  2. * Copyright 2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
  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.apache.commons.net.ftp;
  17. import java.io.BufferedReader;
  18. import java.io.IOException;
  19. import java.io.InputStream;
  20. import java.io.InputStreamReader;
  21. import java.util.Iterator;
  22. import java.util.LinkedList;
  23. import java.util.List;
  24. import java.util.ListIterator;
  25. /**
  26. * This class handles the entire process of parsing a listing of
  27. * file entries from the server.
  28. * <p>
  29. * This object defines a two-part parsing mechanism.
  30. * <p>
  31. * The first part is comprised of reading the raw input into an internal
  32. * list of strings. Every item in this list corresponds to an actual
  33. * file. All extraneous matter emitted by the server will have been
  34. * removed by the end of this phase. This is accomplished in conjunction
  35. * with the FTPFileEntryParser associated with this engine, by calling
  36. * its methods <code>readNextEntry()</code> - which handles the issue of
  37. * what delimits one entry from another, usually but not always a line
  38. * feed and <code>preParse()</code> - which handles removal of
  39. * extraneous matter such as the preliminary lines of a listing, removal
  40. * of duplicates on versioning systems, etc.
  41. * <p>
  42. * The second part is composed of the actual parsing, again in conjunction
  43. * with the particular parser used by this engine. This is controlled
  44. * by an iterator over the internal list of strings. This may be done
  45. * either in block mode, by calling the <code>getNext()</code> and
  46. * <code>getPrevious()</code> methods to provide "paged" output of less
  47. * than the whole list at one time, or by calling the
  48. * <code>getFiles()</code> method to return the entire list.
  49. * <p>
  50. * Examples:
  51. * <p>
  52. * Paged access:
  53. * <pre>
  54. * FTPClient f=FTPClient();
  55. * f.connect(server);
  56. * f.login(username, password);
  57. * FTPListParseEngine engine = f.initiateListParsing(directory);
  58. *
  59. * while (engine.hasNext()) {
  60. * FTPFile[] files = engine.getNext(25); // "page size" you want
  61. * //do whatever you want with these files, display them, etc.
  62. * //expensive FTPFile objects not created until needed.
  63. * }
  64. * </pre>
  65. * <p>
  66. * For unpaged access, simply use FTPClient.listFiles(). That method
  67. * uses this class transparently.
  68. * @version $Id: FTPListParseEngine.java,v 1.7 2004/04/22 00:48:07 scohen Exp $
  69. */
  70. public class FTPListParseEngine {
  71. private List entries = new LinkedList();
  72. private ListIterator _internalIterator = entries.listIterator();
  73. FTPFileEntryParser parser = null;
  74. public FTPListParseEngine(FTPFileEntryParser parser) {
  75. this.parser = parser;
  76. }
  77. /**
  78. * handle the iniitial reading and preparsing of the list returned by
  79. * the server. After this method has completed, this object will contain
  80. * a list of unparsed entries (Strings) each referring to a unique file
  81. * on the server.
  82. *
  83. * @param stream input stream provided by the server socket.
  84. *
  85. * @exception IOException
  86. * thrown on any failure to read from the sever.
  87. */
  88. public void readServerList(InputStream stream)
  89. throws IOException
  90. {
  91. this.entries = new LinkedList();
  92. readStream(stream);
  93. this.parser.preParse(this.entries);
  94. resetIterator();
  95. }
  96. /**
  97. * Internal method for reading the input into the <code>entries</code> list.
  98. * After this method has completed, <code>entries</code> will contain a
  99. * collection of entries (as defined by
  100. * <code>FTPFileEntryParser.readNextEntry()</code>), but this may contain
  101. * various non-entry preliminary lines from the server output, duplicates,
  102. * and other data that will not be part of the final listing.
  103. *
  104. * @param stream The socket stream on which the input will be read.
  105. *
  106. * @exception IOException
  107. * thrown on any failure to read the stream
  108. */
  109. private void readStream(InputStream stream) throws IOException
  110. {
  111. BufferedReader reader =
  112. new BufferedReader(new InputStreamReader(stream));
  113. String line = this.parser.readNextEntry(reader);
  114. while (line != null)
  115. {
  116. this.entries.add(line);
  117. line = this.parser.readNextEntry(reader);
  118. }
  119. reader.close();
  120. }
  121. /**
  122. * Returns an array of at most <code>quantityRequested</code> FTPFile
  123. * objects starting at this object's internal iterator's current position.
  124. * If fewer than <code>quantityRequested</code> such
  125. * elements are available, the returned array will have a length equal
  126. * to the number of entries at and after after the current position.
  127. * If no such entries are found, this array will have a length of 0.
  128. *
  129. * After this method is called this object's internal iterator is advanced
  130. * by a number of positions equal to the size of the array returned.
  131. *
  132. * @param quantityRequested
  133. * the maximum number of entries we want to get.
  134. *
  135. * @return an array of at most <code>quantityRequested</code> FTPFile
  136. * objects starting at the current position of this iterator within its
  137. * list and at least the number of elements which exist in the list at
  138. * and after its current position.
  139. */
  140. public FTPFile[] getNext(int quantityRequested) {
  141. List tmpResults = new LinkedList();
  142. int count = quantityRequested;
  143. while (count > 0 && this._internalIterator.hasNext()) {
  144. String entry = (String) this._internalIterator.next();
  145. FTPFile temp = this.parser.parseFTPEntry(entry);
  146. tmpResults.add(temp);
  147. count--;
  148. }
  149. return (FTPFile[]) tmpResults.toArray(new FTPFile[0]);
  150. }
  151. /**
  152. * Returns an array of at most <code>quantityRequested</code> FTPFile
  153. * objects starting at this object's internal iterator's current position,
  154. * and working back toward the beginning.
  155. *
  156. * If fewer than <code>quantityRequested</code> such
  157. * elements are available, the returned array will have a length equal
  158. * to the number of entries at and after after the current position.
  159. * If no such entries are found, this array will have a length of 0.
  160. *
  161. * After this method is called this object's internal iterator is moved
  162. * back by a number of positions equal to the size of the array returned.
  163. *
  164. * @param quantityRequested
  165. * the maximum number of entries we want to get.
  166. *
  167. * @return an array of at most <code>quantityRequested</code> FTPFile
  168. * objects starting at the current position of this iterator within its
  169. * list and at least the number of elements which exist in the list at
  170. * and after its current position. This array will be in the same order
  171. * as the underlying list (not reversed).
  172. */
  173. public FTPFile[] getPrevious(int quantityRequested) {
  174. List tmpResults = new LinkedList();
  175. int count = quantityRequested;
  176. while (count > 0 && this._internalIterator.hasPrevious()) {
  177. String entry = (String) this._internalIterator.previous();
  178. FTPFile temp = this.parser.parseFTPEntry(entry);
  179. tmpResults.add(0,temp);
  180. count--;
  181. }
  182. return (FTPFile[]) tmpResults.toArray(new FTPFile[0]);
  183. }
  184. /**
  185. * Returns an array of FTPFile objects containing the whole list of
  186. * files returned by the server as read by this object's parser.
  187. *
  188. * @return an array of FTPFile objects containing the whole list of
  189. * files returned by the server as read by this object's parser.
  190. * @exception IOException
  191. */
  192. public FTPFile[] getFiles()
  193. throws IOException
  194. {
  195. List tmpResults = new LinkedList();
  196. Iterator iter = this.entries.iterator();
  197. while (iter.hasNext()) {
  198. String entry = (String) iter.next();
  199. FTPFile temp = this.parser.parseFTPEntry(entry);
  200. tmpResults.add(temp);
  201. }
  202. return (FTPFile[]) tmpResults.toArray(new FTPFile[0]);
  203. }
  204. /**
  205. * convenience method to allow clients to know whether this object's
  206. * internal iterator's current position is at the end of the list.
  207. *
  208. * @return true if internal iterator is not at end of list, false
  209. * otherwise.
  210. */
  211. public boolean hasNext() {
  212. return _internalIterator.hasNext();
  213. }
  214. /**
  215. * convenience method to allow clients to know whether this object's
  216. * internal iterator's current position is at the beginning of the list.
  217. *
  218. * @return true if internal iterator is not at beginning of list, false
  219. * otherwise.
  220. */
  221. public boolean hasPrevious() {
  222. return _internalIterator.hasPrevious();
  223. }
  224. /**
  225. * resets this object's internal iterator to the beginning of the list.
  226. */
  227. public void resetIterator() {
  228. this._internalIterator = this.entries.listIterator();
  229. }
  230. }