/*
* Copyright (C) 2004 The Concord Consortium, Inc.,
* 10 Concord Crossing, Concord, MA 01742
*
* Web Site: http://www.concord.org
* Email: info@concord.org
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* END LICENSE */
package org.concord.otrunk.transfer;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Vector;
public class Transfer
{
public static final int CHAR_BUFFER_SIZE = 1024;
public static final int BYTE_BUFFER_SIZE = CHAR_BUFFER_SIZE * 64;
protected ArrayList<TransferListener> listeners = new ArrayList<TransferListener>();
protected TransferEvent currentEvent;
protected int charBufferSize = CHAR_BUFFER_SIZE;
protected int byteBufferSize = BYTE_BUFFER_SIZE;
protected Object copier = null;
public void transfer(Reader input, Writer output)
throws IOException
{
try
{
char [] buffer = new char[charBufferSize];
int total = 0;
for (int i = input.read(buffer, 0, charBufferSize); i > 0;
i = input.read(buffer, 0, charBufferSize))
{
total += i;
output.write(buffer, 0, i);
progressEvent(total);
}
output.flush();
output.close();
input.close();
}
catch (IOException e)
{
System.out.println(e);
e.printStackTrace();
throw(e);
}
}
public void transfer(InputStream input, OutputStream output)
throws IOException
{
transfer(input, output, true);
}
public void transfer(InputStream input, OutputStream output, boolean closeStreams)
throws IOException
{
try
{
byte [] buffer = new byte[byteBufferSize];
int total = 0;
for (int i = input.read(buffer, 0, byteBufferSize); i > 0;
i = input.read(buffer, 0, byteBufferSize))
{
total += i;
output.write(buffer, 0, i);
progressEvent(total);
}
if(closeStreams) {
output.flush();
output.close();
input.close();
}
}
catch (IOException e)
{
System.out.println(e);
throw(e);
}
}
public void transfer(File src, File dest)
throws IOException
{
try
{
if (src.isDirectory())
{
if (dest.exists())
{
if (! dest.isDirectory())
{
throw new RuntimeException("Target not a directory");
}
}
else
{
dest.mkdirs();
}
String [] fileList = src.list();
for (int i = 0; i < fileList.length; i++)
{
transfer(new File(src, fileList[i]), new File(dest, fileList[i]));
}
}
else
{
dest = new File(dest.getCanonicalPath());
if(!dest.exists())
{
// Make any of the directories required for this file
String destCanon = dest.getCanonicalPath();
String parent = new File(destCanon).getParent();
if(parent != null)
{
(new File(parent)).mkdirs();
}
}
else
{
dest.delete();
}
startEvent(src.toString(), dest.toString(), (int)src.length());
InputStream input = new FileInputStream(src);
OutputStream output = new FileOutputStream(dest);
transfer(input, output);
finishEvent();
}
}
catch (IOException e)
{
abortEvent(e);
// clean up
throw e;
}
}
public void copy(File src, File dest)
throws IOException
{
try
{
if(!src.exists())
{
throw new RuntimeException("Source doesn't exist");
}
if(dest.isDirectory())
{
String fileName = src.getName();
File destFile = new File(dest, fileName);
if(src.isDirectory())
{
// Check for infinite recursion
String srcString = src.getCanonicalPath();
String destString = dest.getCanonicalPath();
if(destString.startsWith(srcString))
{
throw new RuntimeException("Dest directory is inside of src directory(infinite recursion)");
}
destFile.mkdir();
// if(copier != null) copier.handleDirectories(src,dest);
String [] fileList = src.list();
for (int i = 0; i < fileList.length; i++)
{
copy(new File(src, fileList[i]), destFile);
}
}
else
{
startEvent(src.toString(), destFile.toString(), (int)src.length());
InputStream input = new FileInputStream(src);
OutputStream output = new FileOutputStream(destFile);
transfer(input, output);
finishEvent();
}
}
else if(dest.exists())
{
if(src.isDirectory())
{
throw new RuntimeException("Source is directory but destination is not");
}
File destParent = new File(new File(dest.getCanonicalPath()).getParent());
copy(src, destParent);
}
else
{
// I used getAbsolute here because some platforms complain when they try to get
// a canonical path for a file that doesn't exist.
File destAbsolute = new File(dest.getAbsolutePath());
File destParent = new File(destAbsolute.getParent());
if(!destParent.exists())
{
throw new RuntimeException("Cannot create destination file. The parent directory " +
"of the destination doesn't exist");
}
copy(src, destParent);
}
}
catch (IOException e)
{
abortEvent(e);
// clean up
throw e;
}
}
public Vector<String> getFileNames(String dirName, Vector<String> fileList, boolean includeDirs)
{
File directory = new File(dirName);
String [] fileNames = directory.list();
for (int i = 0; i < fileNames.length; i++)
{
fileNames[i] = dirName + "/" + fileNames[i];
File file = new File(fileNames[i]);
if (file.isDirectory())
{
fileList = getFileNames(fileNames[i], fileList, includeDirs);
}
else
{
fileList.addElement(fileNames[i]);
}
}
if (includeDirs)
fileList.addElement(dirName);
return fileList;
}
public String [] getFileNames(String dirName, boolean includeDirs)
{
Vector<String> fileList = getFileNames(dirName, new Vector<String>(), includeDirs);
String [] fileNames = new String[fileList.size()];
for (int i = 0; i < fileNames.length; i++)
{
fileNames[i] = (String) fileList.elementAt(i);
}
return fileNames;
}
public String [] getFileNames(String dirName)
{
return getFileNames(dirName, false);
}
public File [] getFiles(String dirName, boolean includeDirs)
{
Vector<String> fileList = getFileNames(dirName, new Vector<String>(), includeDirs);
File [] files = new File[fileList.size()];
for (int i = 0; i < files.length; i++)
{
files[i] = new File((String) fileList.elementAt(i));
}
return files;
}
public File [] getFiles(String dirName)
{
return getFiles(dirName, false);
}
public void setBufferSize(int size)
{
charBufferSize = size;
byteBufferSize = 4 * size;
}
public void addTransferListener(TransferListener listener)
{
listeners.add(listener);
}
public void removeTransferListener(TransferListener listener)
{
listeners.remove(listener);
}
public void checkEvent(String sourceContent, String contentName)
{
currentEvent = new TransferEvent(this, sourceContent, contentName, 0);
for (TransferListener listener : listeners) {
listener.transferCheck(currentEvent);
}
}
/**
* if the length is -1 then the length is unknown
*/
public void startEvent(String sourceContent, String contentName, int length)
{
if (currentEvent == null)
currentEvent = new TransferEvent(this, sourceContent, contentName, length);
else
{
currentEvent.setSourceContent(sourceContent);
currentEvent.setContentName(contentName);
currentEvent.setContentLength(length);
}
for (TransferListener listener : listeners) {
listener.transferStarted(currentEvent);
}
}
public void progressEvent(int currentTotal)
{
if (currentEvent instanceof TransferEvent)
{
currentEvent.setProgress(currentTotal);
for (TransferListener listener : listeners) {
listener.transferProgress(currentEvent);
}
}
}
public void finishEvent()
{
for (TransferListener listener : listeners) {
listener.transferFinished(currentEvent);
}
}
public void abortEvent(Exception e)
{
currentEvent.setException(e);
for (TransferListener listener : listeners) {
listener.transferAborted(currentEvent);
}
}
public Transfer.Server createTransferServer(int port)
{
return new Transfer.Server(this, port);
}
public Transfer.Client createTransferClient(String host, int port, String dirName)
{
return new Transfer.Client(this, host, port, dirName);
}
public static void main(String [] args)
{
if (args.length > 0)
{
Transfer transfer = new Transfer();
if (args[0].toLowerCase().equals("client"))
{
transfer.createTransferClient(args[1], Integer.parseInt(args[2]), args[3]);
}
else if (args[0].toLowerCase().equals("server"))
{
transfer.createTransferServer(Integer.parseInt(args[1]));
}
}
}
public class Server
implements Runnable
{
protected Socket clientSocket;
protected Thread serverThread;
protected Transfer transfer;
public Server(Transfer transfer, int port)
{
this.transfer = transfer;
try
{
ServerSocket socket = new ServerSocket(port);
while (true)
{
try
{
clientSocket = socket.accept();
serverThread = new Thread(this);
serverThread.start();
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
}
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
}
public void run()
{
String fileName = "<No file>";
int length = 0;
try
{
BufferedReader input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
fileName = input.readLine();
length = Integer.parseInt(input.readLine());
startEvent(fileName, fileName, length);
File file = new File(fileName);
File path = new File(file.getCanonicalPath());
String parent = path.getParent();
if (parent instanceof String)
{
File directory = new File(parent);
directory.mkdirs();
}
FileWriter output = new FileWriter(file);
transfer(input, output);
finishEvent();
}
catch (Exception e)
{
abortEvent(e);
}
}
}
public class Client
{
protected Transfer transfer;
public Client(Transfer transfer, String host, int port, String dirName)
{
this.transfer = transfer;
File directory = new File(dirName);
if (directory.isDirectory())
{
transferFiles(host, port, getFileNames(dirName));
}
}
protected void transferFiles(String host, int port, String [] fileNames)
{
for (int i = 0; i < fileNames.length; i++)
{
try
{
Socket socket = new Socket(host, port);
File file = new File(fileNames[i]);
int length = (int) file.length();
FileReader input = new FileReader(file);
BufferedWriter output = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
startEvent(host + ":" + port + "/" + fileNames[i], fileNames[i], length);
output.write(fileNames[i]);
output.newLine();
output.write("" + length);
output.newLine();
output.flush();
transfer(input, output);
finishEvent();
}
catch (Exception e)
{
abortEvent(e);
}
}
}
}
}