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.FTPCommunicationChannel; import it.sauronsoftware.ftp4j.FTPDataTransferException; import it.sauronsoftware.ftp4j.FTPDataTransferListener; 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.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.logging.Level; import java.util.logging.Logger; import java.util.zip.DeflaterOutputStream; import javax.swing.JFrame; import javax.swing.JOptionPane; import main.java.udt.util.UnifiedSocket; 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 static uk.ac.ebi.enaega.uploadclient.FTPClient_alternative.TYPE_BINARY; import static uk.ac.ebi.enaega.uploadclient.FTPClient_alternative.TYPE_TEXTUAL; /** * * @author asenf */ public class UploadClient implements Runnable { private final InputStream inputStream; private final long streamOffset; private OutputStream dataTransferOutputStream; private final UnifiedSocket dtConnection; private final boolean modezEnabled; private final FTPDataTransferListener listener; private final long offset; private final MyTableModel mm; private final int tp; private final int SEND_AND_RECEIVE_BUFFER_SIZE; private final PGPPublicKey pgKey; private final String charSet; private final String fileName; private String result = "", result1 = ""; private long c = 0; private boolean complete = false; private boolean completed; public UploadClient(InputStream inputStream, long streamOffset, OutputStream dataTransferOutputStream, UnifiedSocket dtConnection, boolean modezEnabled, FTPDataTransferListener listener, long offset, MyTableModel mm, int tp, int SEND_AND_RECEIVE_BUFFER_SIZE, PGPPublicKey pgKey, String charSet, String fileName) { this.inputStream = inputStream; this.streamOffset = streamOffset; this.dataTransferOutputStream = dataTransferOutputStream; this.dtConnection = dtConnection; 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; } @Override public void run() { completed = false; 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(FTPClient_alternative.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(FTPClient_alternative.class.getName()).log(Level.SEVERE, null, ex); } catch (PGPException ex) { Logger.getLogger(FTPClient_alternative.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. try { // Skips. inputStream.skip(streamOffset); // Opens the data transfer connection. dataTransferOutputStream = dtConnection.getOutputStream(); // TCP or UDT - automatically // MODE Z enabled? if (modezEnabled) { // don't use with PGP stream dataTransferOutputStream = new DeflaterOutputStream(dataTransferOutputStream); } // 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(); } // 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; 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(FTPClient_alternative.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); writer.write(buffer__); baos.reset(); } else { // Write directly to socket writer.write(buffer, 0, l); } 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 = ""; if (md5sum != null) 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 --------------------- byte[] buffer = new byte[SEND_AND_RECEIVE_BUFFER_SIZE]; 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(FTPClient_alternative.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 while ((l = inputStream.read(buffer)) != -1) { // The actual data transfer loop ------------------- if (this.pgKey != null) { literalOut.write(buffer, 0, l); // Write to mem buffer literalOut.flush(); byte[] buffer_ = baos.toByteArray(); // retrieve that buffer crypt_digest.update(buffer_); // update crypto MD5 dataTransferOutputStream.write(buffer_); // Write cipher data to socket c += buffer_.length; baos.reset(); // empty mem buffer } else { dataTransferOutputStream.write(buffer, 0, l); // no cipher -- write directly to socket c += buffer.length; } 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); } } // Get a representation of the MD5 digest (checksum) plain file byte[] md5sum = digest.digest(); result = ""; if (md5sum != null) 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 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); complete = true; } } catch (Throwable e) { if (listener != null) { listener.aborted(); } complete = false; try { throw new FTPDataTransferException("I/O error in data transfer", e); } catch (FTPDataTransferException ex) { Logger.getLogger(UploadClient.class.getName()).log(Level.SEVERE, null, ex); } } completed = true; } public String get_md5() { return this.result; } public String get_crypto_md5() { return this.result1; } public long get_c() { return this.c; } public boolean complete() { return this.complete; } public boolean isComplete() { return this.completed; } public void cleanup() { try { if (dataTransferOutputStream != null) dataTransferOutputStream.close(); if (dtConnection != null) dtConnection.close(); } catch (IOException ex) { Logger.getLogger(UploadClient.class.getName()).log(Level.SEVERE, null, ex); } if (listener != null) { listener.aborted(); } } 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; } }