All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.globus.ftp.GridFTPClient Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 1999-2006 University of Chicago
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.globus.ftp;

import java.io.IOException;
import java.io.File;
import java.io.RandomAccessFile;
import java.util.Vector;
import java.net.UnknownHostException;

import org.globus.ftp.exception.ClientException;
import org.globus.ftp.exception.ServerException;
import org.globus.ftp.exception.FTPReplyParseException;
import org.globus.ftp.exception.UnexpectedReplyCodeException;
import org.globus.ftp.vanilla.Command;
import org.globus.ftp.vanilla.Reply;
import org.globus.ftp.vanilla.TransferState;
import org.globus.ftp.vanilla.FTPControlChannel;
import org.globus.ftp.extended.GridFTPServerFacade;
import org.globus.ftp.extended.GridFTPControlChannel;
import org.globus.gsi.gssapi.auth.Authorization;
import org.globus.ftp.MultipleTransferComplete;
import org.globus.ftp.MultipleTransferCompleteListener;

import org.ietf.jgss.GSSCredential;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.globus.common.Version;

import java.io.ByteArrayOutputStream;
import java.text.DecimalFormat;
import org.globus.ftp.exception.FTPException;


/**
 * This is the main user interface for GridFTP operations.
 * Use this class for client - server or third party transfers
 * with mode E, parallelism, markers, striping or GSI authentication.
 * Consult the manual for general usage.
 * 
Note: If using with GridFTP servers operations like * {@link #setMode(int) setMode()}, {@link #setType(int) setType()}, * {@link #setDataChannelProtection(int) setDataChannelProtection()}, * and {@link #setDataChannelAuthentication(DataChannelAuthentication) * setDataChannelAuthentication()} that affect data channel settings * must be called before passive or active data channel mode is set. **/ public class GridFTPClient extends FTPClient { private static Log logger = LogFactory.getLog(GridFTPClient.class.getName()); //utility alias to session and localServer protected GridFTPSession gSession; protected GridFTPServerFacade gLocalServer; protected String usageString; /** * Constructs client and connects it to the remote server. * * @param host remote server host * @param port remote server port */ public GridFTPClient(String host, int port) throws IOException, ServerException { gSession = new GridFTPSession(); session = gSession; controlChannel = new GridFTPControlChannel(host, port); controlChannel.open(); gLocalServer = new GridFTPServerFacade((GridFTPControlChannel)controlChannel); localServer = gLocalServer; gLocalServer.authorize(); this.useAllo = true; setUsageInformation("CoG", Version.getVersion()); } /** * Performs authentication with specified user credentials. * * @param credential user credentials to use. * @throws IOException on i/o error * @throws ServerException on server refusal or faulty server behavior */ public void authenticate(GSSCredential credential) throws IOException, ServerException { authenticate(credential, null); } public void setUsageInformation( String appName, String appVer) { usageString = new String( "CLIENTINFO appname=" + appName +";appver=" + appVer + ";schema=gsiftp;"); } /** * Performs authentication with specified user credentials and * a specific username (assuming the user dn maps to the passed username). * * @param credential user credentials to use. * @param username specific username to authenticate as. * @throws IOException on i/o error * @throws ServerException on server refusal or faulty server behavior */ public void authenticate(GSSCredential credential, String username) throws IOException, ServerException { ((GridFTPControlChannel)controlChannel).authenticate(credential, username); gLocalServer.setCredential(credential); gSession.authorized = true; this.username = username; // quietly send version information to the server. // ignore errors try { String version = Version.getVersion(); this.site(usageString); } catch (Exception ex) { } } /** * Performs remote directory listing like * {@link FTPClient#list(String,String) FTPClient.list()}. * Note: This method cannot be used * in conjunction with parallelism or striping; set parallelism to * 1 before calling it. Otherwise, use * {@link FTPClient#list(String,String,DataSink) FTPClient.list()}. * Unlike in vanilla FTP, here IMAGE mode is allowed. * For more documentation, look at FTPClient. */ public Vector list(String filter, String modifier) throws ServerException, ClientException, IOException { if (gSession.parallel > 1) { throw new ClientException( ClientException.BAD_MODE, "list cannot be called with parallelism"); } return super.list(filter, modifier); } /** * Performs remote directory listing like * {@link FTPClient#nlist(String) FTPClient.nlist()}. * Note: This method cannot be used * in conjunction with parallelism or striping; set parallelism to * 1 before calling it. Otherwise, use * {@link FTPClient#nlist(String,DataSink) FTPClient.nlist()}. * Unlike in vanilla FTP, here IMAGE mode is allowed. * For more documentation, look at FTPClient. */ public Vector nlist(String path) throws ServerException, ClientException, IOException { if (gSession.parallel > 1) { throw new ClientException( ClientException.BAD_MODE, "nlist cannot be called with parallelism"); } return super.nlist(path); } /** * Performs remote directory listing like * {@link FTPClient#mlsd(String) FTPClient.mlsd()}. * Note: This method cannot be used * in conjunction with parallelism or striping; set parallelism to * 1 before calling it. Otherwise, use * {@link FTPClient#mlsd(String,DataSink) FTPClient.mlsd()}. * Unlike in vanilla FTP, here IMAGE mode is allowed. * For more documentation, look at FTPClient. */ public Vector mlsd(String filter) throws ServerException, ClientException, IOException { if (gSession.parallel > 1) { throw new ClientException( ClientException.BAD_MODE, "mlsd cannot be called with parallelism"); } return super.mlsd(filter); } protected void listCheck() throws ClientException { // do nothing } protected void checkTransferParamsGet() throws ServerException, IOException, ClientException { Session localSession = localServer.getSession(); session.matches(localSession); // if transfer modes have not been defined, // set this (dest) as active if (session.serverMode == Session.SERVER_DEFAULT) { HostPort hp = setLocalPassive(); setActive(hp); } } protected String getModeStr(int mode) { switch (mode) { case Session.MODE_STREAM: return "S"; case Session.MODE_BLOCK: return "B"; case GridFTPSession.MODE_EBLOCK: return "E"; default: throw new IllegalArgumentException("Bad mode: " + mode); } } /** * Sets remote server TCP buffer size, in the following way: * First see if server supports "SBUF" and if so, use it. * If not, try the following commands until success: * "SITE RETRBUFSIZE", "SITE RBUFSZ", "SITE RBUFSIZ", * "SITE STORBUFSIZE", "SITE SBUFSZ", "SITE SBUFSIZ", * "SITE BUFSIZE". * Returns normally if the server confirms successfull setting of the * remote buffer size, both for sending and for receiving data. * Otherwise, throws ServerException. **/ public void setTCPBufferSize(int size) throws IOException, ServerException { if (size <= 0) { throw new IllegalArgumentException("size <= 0"); } try { boolean succeeded = false; String sizeString = Integer.toString(size); FeatureList feat = getFeatureList(); if (feat.contains(FeatureList.SBUF)) { succeeded = tryExecutingCommand( new Command("SBUF", sizeString)); } if (!succeeded) { succeeded = tryExecutingCommand( new Command("SITE BUFSIZE", sizeString)); } if (!succeeded) { succeeded = tryExecutingTwoCommands(new Command("SITE RETRBUFSIZE", sizeString), new Command("SITE STORBUFSIZE", sizeString)); } if (!succeeded) { succeeded = tryExecutingTwoCommands(new Command("SITE RBUFSZ", sizeString), new Command("SITE SBUFSZ", sizeString)); } if (!succeeded) { succeeded = tryExecutingTwoCommands(new Command("SITE RBUFSIZ", sizeString), new Command("SITE SBUFSIZ", sizeString)); } if (succeeded) { this.gSession.TCPBufferSize = size; } else { throw new ServerException(ServerException.SERVER_REFUSED, "Server refused setting TCP buffer size with any of the known commands."); } } catch (FTPReplyParseException rpe) { throw ServerException.embedFTPReplyParseException(rpe); } } private boolean tryExecutingTwoCommands(Command cmd1, Command cmd2) throws IOException, FTPReplyParseException, ServerException { boolean result = tryExecutingCommand(cmd1); if (result) { result = tryExecutingCommand(cmd2); } return result; } /* * This is like controlChannel.executeCommand, only that negative reply it * returns "false" rather than throwing exception */ private boolean tryExecutingCommand(Command cmd) throws IOException, FTPReplyParseException, ServerException { Reply reply = controlChannel.exchange(cmd); return Reply.isPositiveCompletion(reply); } /** * Sets local TCP buffer size (for both receiving and sending). **/ public void setLocalTCPBufferSize(int size) throws ClientException { if (size <=0 ) { throw new IllegalArgumentException("size <= 0"); } gLocalServer.setTCPBufferSize(size); } /** * Sets remote server to striped passive server mode (SPAS). **/ public HostPortList setStripedPassive() throws IOException, ServerException { Command cmd = new Command("SPAS", (controlChannel.isIPv6()) ? "2" : null); Reply reply = null; try { reply = controlChannel.execute(cmd); } catch (UnexpectedReplyCodeException urce) { throw ServerException.embedUnexpectedReplyCodeException(urce); } catch(FTPReplyParseException rpe) { throw ServerException.embedFTPReplyParseException(rpe); } this.gSession.serverMode = GridFTPSession.SERVER_EPAS; if (controlChannel.isIPv6()) { gSession.serverAddressList = HostPortList.parseIPv6Format(reply.getMessage()); int size = gSession.serverAddressList.size(); for (int i=0;i 1) { throw new ClientException( ClientException.BAD_MODE, "mlsr cannot be called with parallelism"); } Command cmd = (path == null) ? new Command("MLSR") : new Command("MLSR", path); MlsxParserDataSink sink = new MlsxParserDataSink(writer); performTransfer(cmd, sink); } private class MlsxParserDataSink implements DataSink { private MlsxEntryWriter writer; private byte[] buf = new byte[4096]; private int pos = 0; public MlsxParserDataSink(MlsxEntryWriter w) { writer = w; } public void write(Buffer buffer) throws IOException { byte[] data = buffer.getBuffer(); int len = buffer.getLength(); int i = 0; while (i < len && pos < buf.length) { if (data[i] == '\r' || data[i] == '\n') { if (pos > 0) { try { writer.write(new MlsxEntry(new String(buf, 0, pos))); } catch (FTPException ex) { throw new IOException(); } } pos = 0; while (i < len && data[i] < ' ') ++i; } else { buf[pos++] = data[i++]; } } } public void close() throws IOException { writer.close(); } } /** * Change the Unix group membership of a file. * * @param group the name or ID of the group * @param file the file whose group membership should be changed * @exception ServerException if an error occurred. */ public void changeGroup(String group, String file) throws IOException, ServerException { String arguments = group + " " + file; Command cmd = new Command("SITE CHGRP", arguments); try { controlChannel.execute(cmd); } catch (UnexpectedReplyCodeException urce) { throw ServerException.embedUnexpectedReplyCodeException(urce); } catch (FTPReplyParseException rpe) { throw ServerException.embedFTPReplyParseException(rpe); } } /** * Change the modification time of a file. * * @param year Modifcation year * @param month Modification month (1-12) * @param day Modification day (1-31) * @param hour Modification hour (0-23) * @param min Modification minutes (0-59) * @param sec Modification seconds (0-59) * @param file file whose modification time should be changed * @throws IOException * @throws ServerException if an error occurred. */ public void changeModificationTime(int year, int month, int day, int hour, int min, int sec, String file) throws IOException, ServerException { DecimalFormat df2 = new DecimalFormat("00"); DecimalFormat df4 = new DecimalFormat("0000"); String arguments = df4.format(year) + df2.format(month) + df2.format(day) + df2.format(hour) + df2.format(min) + df2.format(sec) + " " + file; Command cmd = new Command("SITE UTIME", arguments); try { controlChannel.execute(cmd); }catch (UnexpectedReplyCodeException urce) { throw ServerException.embedUnexpectedReplyCodeException(urce); } catch (FTPReplyParseException rpe) { throw ServerException.embedFTPReplyParseException(rpe); } } /** * Create a symbolic link on the FTP server. * * @param link_target the path to which the symbolic link should point * @param link_name the path of the symbolic link to create * @throws IOException * @throws ServerException if an error occurred. */ public void createSymbolicLink(String link_target, String link_name) throws IOException, ServerException { String arguments = link_target.replaceAll(" ", "%20") + " " + link_name; Command cmd = new Command("SITE SYMLINK", arguments); try { controlChannel.execute(cmd); }catch (UnexpectedReplyCodeException urce) { throw ServerException.embedUnexpectedReplyCodeException(urce); } catch (FTPReplyParseException rpe) { throw ServerException.embedFTPReplyParseException(rpe); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy