uk.ac.ebi.enaega.uploadclient.UploadClient.java Source code

Java tutorial

Introduction

Here is the source code for uk.ac.ebi.enaega.uploadclient.UploadClient.java

Source

/*
 * 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;
    }
}