Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package uk.ac.ebi.enaega.uploadclient; import it.sauronsoftware.ftp4j.CircularBuffer; import static it.sauronsoftware.ftp4j.FTPClient.TYPE_BINARY; import static it.sauronsoftware.ftp4j.FTPClient.TYPE_TEXTUAL; import it.sauronsoftware.ftp4j.FTPCommunicationChannel; import it.sauronsoftware.ftp4j.FTPDataTransferException; import it.sauronsoftware.ftp4j.FTPDataTransferListener; import it.sauronsoftware.ftp4j.FTPReply; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; 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.ConnectException; import java.net.InetAddress; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SecureRandom; import java.security.Security; import java.text.DecimalFormat; import java.util.Date; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JFrame; import javax.swing.JOptionPane; import main.java.udt.UDPEndPoint; import main.java.udt.UDTOutputStream; import main.java.udt.util.UnifiedSocket; import net.sourceforge.bromo.CommandException; import net.sourceforge.bromo.PasvServer; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openpgp.PGPCompressedDataGenerator; import org.bouncycastle.openpgp.PGPEncryptedData; import org.bouncycastle.openpgp.PGPEncryptedDataGenerator; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPLiteralData; import org.bouncycastle.openpgp.PGPLiteralDataGenerator; import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.util.Arrays; /** * * @author asenf */ public class UploadClientUDT implements Runnable { private InputStream inputStream; private long streamOffset; private OutputStream dataTransferOutputStream; private PasvServer pasvServer; private boolean modezEnabled; private FTPDataTransferListener listener; private long offset; private MyTableModel mm; private int tp; private int SEND_AND_RECEIVE_BUFFER_SIZE; private PGPPublicKey pgKey; private String charSet; private String fileName; private InetAddress dataHost; private int hostPort; private FTPCommunicationChannel communication; private String result = "", result1 = ""; private long c = 0; public UploadClientUDT(InputStream inputStream, long streamOffset, OutputStream dataTransferOutputStream, PasvServer pasvServer, boolean modezEnabled, FTPDataTransferListener listener, long offset, MyTableModel mm, int tp, int SEND_AND_RECEIVE_BUFFER_SIZE, PGPPublicKey pgKey, String charSet, String fileName, InetAddress dataHost, int hostPort, FTPCommunicationChannel communication) { this.inputStream = inputStream; this.streamOffset = streamOffset; this.dataTransferOutputStream = dataTransferOutputStream; this.pasvServer = pasvServer; this.modezEnabled = modezEnabled; this.listener = listener; this.offset = offset; this.mm = mm; this.tp = tp; this.SEND_AND_RECEIVE_BUFFER_SIZE = SEND_AND_RECEIVE_BUFFER_SIZE; this.pgKey = pgKey; this.charSet = charSet; this.fileName = fileName; this.dataHost = dataHost; this.hostPort = hostPort; this.communication = communication; } @Override public void run() { System.setProperty("java.net.preferIPv4Stack", "true"); ByteArrayOutputStream baos = null; // PGP MessageDigest crypt_digest = null; // PGP OutputStream literalOut = null, encOut = null, compressedOut = null; // PGP int DEFAULT_BUFFER_SIZE = 65 * 1024; // PGP PGPEncryptedDataGenerator encryptedDataGenerator = null; // PGP PGPCompressedDataGenerator compressedDataGenerator = null; // PGP PGPLiteralDataGenerator literalDataGenerator = null; // PGP if (this.pgKey != null) { // EGA: Encrypt file try { Security.addProvider(new BouncyCastleProvider()); baos = new ByteArrayOutputStream(2 * DEFAULT_BUFFER_SIZE); // Write to memory! try { crypt_digest = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException ex) { Logger.getLogger(UploadClientUDT.class.getName()).log(Level.SEVERE, null, ex); } // Encrypted Data Generator -- needs unlimited Security Policy encryptedDataGenerator = new PGPEncryptedDataGenerator(PGPEncryptedData.CAST5, true, new SecureRandom(), "BC"); try { encryptedDataGenerator.addMethod(this.pgKey); encOut = encryptedDataGenerator.open(baos, new byte[DEFAULT_BUFFER_SIZE]); } catch (NoSuchProviderException ex) { Logger.getLogger(UploadClientUDT.class.getName()).log(Level.SEVERE, null, ex); } catch (PGPException ex) { Logger.getLogger(UploadClientUDT.class.getName()).log(Level.SEVERE, null, ex); } // Compression compressedDataGenerator = new PGPCompressedDataGenerator(PGPCompressedDataGenerator.ZIP); compressedOut = compressedOut = new BufferedOutputStream(compressedDataGenerator.open(encOut)); // Literal Data Generator and Output Stream literalDataGenerator = new PGPLiteralDataGenerator(); literalOut = literalDataGenerator.open(compressedOut, PGPLiteralData.BINARY, fileName, new Date(), new byte[DEFAULT_BUFFER_SIZE]); // 1<<16 } catch (Throwable t) { JOptionPane.showMessageDialog(new JFrame(), "Can't instantiate cipher key.\nBe sure to have JCE Unlimited Strength Security Policy installed.", "Cipher Key Problem", JOptionPane.ERROR_MESSAGE); String[] failure = { "Cipher Issues" }; return; //return failure; } } // Upload the stream. // Transfer! Start by accepting aconnection initiated by the server UnifiedSocket dataSocket = null; // Upload the stream. long c = 0; System.out.println("1 getting " + dataHost.toString() + " " + hostPort); try { // dataSocket = pasvServer.getMatching( dataHost, hostPort ); dataSocket = getSocket_timeout(); //getSocket(); //if (dataSocket == null) dataSocket = getSocket_timeout(); if (dataSocket == null) throw new ConnectException(); System.out.println("2"); // Skips. inputStream.skip(streamOffset); // Opens the data transfer connection. dataTransferOutputStream = dataSocket.getOutputStream(); // TCP or UDT - automatically // Listeners. Initialize to offset! if (listener != null) { listener.started(); int large = 0, small = 0; large = (int) (offset / Integer.MAX_VALUE); // times the size of largest int small = (int) (offset % Integer.MAX_VALUE); // remainder for (int iu = 0; iu < large; iu++) listener.transferred(Integer.MAX_VALUE); listener.transferred(small); } long tot = 0; int idx = 0; // Update the table model if (mm != null) { // For Table Updates idx = mm.getCur(); mm.setValueAt("0%", idx, 5); tot = mm.getSize(); } String line = communication.readFTPReply().toString(); System.out.println("Server Reply (STOR test.txt): " + line); // Let's do it! if (tp == TYPE_TEXTUAL) { // ------------------------------------- TEXT DATA ------------------ char[] buffer = new char[SEND_AND_RECEIVE_BUFFER_SIZE]; byte[] bbuffer = new byte[SEND_AND_RECEIVE_BUFFER_SIZE]; int l, l_tot = 0; long cnt = 0, cnt_ = 0; long block_cnt = 0, block_cnt_pre = 0; long flush_point = 1048576L * 10L; long pre_flush_point = 1048576L * 9L; Reader reader = new InputStreamReader(inputStream); Writer writer = new OutputStreamWriter(dataTransferOutputStream, charSet); MessageDigest digest = null; // calculate checksum of incoming data stream try { digest = MessageDigest.getInstance("MD5"); // get the hash algorithm } catch (NoSuchAlgorithmException ex) { Logger.getLogger(UploadClientUDT.class.getName()).log(Level.SEVERE, null, ex); } long dt_file = System.currentTimeMillis(), dt_upd = System.currentTimeMillis(); // time before upload while ((l = reader.read(buffer)) != -1) { // The actual data transfer loop ------------------- System.arraycopy(buffer, 0, bbuffer, 0, l); digest.update(bbuffer, 0, l); // Calculate MD5 for TCP stream if (this.pgKey != null) { // Cipher - write to mem buffer first, to enable MD5 literalOut.write(bbuffer, 0, l); literalOut.flush(); byte[] buffer_ = baos.toByteArray(); crypt_digest.update(buffer_); char[] buffer__ = new char[buffer_.length]; System.arraycopy(buffer_, l_tot, buffer__, 0, buffer_.length); cnt += buffer_.length; cnt_ += buffer_.length; block_cnt += buffer_.length; block_cnt_pre += buffer_.length; writer.write(buffer__); baos.reset(); } else { // Write directly to socket cnt += buffer.length; cnt_ += buffer.length; block_cnt += buffer.length; block_cnt_pre += buffer.length; writer.write(buffer, 0, l); } if ((block_cnt_pre / pre_flush_point) > 0) { block_cnt_pre = 0; writer.flush(); } //writer.flush(); if (listener != null) { listener.transferred(l); if (l > 0) { // l = bytes, dt_file = milliseconds dt_upd = System.currentTimeMillis() - dt_upd; double rate = (((double) (l)) / (((double) (dt_upd)))) * 1000.0; // bytes/s if (rate > 0) { String sd = size_display((long) (rate)); if (sd != null && sd.length() > 0) listener.setText(size_display((long) (rate)) + "/s"); } dt_upd = System.currentTimeMillis(); } } if (mm != null && tot != 0) { l_tot += l; double pct = (double) l_tot / (double) tot; int i_pct = (int) Math.floor(pct * 100); String s_pct = String.valueOf(i_pct) + "%"; mm.setValueAt(s_pct, idx, 5); } } // Get a representation of the MD5 digest (checksum) byte[] md5sum = digest.digest(); result = ""; for (int i = 0; i < md5sum.length; i++) result += Integer.toString((md5sum[i] & 0xff) + 0x100, 16).substring(1); } else if (tp == TYPE_BINARY) { // ------------------------------ BINARY DATA --------------------- System.out.println("Binary Transfer"); long cnt = 0, cnt_ = 0; long block_cnt = 0, block_cnt_pre = 0; long flush_point = 1048576L * 10L; long pre_flush_point = 1048576L * 9L; int bufsze = 250 * (UDPEndPoint.DATAGRAM_SIZE - 24); byte[] buffer = new byte[bufsze]; int l; long l_tot = 0; MessageDigest digest = null; // calculate checksum of incoming data stream try { digest = MessageDigest.getInstance("MD5"); // get the hash algorithm } catch (NoSuchAlgorithmException ex) { Logger.getLogger(UploadClientUDT.class.getName()).log(Level.SEVERE, null, ex); } // Actual transfer identical between TCP and UDT long dt_file = System.currentTimeMillis(), dt_upd = System.currentTimeMillis(); // time before upload CircularBuffer cb = new CircularBuffer(bufsze + (20 * (UDPEndPoint.DATAGRAM_SIZE - 24))); System.out.println("Actual Send Loop starts"); while ((l = inputStream.read(buffer)) != -1) { // The actual data transfer loop ------------------- if (this.pgKey != null) { // PGP Key present - encrypted Stream literalOut.write(buffer, 0, l); // Write to mem buffer - this is the encryption literalOut.flush(); byte[] buffer_ = baos.toByteArray(); // retrieve that buffer crypt_digest.update(buffer_); // update crypto MD5 c += buffer_.length; cb.put(buffer_); // Write into circular buffer baos.reset(); // empty mem buffer } else { c += l; //buffer.length; // only what was read! cb.put(Arrays.copyOf(buffer, l)); // Write into circular buffer } // Send the data in packet-sized portions from circular buffer temp structure while (cb.getSize() > (UDPEndPoint.DATAGRAM_SIZE - 24)) { byte[] sendbuf = new byte[(UDPEndPoint.DATAGRAM_SIZE - 24)]; sendbuf = cb.get(sendbuf.length); cnt += sendbuf.length; cnt_ += sendbuf.length; block_cnt += sendbuf.length; block_cnt_pre += sendbuf.length; dataTransferOutputStream.write(sendbuf, 0, sendbuf.length); // buffer, 0, l if ((block_cnt_pre / pre_flush_point) > 0) { block_cnt_pre = 0; ((UDTOutputStream) dataTransferOutputStream).pre_flush(); } if ((block_cnt / flush_point) > 0) { block_cnt = 0; dataTransferOutputStream.flush(); } } digest.update(buffer, 0, l); // Calculate plain text MD5 for TCP stream if (listener != null) { listener.transferred(l); // Update total-progress bar if (l > 0) { // l = bytes, dt_file = milliseconds dt_upd = System.currentTimeMillis() - dt_upd; double rate = (((double) (l)) / (((double) (dt_upd)))) * 1000.0; // bytes/s if (rate > 0) { String sd = size_display((long) (rate)); if (sd != null && sd.length() > 0) listener.setText(size_display((long) (rate)) + "/s"); } dt_upd = System.currentTimeMillis(); } } if (mm != null && tot != 0) { // Update in-table progress bar l_tot += l; double pct = (double) l_tot / (double) tot; int i_pct = (int) Math.floor(pct * 100); String s_pct = String.valueOf(i_pct) + "%"; mm.setValueAt(s_pct, idx, 5); } } // Input stream completely read --- if (cb.getSize() > 0) { // Flush the buffer at the end - MD5s already complete at this point byte[] sendbuf = new byte[cb.getSize()]; sendbuf = cb.get(sendbuf.length); dataTransferOutputStream.write(sendbuf, 0, sendbuf.length); } // Get a representation of the MD5 digest (checksum) plain file byte[] md5sum = digest.digest(); result = ""; for (int i = 0; i < md5sum.length; i++) result += Integer.toString((md5sum[i] & 0xff) + 0x100, 16).substring(1); } // Upload loop complete. Close PGP streams, if used (produces extra data) if (this.pgKey != null) { literalOut.close(); literalDataGenerator.close(); // Close all other streams compressedOut.close(); compressedDataGenerator.close(); encOut.close(); encryptedDataGenerator.close(); byte[] buffer_ = baos.toByteArray(); // retrieve that buffer crypt_digest.update(buffer_); // update crypto MD5 dataTransferOutputStream.write(buffer_); // Write cipher data to socket dataTransferOutputStream.flush(); baos.close(); // Get a representation of the MD5 digest (checksum) cipher file byte[] md5sum = crypt_digest.digest(); result1 = ""; for (int i = 0; i < md5sum.length; i++) result1 += Integer.toString((md5sum[i] & 0xff) + 0x100, 16).substring(1); } dataTransferOutputStream.flush(); } catch (Throwable e) { if (listener != null) { listener.aborted(); } try { throw new FTPDataTransferException("I/O error in data transfer", e); } catch (FTPDataTransferException ex) { Logger.getLogger(UploadClientUDT.class.getName()).log(Level.SEVERE, null, ex); } } finally { // Closing stream and data connection. if (dataTransferOutputStream != null) { try { dataTransferOutputStream.flush(); dataTransferOutputStream.close(); } catch (Throwable t) { ; } } try { dataSocket.close(); } catch (Throwable t) { ; } // Set to null the instance-level input stream. dataTransferOutputStream = null; // Consume the result reply of the transfer. FTPReply readFTPReply = null; try { readFTPReply = communication.readFTPReply(); } catch (Throwable ex) { Logger.getLogger(UploadClientUDT.class.getName()).log(Level.SEVERE, null, ex); } System.out.println(readFTPReply.toString()); // Change the operation status. } } private UnifiedSocket getSocket_timeout() throws IOException, CommandException { UnifiedSocket x = null; Future y = null; Callable callable = new Callable() { @Override public UnifiedSocket call() throws Exception { //if (!dataPasv) { // net.sourceforge.bromo.Logger.log( net.sourceforge.bromo.Logger.LOG_DEBUG, "ServerDTP.getSocket(PORT) = " + dataHost + ":" + dataPort ); // return new UnifiedSocket( dataHost, dataPort, serverPI.isTCP() ); //} net.sourceforge.bromo.Logger.log(net.sourceforge.bromo.Logger.LOG_DEBUG, "UploadClientUDT.getSocket(PASV) = " + dataHost + ":" + hostPort); return pasvServer.getMatching(dataHost, hostPort); } }; ExecutorService exec = Executors.newSingleThreadExecutor(); Future<UnifiedSocket> res = exec.submit(callable); try { x = res.get(5, TimeUnit.SECONDS); } catch (ExecutionException ex) { java.util.logging.Logger.getLogger(UploadClientUDT.class.getName()).log(Level.SEVERE, null, ex); } catch (TimeoutException ex) { java.util.logging.Logger.getLogger(UploadClientUDT.class.getName()).log(Level.SEVERE, null, ex); } catch (InterruptedException ex) { java.util.logging.Logger.getLogger(UploadClientUDT.class.getName()).log(Level.SEVERE, null, ex); } if (!res.isDone()) res.cancel(true); exec.shutdown(); return x; } public String get_md5() { return this.result; } public String get_crypto_md5() { return this.result1; } public long get_c() { return this.c; } private String size_display(long in) { // expects bytes String result = ""; DecimalFormat df = new DecimalFormat("#,##0.00"); double in_format = 0; if (in < 1024) { result = in + " Bytes"; } else if (in < Math.pow(1024, 2)) { in_format = (in / Math.pow(1024, 1)); //result = new Double(df.format(in_format)).doubleValue() + " KB"; result = df.format(in_format) + " KB"; } else if (in < Math.pow(1024, 3)) { in_format = (in / Math.pow(1024, 2)); //result = new Double(df.format(in_format)).doubleValue() + " MB"; result = df.format(in_format) + " MB"; } else if (in < Math.pow(1024, 4)) { in_format = (in / Math.pow(1024, 3)); //result = new Double(df.format(in_format)).doubleValue() + " GB"; result = df.format(in_format) + " GB"; } else if (in < Math.pow(1024, 5)) { in_format = (in / Math.pow(1024, 4)); //result = new Double(df.format(in_format)).doubleValue() + " TB"; result = df.format(in_format) + " TB"; } else if (in < Math.pow(1024, 6)) { in_format = (in / Math.pow(1024, 5)); //result = new Double(df.format(in_format)).doubleValue() + " PB"; result = df.format(in_format) + " PB"; } return result; } }