View Javadoc

1   // ActiveGetter.java
2   // $Id: ActiveGetter.java,v 1.6 2007/02/21 00:07:50 sjardine Exp $
3   //
4   // Copyright 2000, Joe Phillips <jaiger@innovationsw.com>
5   // Copyright 2001, 2002 Innovation Software Group, LLC - http://www.innovationsw.com
6   //
7   // This library is free software; you can redistribute it and/or
8   // modify it under the terms of the GNU Library General Public
9   // License as published by the Free Software Foundation; either
10  // version 2 of the License, or (at your option) any later version.
11  //
12  // This library is distributed in the hope that it will be useful,
13  // but WITHOUT ANY WARRANTY; without even the implied warranty of
14  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  // Library General Public License for more details.
16  //
17  // You should have received a copy of the GNU Library General Public
18  // License along with this library; if not, write to the Free
19  // Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  //
21  // TODO implement compressed streams
22  
23  package gnu.inet.ftp;
24  
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.io.InterruptedIOException;
28  import java.io.OutputStream;
29  import java.net.InetAddress;
30  import java.net.ServerSocket;
31  import java.net.Socket;
32  import java.net.SocketException;
33  import java.util.zip.InflaterInputStream;
34  
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  
38  /***
39   * This class implements an FTP-style data connection server thread for GETing
40   * files/data non-passively.
41   * <P>
42   * This class is used internally to the FtpClient class.
43   */
44  public class ActiveGetter extends Getter {
45  
46      private final static Log log = LogFactory.getLog(ActiveGetter.class);
47  
48      private InetAddress address;
49  
50      private int port;
51  
52      private ServerSocket server;
53  
54      private int timeout;
55  
56      /***
57       * Create a new ActiveGetter with the given OutputStream for data output.
58       * 
59       * @throws IOException
60       *                 an IO error occurred with the ServerSocket
61       */
62      public ActiveGetter(OutputStream out) throws IOException {
63  	super();
64  
65  	// create server socket
66  	this.server = new ServerSocket(0);
67  	this.timeout = 30 * 1000; // 30s timeout
68  	// store the port that the server is listening on
69  	this.port = server.getLocalPort();
70  	this.address = this.server.getInetAddress();
71  
72  	this.ostream = out;
73      }// end of default constructor
74  
75      //
76      // public methods
77      //
78  
79      /***
80       * get the local port this ActiveGetter is listening on
81       * 
82       * @return port number
83       */
84      public synchronized int getPort() {
85  	return port;
86      }// getPort
87  
88      /***
89       * get the local IP address that this ActiveGetter is listening on
90       * 
91       * @return server socket IP address
92       */
93      public InetAddress getInetAddress() {
94  	return address;
95      }// getInetAddress
96  
97      /***
98       * Set the connection timeout in milliseconds. This method must be called
99       * before start()/run() for the value to take affect.
100      * 
101      * @param milliseconds
102      *                the socket timeout value in milliseconds
103      */
104     public void setTimeout(int milliseconds) {
105 	timeout = milliseconds;
106     }// setTimeout
107 
108     /***
109      * get data from server using given parameters.
110      */
111     public void run() {
112 	boolean signalClosure = false;
113 	Socket sock = null;
114 	InputStream istream = null;
115 	long amount = 0;
116 	long buffer_size = 0;
117 	byte buffer[] = new byte[BUFFER_SIZE];
118 	// this.cancelled= false; // reset cancelled flag
119 
120 	try {
121 	    // wait for connection
122 	    server.setSoTimeout(timeout); // can only wait so long
123 	    if (cancelled)
124 		throw new InterruptedIOException("Transfer cancelled"); // small
125 	    // race
126 	    // condition
127 	    // here
128 	    sock = server.accept();
129 	    signalConnectionOpened(new ConnectionEvent(sock.getInetAddress(),
130 		    sock.getPort()));
131 	    signalClosure = true;
132 	    signalTransferStarted();
133 
134 	    try {
135 
136 		// handle different type settings
137 		switch (type) {
138 		case FtpClientProtocol.TYPE_ASCII:
139 		    istream = new AsciiInputStream(sock.getInputStream());
140 		    break;
141 		default:
142 		    istream = sock.getInputStream();
143 		    break;
144 		}// switch
145 
146 		// handle different mode settings
147 		switch (mode) {
148 		case FtpClientProtocol.MODE_ZLIB:
149 		    istream = new InflaterInputStream(istream);
150 		    break;
151 		case FtpClientProtocol.MODE_STREAM:
152 		default:
153 		    break;
154 		}// switch
155 
156 		int len;
157 		while (!cancelled && ((len = istream.read(buffer)) > 0)) {
158 		    ostream.write(buffer, 0, len);
159 		    amount += len;
160 		    buffer_size += len;
161 		    if (buffer_size >= BUFFER_SIZE) {
162 			buffer_size = buffer_size % BUFFER_SIZE;
163 			signalTransfered(amount);
164 		    }
165 		    yield();
166 		}
167 
168 		ostream.flush();
169 	    } catch (InterruptedIOException iioe) {
170 		if (!cancelled) {
171 		    log.error(iioe.getMessage(), iioe);
172 		}
173 	    } catch (Exception e) {
174 		log.error(e.getMessage(), e);
175 	    } finally {
176 		log.debug("Closing inputstream");
177 		if (istream != null) {
178 		    istream.close();
179 		}
180 		if (!sock.isClosed()) {
181 		    try {
182 			log.debug("Setting socket to 0 lingering");
183 			sock.setSoLinger(true, 0);
184 			sock.close();
185 		    } catch (SocketException e) {
186 			// Don't care.
187 		    }
188 		}
189 		signalTransferCompleted();
190 	    }
191 	} catch (InterruptedIOException eiioe) {
192 	    signalConnectionFailed(eiioe);
193 	    if (!cancelled) {
194 		log.error(eiioe.getMessage(), eiioe);
195 	    }
196 	} catch (Exception ee) {
197 	    signalConnectionFailed(ee);
198 	    log.error(ee.getMessage(), ee);
199 	} finally {
200 	    try {
201 		log.debug("Closing server socket");
202 		server.close();
203 	    } catch (IOException ex) {
204 		// don't care
205 	    }
206 	}
207 
208 	if (signalClosure == true && sock != null) {
209 	    signalConnectionClosed(new ConnectionEvent(sock.getInetAddress(),
210 		    sock.getPort()));
211 	}
212     }// run
213 
214 }// ActiveGetter
215 
216 // ActiveGetter.java