Skip to end of metadata
Go to start of metadata

O Tecgraf/PUC-Rio define e implementa o protocolo FTC (File Transfer Channels) para acessar remotamente arquivos através da abstração de canais de uma forma multi-linguagem. Essa abstração de canais é semelhante aos canais do Java NIO e permite um controle preciso sobre leituras e escritas favorecendo a escalabilidade.

As linguagens suportadas pelo FTC são: C++, Java e Lua. C# passou a ser suportada a partir da versão 1.4 do FTC.

Nesse tutorial será exemplificada a implementação de um cliente e um servidor FTC 1.1 em Java.

Implementando Servidor FTC 1.1

Deve-se começar implementando a interface tecgraf.ftc.server.FileServerOwner. O método createFileChannel será invocado pela biblioteca do FTC quando for solicitado um canal para o arquivo e possui os seguintes parâmetros:

  • parâmetros de entrada:
    • requester: é um objeto Java qualquer que a API prevê para permitir que o implementador identifique o responsável pela requisição.
    • fileId: é um identificador do arquivo no servidor e não deve ultrapassar 255 bytes. Tipicamente será a localização do arquivo dentro do servidor.
    • readOnly: é uma flag para indicar se o canal deve ser aberto apenas para leitura ou se também para escritas.
  • resultado:
    • deve ser retornado um canal java.nio.channels.FileChannel.

 

Classe que cria os canais (FileServerOwnerImpl.java)
import tecgraf.ftc.common.exception.FailureException;
import tecgraf.ftc.common.exception.PermissionException;
import tecgraf.ftc.server.FileServerConfig;
import tecgraf.ftc.server.FileServerOwner;

import java.io.FileNotFoundException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;

public class FileServerOwnerImpl implements FileServerOwner {
	private FileServerConfig config;
	...
	public FileChannel createFileChannel(Object requester, byte[] fileId, boolean readOnly)
            throws PermissionException, FailureException {

        String filename = new String(fileId);

        System.out.println("FTC: requester = " + requester.toString());
        System.out.println("FTC: fileid = " + filename);

        try {
            String mode = (readOnly ? "r" : "rw");
            RandomAccessFile randomAccessFile = new RandomAccessFile(filename, mode);
            return randomAccessFile.getChannel();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            throw new FailureException(e);
        }
    }
	...
	public FileServerConfig getConfig() {
	    return config;
	}

	public void setConfig(FileServerConfig config) {
    	this.config = config;
	} 
}

Após implementar o provedor de canais, basta instanciar um objeto da classe tecgraf.ftc.server.FileServer fornecendo sua implementação do provedor de canais FileServerOwnerImpl (definida no passo anterior). O servidor do FTC é bloqueante e usa seletores do Java NIO.

Classe principal do servidor (Server.java)
import tecgraf.ftc.server.FileServer;
import tecgraf.ftc.server.FileServerConfigImpl;
...
public class Server {
	public static void main(String[] args) {
		...
		FileServerConfigImpl configImpl = new FileServerConfigImpl();
		configImpl.setHostName("localhost");
		configImpl.setPort(9999);

		FileServerOwnerImpl ownerImpl = new FileServerOwnerImpl();
		ownerImpl.setConfig(configImpl);

		final FileServer ftcServer = new FileServer(ownerImpl);

        ftcServer.dispatch(); // inicia loop de eventos bloqueante
	}
}

Para interromper o loop de eventos bloqueante do FTC será preciso executar o método stop do servidor FTC.

Exemplo da captura do sinal de aborto de um processo em Java e parada adequada do servidor FTC:

Runtime.getRuntime().addShutdownHook(
        new Thread() {
            public void run() {
                // parando o atendimento de requisições FTC
                ftcServer.stop();
            }
        });

Caso não se queira bloquear a thread principal será preciso utilizar uma outra thread para executar o método dispatch do servidor FTC.  Exemplo:

// thread para tratar as requisições do protocolo FTC
final Thread ftcServerThread = new Thread() {
    public void run() {
        ftcServer.dispatch();
    }
};
// disparo da thread para o servidor FTC
ftcServerThread.start();
...
// captura do sinal de aborto de um processo em Java e parada adequada do servidor FTC e da thread adicional
Runtime.getRuntime().addShutdownHook(
        new Thread() {
            public void run() {
                // parando o atendimento de requisições FTC
                ftcServer.stop();
				try {
				    // esperando a thread do servidor FTC terminar
				    ftcServerThread.join();
				} catch (InterruptedException e) {
				    e.printStackTrace();
				}
            }
        });

Implementando Cliente FTC 1.1

O cliente FTC precisa criar uma instância da classe tecgraf.ftc.common.logic.RemoteFileChannelImpl que possui o seguinte construtor:

/**
 * Cria um arquivo remoto.
 * 
 * @param identifier O identificador do arquivo (tamanho maximo de 255 bytes).
 * @param writable Indica se a escrita é permitida no arquivo.
 * @param host A máquina do servidor de arquivos.
 * @param port A porta do servidor de arquivos (valores ente 0-65535).
 * @param accessKey A chave de acesso ao arquivo (tamanho maximo de 255 bytes).
 */
public RemoteFileChannelImpl(byte[] identifier, boolean writable, String host, int port, byte[] accessKey); 

Portanto, é preciso reconhecer os parâmetros identifier (mesmo valor que fileId), writablehost, port e accessKey que o servidor do FTC está utilizando para poder acessar o canal remoto.

Exemplo de obtenção do stream remoto completo e armazenamento em arquivo local no cliente:

import tecgraf.ftc.common.logic.RemoteFileChannel;
import tecgraf.ftc.common.logic.RemoteFileChannelImpl;
...
// criação do remote file channel do FTC
RemoteFileChannel channel = new RemoteFileChannelImpl(identifier, writable, host, port, accessKey);
// abertura do canal do FTC
channel.open(true);
// criação do arquivo em disco local
FileOutputStream outStream = new FileOutputStream(new File("test.txt"));
// copia do stream remoto para o output stream local
channel.transferTo(0, channel.getSize(), outStream);
// fechando canal do FTC
channel.close();
// fechando o output stream local
outStream.close();
  • No labels
Write a comment…