1
2
3
4
5 package org.astrogrid.mySpace.mySpaceUtil;
6
7 import java.io.File;
8 import org.globus.ftp.DataChannelAuthentication;
9 import org.globus.ftp.GridFTPClient;
10 import org.globus.ftp.Session;
11 import org.globus.io.streams.GlobusFileInputStream;
12 import org.globus.io.streams.GlobusFileOutputStream;
13 import org.globus.io.streams.GlobusInputStream;
14 import org.globus.io.streams.GlobusOutputStream;
15 import org.globus.io.streams.HTTPInputStream;
16 import org.globus.util.GlobusURL;
17 import org.gridforum.jgss.ExtendedGSSManager;
18 import org.ietf.jgss.GSSCredential;
19
20 /***
21 * A manager for the download of a single data-set from a URL.
22 *
23 * The client should create a fresh FileTransfer for each transfer.
24 * There is no valid way to reuse one of these object for a second
25 * transfer. The source and destination of the data are set when
26 * the FileTransfer is created.
27 *
28 * The data source may be either a single URL or an array of URLs
29 * that are mirrors of the same data-set. In the latter case,
30 * the FileTransfer will start6 with the URL in element zero of
31 * the array and try URLs in turn until a successful transfer is
32 * achieved or until there are no more URLs. The data destination
33 * is always a file on the local file-system.
34 *
35 * Exceptions while downloading are caught. On catching an
36 * exception for a given URL, the class stores the exception
37 * and goes on to the next URL in the input set. If there are
38 * no more URLs to try, then a FileTransferException is thrown.
39 * After the {@link transfer} completes or fails, the client may
40 * retrieve the exceptions stored for the individual download
41 * attempts by calling {@link getErrors}. The URL, in the set of
42 * mirrors, that actually supplied the data may be retrieved by
43 * calling {@link getChosenUrl}.
44 *
45 * A FileTransfer is not MT-safe.
46 *
47 * @author Jia Yu
48 * @author Guy Rixon
49 */
50 public class FileTransfer {
51
52 /***
53 * The mirrors of the data-source.
54 */
55 private String[] urls;
56
57 /***
58 * The destination for the transferred data.
59 */
60 private File file;
61
62 /***
63 * The mirror that actually gave a valid transfer.
64 */
65 private String urlUsed;
66
67 /***
68 * The error associated with each mirror.
69 * Errors are null where a mirror gave a successful
70 * transfer or where a mirror has not yet been used.
71 */
72 private Exception[] errors;
73
74
75 /***
76 * Creates a FileTransfer with a set of source URLs and
77 * one destination file. The source URLs must be given
78 * in order of preference.
79 *
80 * @param sources the list of mirror URLs from which to transfer.
81 * @param destination the name of the file in which to put the data.
82 */
83 public FileTransfer (final String[] sources, final String destination) {
84 this.urls = sources;
85 this.file = new File(destination);
86 this.errors = new Exception[sources.length];
87 }
88
89
90 /***
91 * Creates a FileTransfer with a single source URL and
92 * one destination file.
93 *
94 * @param source the URL from which to transfer.
95 * @param destination the name of the file in which to put the data.
96 */
97 public FileTransfer (final String source, final String destination) {
98 String[] mirrors = {source};
99 this.urls = mirrors;
100 this.file = new File(destination);
101 this.errors = new Exception[1];
102 }
103
104
105
106 /***
107 * Executes the transfer using the sources and destination
108 * set during construction. The given sources are tried in
109 * order until a transfer succeeds or there are no more sources.
110 *
111 * @throws FileTransferException if all sources fail.
112 */
113 public final void transfer () throws FileTransferException {
114 boolean success = false;
115 for (int i = 0; i < this.urls.length && !success; i++) {
116 try {
117 this.transfer(this.urls[i], this.file);
118 success = true;
119 this.urlUsed = this.urls[i];
120 }
121 catch (Exception e) {
122 this.errors[i] = e;
123 }
124 }
125 if (!success) {
126 throw new FileTransferException(this.file +
127 " was not obtained;" +
128 " all file-transfer protocols failed.");
129 }
130 }
131
132
133 /***
134 * Returns the URL used in the last transfer. Returns null if
135 * no transfer has been made since construction.
136 *
137 * @return the URL used in the transfer.
138 */
139 public final String getChosenUrl () {
140 return this.urlUsed;
141 }
142
143
144 /***
145 * Returns the Exceptions associated with each source URL.
146 * Before the transfer all the exceptions are null. After
147 * the transfer, exceptions are non-null only where a source
148 * URL has been tried and has failed. I.e., the exceptions
149 * are non-null at the start of the returned array and are
150 * null for the successful URL and any URL following it.
151 *
152 * @return array of Exceptions mapped on-for-one to the
153 * array of source URLs given at construction.
154 */
155 public final Exception[] getErrors () {
156 return this.errors;
157 }
158
159
160 /***
161 * Attempts one transfer, using one source URL.
162 *
163 * @param urlStr the URL for the data source.
164 * @param localFile the destination of the data.
165 *
166 * @throws FileTransferException if the transfer does not complete.
167 */
168 private void transfer(final String urlStr, final File localFile)
169 throws FileTransferException {
170
171
172
173 try {
174
175
176
177 GlobusURL url = new GlobusURL(urlStr);
178
179
180 if (url.getProtocol().equalsIgnoreCase("gsiftp") ||
181 url.getProtocol().equalsIgnoreCase("gridftp")) {
182 this.useGridFtp(url, localFile);
183 }
184 else if (url.getProtocol().equalsIgnoreCase("http")) {
185 this.useHttp(url, localFile);
186 }
187 else if (url.getProtocol().equalsIgnoreCase("file")) {
188 this.useFile(url, localFile);
189 }
190 else {
191 System.out.println("FileTransfer.transfer: unknown protocol: "
192 + url.getProtocol());
193 throw new Exception("Unknown protocol: " + url.getProtocol());
194 }
195
196 }
197 catch (Exception e) {
198 String message = "File transfer from "
199 + urlStr
200 + " to "
201 + localFile.getPath()
202 + " failed.";
203 System.out.println(message + " " + e.getMessage());
204 throw new FileTransferException(message, e);
205 }
206 }
207
208
209 /***
210 * Transfers from a GridFTP URL (scheme gsiftp or gridftp).
211 *
212 * @param url the data source.
213 * @param localFile the data destination.
214 *
215 * @throws Exception if the transfer fails.
216 */
217 private void useGridFtp (final GlobusURL url, final File localFile)
218 throws Exception {
219
220 GSSCredential cred = null;
221 GridFTPClient hotClient = null;
222
223 try {
224 hotClient = new GridFTPClient(url.getHost(), url.getPort());
225 System.out.println("FileTransfer.transfer : created a GridFTP client.");
226
227
228 System.out.println("FileTransfer.transfer : creaing credentials");
229 ExtendedGSSManager manager =
230 (ExtendedGSSManager) ExtendedGSSManager.getInstance();
231 cred = manager.createCredential(GSSCredential.INITIATE_AND_ACCEPT);
232
233
234 System.out.println("FileTransfer.transfer : authenticating");
235 hotClient.authenticate(cred);
236
237
238
239
240
241
242 System.out.println("FileTransfer.transfer : setting data channel");
243 hotClient.setDataChannelAuthentication(DataChannelAuthentication.NONE);
244 hotClient.setType(Session.TYPE_IMAGE);
245
246
247 System.out.println("FileTransfer.transfer : getting data");
248 if (!hotClient.exists(url.getPath())) {
249 throw new FileTransferException("the File does not exist");
250 }
251 else {
252 hotClient.get(url.getPath(), localFile);
253 }
254
255 }
256 catch (Exception e) {
257 throw e;
258 }
259 finally {
260 if (hotClient != null) hotClient.close();
261 }
262 }
263
264
265 /***
266 * Attempts a transfer from an HTTP URL.
267 *
268 * @param url the data source.
269 * @param localFile the data destination.
270 *
271 * @throws Exception if the transfer fails
272 */
273 private void useHttp (final GlobusURL url, final File localFile)
274 throws Exception {
275
276 HTTPInputStream in = null;
277 GlobusFileOutputStream out = null;
278
279 try {
280 in = new HTTPInputStream(url.getHost(), url.getPort(), url.getPath());
281 out = new GlobusFileOutputStream(localFile.getPath(), false);
282 byte[] buffer = new byte[2048];
283 int bytes;
284 while (true) {
285 bytes = in.read(buffer);
286 if (bytes == -1) break;
287 out.write(buffer, 0, bytes);
288 out.flush();
289 }
290 }
291 catch (Exception e) {
292 throw e;
293 }
294 finally {
295 if (in != null) in.close();
296 if (out != null) out.close();
297 }
298 }
299
300
301 /***
302 * Attempts a transfer from a file URL.
303 *
304 * @param url the data source.
305 * @param localFile the data destination.
306 *
307 * @throws Exception if the transfer fails.
308 */
309 private void useFile (final GlobusURL url, final File localFile)
310 throws Exception {
311
312 GlobusFileInputStream in = null;
313 GlobusFileOutputStream out = null;
314
315 System.out.println("FileTransfer.transfer : using 'file' protocol.");
316
317 try {
318 in = new GlobusFileInputStream(url.getPath());
319 out = new GlobusFileOutputStream(localFile.getPath(), false);
320 byte[] buffer = new byte[2048];
321 int bytes;
322 while (true) {
323 bytes = in.read(buffer);
324 if (bytes == -1) break;
325 out.write(buffer, 0, bytes);
326 out.flush();
327 }
328 }
329 catch (Exception e) {
330 throw e;
331 }
332 finally {
333 if (in != null) in.close();
334 if (out != null) out.close();
335 }
336 }
337
338 }