1 package fr.in2p3.jsaga.adaptor.data;
2
3 import fr.in2p3.jsaga.adaptor.base.defaults.Default;
4 import fr.in2p3.jsaga.adaptor.base.usage.Usage;
5 import fr.in2p3.jsaga.adaptor.data.optimise.DataCopy;
6 import fr.in2p3.jsaga.adaptor.data.optimise.DataCopyMonitor;
7 import fr.in2p3.jsaga.adaptor.data.optimise.DataRename;
8 import fr.in2p3.jsaga.adaptor.data.read.FileAttributes;
9 import fr.in2p3.jsaga.adaptor.data.read.FileReaderStreamFactory;
10 import fr.in2p3.jsaga.adaptor.data.write.FileWriterStreamFactory;
11 import fr.in2p3.jsaga.adaptor.security.SecurityCredential;
12 import fr.in2p3.jsaga.adaptor.security.impl.GSSCredentialSecurityCredential;
13
14 import org.apache.log4j.Logger;
15 import org.globus.common.ChainedIOException;
16 import org.globus.ftp.DataChannelAuthentication;
17 import org.globus.ftp.FeatureList;
18 import org.globus.ftp.GridFTPSession;
19 import org.globus.ftp.exception.ClientException;
20 import org.globus.ftp.exception.ServerException;
21 import org.globus.ftp.exception.UnexpectedReplyCodeException;
22 import org.globus.gsi.gssapi.GlobusGSSException;
23 import org.globus.gsi.gssapi.auth.HostAuthorization;
24 import org.ietf.jgss.GSSCredential;
25 import org.ogf.saga.error.*;
26
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.OutputStream;
30 import java.util.Map;
31
32
33
34
35
36
37
38
39
40
41
42
43
44 public abstract class GsiftpDataAdaptorAbstract implements DataCopy, DataRename, FileReaderStreamFactory, FileWriterStreamFactory
45 {
46 protected static final String TCP_BUFFER_SIZE = "TCPBufferSize";
47 protected int m_TCPBufferSize;
48 protected boolean m_DataChannelAuthentication;
49
50 protected GSSCredential m_credential;
51 protected GsiftpClient m_client;
52
53 public abstract String getType();
54 public abstract Usage getUsage();
55 public abstract Default[] getDefaults(Map attributes) throws IncorrectStateException;
56 public abstract FileAttributes getAttributes(String absolutePath, String additionalArgs) throws PermissionDeniedException, DoesNotExistException, TimeoutException, NoSuccessException;
57 public abstract FileAttributes[] listAttributes(String absolutePath, String additionalArgs) throws PermissionDeniedException, DoesNotExistException, TimeoutException, NoSuccessException;
58
59 public Class[] getSupportedSecurityCredentialClasses() {
60 return new Class[]{GSSCredentialSecurityCredential.class};
61 }
62
63 public void setSecurityCredential(SecurityCredential credential) {
64 m_credential = ((GSSCredentialSecurityCredential) credential).getGSSCredential();
65 }
66
67 public int getDefaultPort() {
68 return 2811;
69 }
70
71 public void connect(String userInfo, String host, int port, String basePath, Map attributes) throws AuthenticationFailedException, AuthorizationFailedException, BadParameterException, TimeoutException, NoSuccessException {
72
73 if (attributes!=null && attributes.containsKey(TCP_BUFFER_SIZE)) {
74 try {
75 m_TCPBufferSize = Integer.parseInt((String) attributes.get(TCP_BUFFER_SIZE));
76 } catch (NumberFormatException e) {
77 throw new BadParameterException("Bad value for configuration attribute: "+TCP_BUFFER_SIZE, e);
78 }
79 }
80 m_DataChannelAuthentication = false;
81
82
83 m_client = createConnection(m_credential, host, port, m_TCPBufferSize, m_DataChannelAuthentication);
84 }
85
86 public void disconnect() throws NoSuccessException {
87 try {
88 m_client.disconnect();
89 } catch (Exception e) {
90 throw new NoSuccessException(e);
91 }
92 }
93
94 public boolean exists(String absolutePath, String additionalArgs) throws PermissionDeniedException, TimeoutException, NoSuccessException {
95 try {
96 boolean exists = m_client.exists(absolutePath);
97
98
99 if (exists) {
100 return true;
101 } else {
102 try {
103 this.getAttributes(absolutePath, additionalArgs);
104 return true;
105 } catch (DoesNotExistException e) {
106 return false;
107 }
108 }
109 } catch (Exception e) {
110 try {
111 throw rethrowException(e);
112 } catch (DoesNotExistException doesNotExist) {
113 throw new NoSuccessException(e);
114 } catch (BadParameterException badParameter) {
115 throw new NoSuccessException("Unexpected exception", e);
116 }
117 }
118 }
119
120 public InputStream getInputStream(String absolutePath, String additionalArgs) throws PermissionDeniedException, BadParameterException, DoesNotExistException, TimeoutException, NoSuccessException {
121
122 try {
123 return new GsiftpInputStream(m_client, absolutePath);
124 } catch (Exception e) {
125 throw rethrowException(e);
126 }
127 }
128
129 protected void checkExists(String absolutePath) throws AlreadyExistsException, NoSuccessException, PermissionDeniedException, BadParameterException, TimeoutException, ParentDoesNotExist {
130 boolean exists;
131 try {
132 exists = m_client.exists(absolutePath);
133 } catch (Exception e) {
134 try {
135 throw rethrowExceptionFull(e);
136 } catch (DoesNotExistException e1) {
137 throw new ParentDoesNotExist(e);
138 }
139 }
140 if (exists) {
141 throw new AlreadyExistsException("File already exists: "+absolutePath);
142 }
143 }
144
145 public OutputStream getOutputStream(String parentAbsolutePath, String fileName, boolean exclusive, boolean append, String additionalArgs) throws PermissionDeniedException, BadParameterException, AlreadyExistsException, ParentDoesNotExist, TimeoutException, NoSuccessException {
146
147
148 if (append && !m_client.isAppendSupported())
149 throw new BadParameterException("'Append' flag will probably not work on the remote server");
150
151 String absolutePath = parentAbsolutePath+"/"+fileName;
152
153
154 if (exclusive) {
155 checkExists(absolutePath);
156 }
157
158
159 try {
160 return new GsiftpOutputStream(m_credential, m_client, absolutePath, append);
161 } catch (Exception e) {
162 try {
163 throw rethrowExceptionFull(e);
164 } catch (DoesNotExistException e2) {
165 throw new ParentDoesNotExist(e);
166 }
167 }
168 }
169
170 public void copy(String sourceAbsolutePath,
171 String targetHost,
172 int targetPort,
173 String targetAbsolutePath,
174 boolean overwrite,
175 String additionalArgs,
176 DataCopyMonitor progressMonitor)
177 throws AuthenticationFailedException, AuthorizationFailedException, PermissionDeniedException, BadParameterException, AlreadyExistsException, DoesNotExistException, ParentDoesNotExist, TimeoutException, NoSuccessException {
178
179 GsiftpDataAdaptorAbstract targetAdaptor;
180 String type = this.getType();
181 if ("gsiftp-v1".equals(type)) targetAdaptor = new Gsiftp1DataAdaptor();
182 else if ("gsiftp-v2".equals(type)) targetAdaptor = new Gsiftp2DataAdaptor();
183 else if ("gsiftp-win".equals(type)) targetAdaptor = new GsiftpWinDataAdaptor();
184 else if ("gsiftp-dcache".equals(type)) targetAdaptor = new GsiftpDCacheDataAdaptor();
185 else if ("gsiftp-dpm".equals(type)) throw new NoSuccessException("Third-party transfer not implemented for protocol: "+type);
186 else throw new NoSuccessException("[INTERNAL ERROR] Unexpected protocol: "+type);
187 targetAdaptor.m_credential = m_credential;
188 targetAdaptor.connect(null, targetHost, targetPort, null, null);
189
190 try {
191
192 if (overwrite && targetAdaptor.exists(targetAbsolutePath, additionalArgs)) {
193 try {
194 targetAdaptor.m_client.deleteFile(targetAbsolutePath);
195 } catch (Exception e) {
196 throw new PermissionDeniedException("Failed to overwrite target file", e);
197 }
198 }
199
200
201 if (!overwrite && targetAdaptor.exists(targetAbsolutePath, additionalArgs)) {
202 throw new AlreadyExistsException("File already exists");
203 }
204
205
206 m_client.setDataChannelAuthentication(DataChannelAuthentication.NONE);
207 targetAdaptor.m_client.setDataChannelAuthentication(DataChannelAuthentication.NONE);
208
209
210 m_client.setType(GridFTPSession.TYPE_IMAGE);
211 targetAdaptor.m_client.setType(GridFTPSession.TYPE_IMAGE);
212 m_client.setMode(GridFTPSession.MODE_EBLOCK);
213 targetAdaptor.m_client.setMode(GridFTPSession.MODE_EBLOCK);
214 m_client.setStripedActive(targetAdaptor.m_client.setStripedPassive());
215 if (progressMonitor == null) {
216 m_client.extendedTransfer(sourceAbsolutePath, targetAdaptor.m_client, targetAbsolutePath, null);
217 } else {
218 m_client.extendedTransfer(sourceAbsolutePath, targetAdaptor.m_client, targetAbsolutePath, new CopyListener(progressMonitor));
219 }
220 } catch (Exception e) {
221 throw rethrowExceptionFull(e);
222 } finally {
223
224 targetAdaptor.disconnect();
225 }
226 }
227
228 public void copyFrom(String sourceHost, int sourcePort, String sourceAbsolutePath, String targetAbsolutePath, boolean overwrite, String additionalArgs) throws AuthenticationFailedException, AuthorizationFailedException, PermissionDeniedException, BadParameterException, AlreadyExistsException, DoesNotExistException, TimeoutException, NoSuccessException {
229
230 GsiftpDataAdaptorAbstract sourceAdaptor = new Gsiftp1DataAdaptor();
231 sourceAdaptor.m_credential = m_credential;
232 sourceAdaptor.connect(null, sourceHost, sourcePort, null, null);
233
234 try {
235
236 if (overwrite && this.exists(targetAbsolutePath, additionalArgs)) {
237 try {
238 m_client.deleteFile(targetAbsolutePath);
239 } catch (Exception e) {
240 throw new PermissionDeniedException("Failed to overwrite target file", e);
241 }
242 }
243
244
245 if (!overwrite && this.exists(targetAbsolutePath, additionalArgs)) {
246 throw new AlreadyExistsException("File already exists");
247 }
248
249
250 sourceAdaptor.m_client.setDataChannelAuthentication(DataChannelAuthentication.NONE);
251 m_client.setDataChannelAuthentication(DataChannelAuthentication.NONE);
252
253
254 sourceAdaptor.m_client.setType(GridFTPSession.TYPE_IMAGE);
255 m_client.setType(GridFTPSession.TYPE_IMAGE);
256 sourceAdaptor.m_client.setMode(GridFTPSession.MODE_EBLOCK);
257 m_client.setMode(GridFTPSession.MODE_EBLOCK);
258 sourceAdaptor.m_client.setStripedActive(m_client.setStripedPassive());
259 sourceAdaptor.m_client.extendedTransfer(sourceAbsolutePath, m_client, targetAbsolutePath, null);
260 } catch (Exception e) {
261 throw rethrowExceptionFull(e);
262 } finally {
263
264 sourceAdaptor.disconnect();
265 }
266 }
267
268 public void rename(String sourceAbsolutePath, String targetAbsolutePath, boolean overwrite, String additionalArgs) throws PermissionDeniedException, BadParameterException, DoesNotExistException, AlreadyExistsException, TimeoutException, NoSuccessException {
269 try {
270 m_client.rename(sourceAbsolutePath, targetAbsolutePath);
271 } catch (Exception e) {
272 throw rethrowExceptionFull(e);
273 }
274 }
275
276 public void removeFile(String parentAbsolutePath, String fileName, String additionalArgs) throws PermissionDeniedException, BadParameterException, DoesNotExistException, TimeoutException, NoSuccessException {
277 try {
278 m_client.deleteFile(parentAbsolutePath+"/"+fileName);
279 } catch (Exception e) {
280 throw rethrowException(e);
281 }
282 }
283
284 public void makeDir(String parentAbsolutePath, String directoryName, String additionalArgs) throws PermissionDeniedException, BadParameterException, AlreadyExistsException, ParentDoesNotExist, TimeoutException, NoSuccessException {
285 try {
286 m_client.makeDir(parentAbsolutePath+"/"+directoryName);
287 } catch (Exception e) {
288 try {
289 throw rethrowExceptionFull(e);
290 } catch (DoesNotExistException e2) {
291 throw new ParentDoesNotExist(e);
292 }
293 }
294 }
295
296 public void removeDir(String parentAbsolutePath, String directoryName, String additionalArgs) throws PermissionDeniedException, BadParameterException, DoesNotExistException, TimeoutException, NoSuccessException {
297 try {
298 m_client.deleteDir(parentAbsolutePath+"/"+directoryName);
299 } catch (Exception e) {
300 throw rethrowException(e);
301 }
302 }
303
304 public static GsiftpClient createConnection(GSSCredential cred, String host, int port, int tcpBufferSize, boolean reqDCAU) throws AuthenticationFailedException, AuthorizationFailedException, TimeoutException, NoSuccessException {
305 Logger.getLogger(GsiftpDataAdaptorAbstract.class).info("Connecting to Gsiftp service at: " + host + ":" + port + "...");
306 GsiftpClient client;
307 try {
308 client = new GsiftpClient(host, port);
309 } catch (IOException e) {
310 if (e.getMessage()!=null && e.getMessage().indexOf("Authentication") > -1) {
311 throw new AuthenticationFailedException(e);
312 } else {
313 throw new TimeoutException(e);
314 }
315 } catch (ServerException e) {
316 switch(e.getCode()) {
317 case ServerException.SERVER_REFUSED:
318 try {
319 throw e.getRootCause();
320 } catch (UnexpectedReplyCodeException unexpectedReplyCode) {
321 switch(unexpectedReplyCode.getReply().getCode()) {
322 case 530:
323 throw new AuthorizationFailedException(unexpectedReplyCode);
324 default:
325 throw new NoSuccessException(unexpectedReplyCode);
326 }
327 } catch (Exception e1) {
328 throw new NoSuccessException(e1);
329 }
330 default:
331 throw new NoSuccessException(e);
332 }
333 }
334
335 Logger.getLogger(GsiftpDataAdaptorAbstract.class).info(client.getWelcome());
336
337 try {
338 client.setAuthorization(HostAuthorization.getInstance());
339 client.authenticate(cred);
340
341
342 if (tcpBufferSize > 0) {
343 client.setTCPBufferSize(tcpBufferSize);
344 }
345
346
347 if (client.isFeatureSupported(FeatureList.DCAU)) {
348 if (! reqDCAU) {
349 client.setDataChannelAuthentication(DataChannelAuthentication.NONE);
350 }
351 } else {
352 client.setLocalNoDataChannelAuthentication();
353 }
354
355 return client;
356 } catch (ChainedIOException e) {
357 disconnectClient(client);
358 try {
359 throw e.getCause();
360 } catch (GlobusGSSException gssException) {
361 throw new AuthenticationFailedException(gssException);
362 } catch (Throwable throwable) {
363 throw new TimeoutException(throwable);
364 }
365 } catch (IOException e) {
366 disconnectClient(client);
367 if (e.getMessage()!=null && e.getMessage().indexOf("Authentication") > -1) {
368 throw new AuthenticationFailedException(e);
369 } else {
370 throw new TimeoutException(e);
371 }
372 } catch (ServerException e) {
373 disconnectClient(client);
374 switch(e.getCode()) {
375 case ServerException.SERVER_REFUSED:
376 try {
377 throw e.getRootCause();
378 } catch (UnexpectedReplyCodeException unexpectedReplyCode) {
379 switch(unexpectedReplyCode.getReply().getCode()) {
380 case 530:
381 throw new AuthorizationFailedException(unexpectedReplyCode);
382 default:
383 throw new NoSuccessException(unexpectedReplyCode);
384 }
385 } catch (Exception e1) {
386 throw new NoSuccessException(e1);
387 }
388 default:
389 throw new NoSuccessException(e);
390 }
391 }
392 }
393
394 private static void disconnectClient(GsiftpClient client) {
395 try {
396 client.disconnect();
397 } catch (ServerException ex) {
398 Logger.getLogger(GsiftpDataAdaptorAbstract.class).warn("Error disconnecting", ex);
399 } catch (IOException ex) {
400 Logger.getLogger(GsiftpDataAdaptorAbstract.class).warn("Error disconnecting", ex);
401 }
402 }
403
404 protected NoSuccessException rethrowException(Exception exception) throws PermissionDeniedException, BadParameterException, DoesNotExistException, TimeoutException, NoSuccessException {
405 try {
406 throw rethrowExceptionFull(exception);
407 } catch (AlreadyExistsException e) {
408 throw new NoSuccessException(e);
409 }
410 }
411
412 NoSuccessException rethrowExceptionFull(Exception exception) throws PermissionDeniedException, BadParameterException, DoesNotExistException, AlreadyExistsException, TimeoutException, NoSuccessException {
413 try {
414 throw exception;
415 }
416 catch (PermissionDeniedException e) {throw e;}
417 catch (BadParameterException e) {throw e;}
418 catch (DoesNotExistException e) {throw e;}
419 catch (AlreadyExistsException e) {throw e;}
420 catch (TimeoutException e) {throw e;}
421 catch (NoSuccessException e) {throw e;}
422 catch (IllegalArgumentException e) {
423 throw new BadParameterException(e);
424 } catch (IOException e) {
425 throw new TimeoutException(e);
426 } catch (ServerException e) {
427 switch(e.getCode()) {
428 case ServerException.SERVER_REFUSED:
429 try {
430 throw e.getRootCause();
431 } catch (UnexpectedReplyCodeException unexpectedReplyCode) {
432 switch(unexpectedReplyCode.getReply().getCode()) {
433 case 112:
434 throw new TimeoutException(e);
435 case 500:
436 case 521:
437 case 550:
438 case 451:
439 this.rethrowParsedException(unexpectedReplyCode);
440 default:
441 throw new NoSuccessException(e);
442 }
443 } catch (Exception e1) {
444 throw new PermissionDeniedException(e1);
445 }
446 case ServerException.REPLY_TIMEOUT: throw new TimeoutException(e);
447 default: throw new NoSuccessException(e);
448 }
449 } catch (ClientException e) {
450 switch(e.getCode()) {
451 case ClientException.NOT_AUTHORIZED: throw new PermissionDeniedException(e);
452 case ClientException.REPLY_TIMEOUT: throw new TimeoutException(e);
453 default: throw new NoSuccessException(e);
454 }
455 } catch (Exception e) {
456 throw new NoSuccessException(e);
457 }
458 }
459 protected abstract void rethrowParsedException(UnexpectedReplyCodeException e) throws DoesNotExistException, AlreadyExistsException, PermissionDeniedException, NoSuccessException;
460 }