0

i am working on a project in java that transfers files from a client to a server. now i need to show the progress bar for each file transfer i.e the progress bar should automatically pop up as each transfer starts. i have made the program to create a progress bar but i am not able to merge it with the client-server programs. i would really appreciate if someone helps me with the loop to be used. thank you.

ClientMain.java

public class ClientMain {
private DirectoryTxr transmitter = null;
Socket clientSocket = null;
private boolean connectedStatus = false;
private String ipAddress;
String srcPath = null;
String dstPath = "";
public ClientMain() {

}

public void setIpAddress(String ip) {
    this.ipAddress = ip;
}

public void setSrcPath(String path) {
    this.srcPath = path;
}

public void setDstPath(String path) {
    this.dstPath = path;
}

private void createConnection() {
    Runnable connectRunnable = new Runnable() {
        public void run() {
            while (!connectedStatus) {
                try {
                    clientSocket = new Socket(ipAddress, 3339);
                    connectedStatus = true;
                    transmitter = new DirectoryTxr(clientSocket, srcPath, dstPath);
                } catch (IOException io) {
                    io.printStackTrace();
                }
            }

        }
    };
    Thread connectionThread = new Thread(connectRunnable);
    connectionThread.start();
}

DirectoryTxr.java

import java.io.*;
import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class DirectoryTxr {
    Socket clientSocket = null;
    String srcDir = null;
    String dstDir = null;
    byte[] readBuffer = new byte[1024];
    private InputStream inStream = null;
    private OutputStream outStream = null;
    int state = 0;
    final int permissionReqState = 1;
    final int initialState = 0;
    final int dirHeaderSendState = 2;
    final int fileHeaderSendState = 3;
    final int fileSendState = 4;
    final int fileFinishedState = 5;
    private boolean isLive = false;
    private int numFiles = 0;
    private int filePointer = 0;
    String request = "May I send?";
    String respServer = "Yes,You can";
    String dirResponse = "Directory created...Please send files";
    String fileHeaderRecvd = "File header received ...Send File";
    String fileReceived = "File Received";
    String dirFailedResponse = "Failed";
    File[] opFileList = null;

    public DirectoryTxr(Socket clientSocket, String srcDir, String dstDir) {

        try {
            this.clientSocket = clientSocket;
            inStream = clientSocket.getInputStream();
            outStream = clientSocket.getOutputStream();
            isLive = true;
            this.srcDir = srcDir;
            this.dstDir = dstDir;
            state = initialState;
            readResponse(); //starting read thread
            sendMessage(request);
            state = permissionReqState;
        } catch (IOException io) {
            io.printStackTrace();
        }


    }

    private void sendMessage(String message) {
        try {
            sendBytes(request.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }


    /**
     * Thread to read response from server
     */
    private void readResponse() {
        Runnable readRunnable = new Runnable() {
            public void run() {
                while (isLive) {
                    try {
                        int num = inStream.read(readBuffer);
                        if (num > 0) {
                            byte[] tempArray = new byte[num];
                            System.arraycopy(readBuffer, 0, tempArray, 0, num);
                            processBytes(tempArray);
                        }
                    } catch (SocketException se) {
                        System.exit(0);
                    } catch (IOException io) {
                        io.printStackTrace();
                        isLive = false;
                    }
                }
            }
        };
        Thread readThread = new Thread(readRunnable);
        readThread.start();

    }

    private void sendDirectoryHeader() {
        File file = new File(srcDir);
        if (file.isDirectory()) {
            try {
                String[] childFiles = file.list();
                numFiles = childFiles.length;
                String dirHeader = "$" + dstDir + "#" + numFiles + "&";
                sendBytes(dirHeader.getBytes("UTF-8"));
            } catch (UnsupportedEncodingException en) {
                en.printStackTrace();
            }
        } else {
            System.out.println(srcDir + " is not a valid directory");
        }
    }


    private void sendFile(String dirName) {
        File file = new File(dirName);

        if (!file.isDirectory()) {
            try {
                int len = (int) file.length();
                int buffSize = len / 8;
                //to avoid the heap limitation
                RandomAccessFile raf = new RandomAccessFile(file, "rw");
                FileChannel channel = raf.getChannel();

                int numRead = 0;
                while (numRead >= 0) {
                    ByteBuffer buf = ByteBuffer.allocate(1024 * 100000);
                    numRead = channel.read(buf);
                    if (numRead > 0) {
                        byte[] array = new byte[numRead];
                        System.arraycopy(buf.array(), 0, array, 0, numRead);
                        sendBytes(array);
                    }
                }
                System.out.println("Finished");

            } catch (IOException io) {
                io.printStackTrace();
            }

        }

    }

    private void sendHeader(String fileName) {
        try {
            File file = new File(fileName);
            if (file.isDirectory())
                return;//avoiding child directories to avoid confusion
            //if want we can sent them recursively
            //with proper state transitions

            String header = "&" + fileName + "#" + file.length() + "*";
            sendHeader(header);

            sendBytes(header.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    private void sendBytes(byte[] dataBytes) {
        synchronized (clientSocket) {
            if (outStream != null) {
                try {
                    outStream.write(dataBytes);
                    outStream.flush();
                } catch (IOException io) {
                    io.printStackTrace();
                }
            }
        }

    }

    private void processBytes(byte[] data) {
        try {
            String parsedMessage = new String(data, "UTF-8");
            System.out.println(parsedMessage);
            setResponse(parsedMessage);
        } catch (UnsupportedEncodingException u) {
            u.printStackTrace();
        }
    }

    private void setResponse(String message) {
        if (message.trim().equalsIgnoreCase(respServer) && state == permissionReqState) {
            state = dirHeaderSendState;
            sendDirectoryHeader();


        } else if (message.trim().equalsIgnoreCase(dirResponse) && state == dirHeaderSendState) {
            state = fileHeaderSendState;
            if (LocateDirectory()) {
                createAndSendHeader();
            } else {
                System.out.println("Vacant or invalid directory");
            }


        } else if (message.trim().equalsIgnoreCase(fileHeaderRecvd) && state == fileHeaderSendState) {
            state = fileSendState;
            sendFile(opFileList[filePointer].toString());
            state = fileFinishedState;
            filePointer++;

        } else if (message.trim().equalsIgnoreCase(fileReceived) && state == fileFinishedState) {
            if (filePointer < numFiles) {
                createAndSendHeader();
            }
            System.out.println("Successfully sent");

        } else if (message.trim().equalsIgnoreCase(dirFailedResponse)) {
            System.out.println("Going to exit....Error ");
            // System.exit(0);
        } else if (message.trim().equalsIgnoreCase("Thanks")) {
            System.out.println("All files were copied");
        }

    }

    private void closeSocket() {
        try {
            clientSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    private boolean LocateDirectory() {
        boolean status = false;
        File file = new File(srcDir);
        if (file.isDirectory()) {
            opFileList = file.listFiles();
            numFiles = opFileList.length;
            if (numFiles <= 0) {
                System.out.println("No files found");
            } else {
                status = true;
            }

        }
        return status;
    }

    private void createAndSendHeader() {
        File opFile = opFileList[filePointer];
        String header = "&" + opFile.getName() + "#" + opFile.length() + "*";
        try {
            state = fileHeaderSendState;
            sendBytes(header.getBytes("UTF-8"));

        } catch (UnsupportedEncodingException e) {

        }
    }

    private void sendListFiles() {
        createAndSendHeader();

    }
}

ServerMain.java

public class ServerMain {

    public ServerMain() {

    }

    public static void main(String[] args) {

        DirectoryRcr dirRcr = new DirectoryRcr();

    }
}

DirectoryRcr.java

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;


public class DirectoryRcr {

    String request = "May I send?";
    String respServer = "Yes,You can";
    String dirResponse = "Directory created...Please send files";
    String dirFailedResponse = "Failed";
    String fileHeaderRecvd = "File header received ...Send File";
    String fileReceived = "File Received";
    Socket socket = null;
    OutputStream ioStream = null;
    InputStream inStream = null;
    boolean isLive = false;
    int state = 0;
    final int initialState = 0;
    final int dirHeaderWait = 1;
    final int dirWaitState = 2;
    final int fileHeaderWaitState = 3;
    final int fileContentWaitState = 4;
    final int fileReceiveState = 5;
    final int fileReceivedState = 6;
    final int finalState = 7;
    byte[] readBuffer = new byte[1024 * 100000];
    long fileSize = 0;
    String dir = "";
    FileOutputStream foStream = null;
    int fileCount = 0;
    File dstFile = null;

    public DirectoryRcr() {
        acceptConnection();
    }

    private void acceptConnection() {
        try {
            ServerSocket server = new ServerSocket(3339);
            socket = server.accept();
            isLive = true;
            ioStream = socket.getOutputStream();
            inStream = socket.getInputStream();
            state = initialState;
            startReadThread();

        } catch (IOException io) {
            io.printStackTrace();
        }
    }

    private void startReadThread() {
        Thread readRunnable = new Thread() {
            public void run() {
                while (isLive) {
                    try {
                        int num = inStream.read(readBuffer);
                        if (num > 0) {
                            byte[] tempArray = new byte[num];
                            System.arraycopy(readBuffer, 0, tempArray, 0, num);
                            processBytes(tempArray);
                        }
                        sleep(100);

                    } catch (SocketException s) {

                    } catch (IOException e) {
                        e.printStackTrace();
                    } catch (InterruptedException i) {
                        i.printStackTrace();
                    }
                }
            }
        };
        Thread readThread = new Thread(readRunnable);
        readThread.start();
    }

    private void processBytes(byte[] buff) throws InterruptedException {
        if (state == fileReceiveState || state == fileContentWaitState) {
            //write to file
            if (state == fileContentWaitState)
                state = fileReceiveState;
            fileSize = fileSize - buff.length;
            writeToFile(buff);


            if (fileSize == 0) {
                state = fileReceivedState;
                try {
                    foStream.close();
                } catch (IOException io) {
                    io.printStackTrace();
                }
                System.out.println("Received " + dstFile.getName());
                sendResponse(fileReceived);
                fileCount--;
                if (fileCount != 0) {
                    state = fileHeaderWaitState;
                } else {
                    System.out.println("Finished");
                    state = finalState;
                    sendResponse("Thanks");
                    Thread.sleep(2000);
                    System.exit(0);
                }

                System.out.println("Received");
            }
        } else {
            parseToUTF(buff);
        }

    }

    private void parseToUTF(byte[] data) {
        try {
            String parsedMessage = new String(data, "UTF-8");
            System.out.println(parsedMessage);
            setResponse(parsedMessage);
        } catch (UnsupportedEncodingException u) {
            u.printStackTrace();
        }

    }

    private void setResponse(String message) {
        if (message.trim().equalsIgnoreCase(request) && state == initialState) {
            sendResponse(respServer);
            state = dirHeaderWait;

        } else if (state == dirHeaderWait) {
            if (createDirectory(message)) {
                sendResponse(dirResponse);
                state = fileHeaderWaitState;
            } else {
                sendResponse(dirFailedResponse);
                System.out.println("Error occurred...Going to exit");
                System.exit(0);
            }


        } else if (state == fileHeaderWaitState) {
            createFile(message);
            state = fileContentWaitState;
            sendResponse(fileHeaderRecvd);

        } else if (message.trim().equalsIgnoreCase(dirFailedResponse)) {
            System.out.println("Error occurred ....");
            System.exit(0);
        }

    }

    private void sendResponse(String resp) {
        try {
            sendBytes(resp.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    private boolean createDirectory(String dirName) {
        boolean status = false;
        dir = dirName.substring(dirName.indexOf("$") + 1, dirName.indexOf("#"));
        fileCount = Integer.parseInt(dirName.substring(dirName.indexOf("#") + 1, dirName.indexOf("&")));
        if (new File(dir).mkdir()) {
            status = true;
            System.out.println("Successfully created directory  " + dirName);
        } else if (new File(dir).mkdirs()) {
            status = true;
            System.out.println("Directories were created " + dirName);

        } else if (new File(dir).exists()) {
            status = true;
            System.out.println("Directory exists" + dirName);
        } else {
            System.out.println("Could not create directory " + dirName);
            status = false;
        }

        return status;
    }

    private void createFile(String fileName) {

        String file = fileName.substring(fileName.indexOf("&") + 1, fileName.indexOf("#"));
        String lengthFile = fileName.substring(fileName.indexOf("#") + 1, fileName.indexOf("*"));
        fileSize = Integer.parseInt(lengthFile);
        dstFile = new File(dir + "/" + file);
        try {
            foStream = new FileOutputStream(dstFile);
            System.out.println("Starting to receive " + dstFile.getName());
        } catch (FileNotFoundException fn) {
            fn.printStackTrace();
        }

    }

    private void writeToFile(byte[] buff) {
        try {
            foStream.write(buff);
        } catch (IOException io) {
            io.printStackTrace();
        }
    }

    private void sendBytes(byte[] dataBytes) {
        synchronized (socket) {
            if (ioStream != null) {
                try {
                    ioStream.write(dataBytes);
                } catch (IOException io) {
                    io.printStackTrace();
                }
            }
        }

    }

the client application contains two classes ClientMain.java and DirectoryTxr.java the server application contains two classes ServerMain.java and DirectoryRcr.java

also my code to create a progress bar is

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;

public class ProgressBar extends JFrame {
 JProgressBar current = new JProgressBar(0, 2000);
 int num = 0;

 public ProgressBar() {
  //exit button
  setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  //create the panel to add the details
  JPanel pane = new JPanel();
  current.setValue(0);
  current.setStringPainted(true);
  pane.add(current);
  setContentPane(pane);
 }

 //to iterate so that it looks like progress bar  
 public void iterate() {
  while (num < 2000) {
   current.setValue(num);
   try {
    Thread.sleep(1000);
   } catch (InterruptedException e) {
   }
   num += 95;
  }
 }

 //for testing the app
 public static void main(String[] arguments) {
  ProgressBar frame = new ProgressBar();
  frame.pack();
  frame.setVisible(true);
  frame.iterate();
 }
}
trisha mehta
  • 11
  • 1
  • 3

2 Answers2

2

Check out the ProgressMonitorInputStream from the Swing tutorial on Using Progress Bars.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • thank you @camickr. but i have already written the code to create a progress bar but i am having problem in creating the loop in the client program that will contain this code.i don't know where and how to create the loop. i am new to coding so i am facing problems. – trisha mehta Jun 14 '13 at 05:14
  • Swing doesn't need a loop (it has it's own). You need some way to tell the UI that a progress update has occured – MadProgrammer Jun 14 '13 at 05:16
  • so how do i merge both the programs? – trisha mehta Jun 14 '13 at 05:26
1

Swing is a single threaded framework. That means that all interactions with the UI are expected to be made within the context of this thread (AKA The Event Dispatching Thread).

This also means that if you performing any kind of time consuming/long running or blocking process within the EDT, you will prevent it from responding to events or updating the UI.

This is what your code is currently doing.

There are a number of mechanism available to you to over come this, in your case, the simplest is probably to use a SwingWorker

import java.awt.EventQueue;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ProgressBar extends JFrame {

    JProgressBar current = new JProgressBar(0, 100);
    int num = 0;

    public ProgressBar() {
        //exit button
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //create the panel to add the details
        JPanel pane = new JPanel();
        current.setValue(0);
        current.setStringPainted(true);
        pane.add(current);
        setContentPane(pane);
    }

    //to iterate so that it looks like progress bar  
    public void iterate() {
        SwingWorker worker = new SwingWorker<Object, Object>() {
            @Override
            protected Object doInBackground() throws Exception {
                while (num < 2000) {
//                    current.setValue(num);
                    try {
                        Thread.sleep(125);
                    } catch (InterruptedException e) {
                    }
                    num += 95;
                    int p = Math.round(((float)Math.min(num, 2000) / 2000f) * 100f);
                    setProgress(p);
                }
                return null;
            }
        };
        worker.addPropertyChangeListener(new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                String name = evt.getPropertyName();
                if ("progress".equals(name)) {
                    SwingWorker worker = (SwingWorker) evt.getSource();
                    current.setValue(worker.getProgress());
                }
            }
        });
        worker.execute();
    }

    //for testing the app
    public static void main(String[] arguments) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                ProgressBar frame = new ProgressBar();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
                frame.iterate();
            }
        });
    }
}

Check out http://docs.oracle.com/javase/tutorial/uiswing/concurrency/ for more details.

Updated with example of dual welding progress bars

If you need to display more then one progress bat, you can simply use the publish and process methods of SwingWorker to accomplish more complex results...

enter image description here

import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

 */
public class ProgressBar extends JFrame {

    JProgressBar current = new JProgressBar(0, 100);
    JProgressBar overall = new JProgressBar(0, 100);
    int num = 0;

    public ProgressBar() {
        //exit button
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //create the panel to add the details
        JPanel pane = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        current.setValue(0);
        current.setStringPainted(true);
        overall.setStringPainted(true);
        pane.add(overall, gbc);
        pane.add(current, gbc);
        setContentPane(pane);
    }

    //to iterate so that it looks like progress bar  
    public void iterate() {
        SwingWorker worker = new SwingWorker<Object, float[]>() {

            @Override
            protected void process(List<float[]> chunks) {
                float[] progress = chunks.get(chunks.size() - 1); // only want the last one
                overall.setValue(Math.round(progress[0] * 100f));
                current.setValue(Math.round(progress[1] * 100f));
            }

            @Override
            protected Object doInBackground() throws Exception {
                int size = 2000;
                int overallSize = size * 10;
                int overallProgress = 0;
                for (int index = 0; index < 10; index++) {
                    for (int count = 0; count < size; count++) {
                        publish(new float[]{
                            getProgress(overallProgress, overallSize),
                            getProgress(count, size),
                        });
                        overallProgress++;
                        Thread.sleep(2);
                    }
                }
                return null;
            }

            public float getProgress(int value, int max) {

                return (float)value / (float)max;

            }
        };
        worker.execute();
    }

    //for testing the app
    public static void main(String[] arguments) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                ProgressBar frame = new ProgressBar();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
                frame.iterate();
            }
        });
    }
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • thank you.i have run the code.this is perfectly working. but this is only showing a progress bar for the cumulative transfer of all the files. i want to show the progress bar individually for each file when i am transferring multiple files. – trisha mehta Jun 14 '13 at 06:04
  • So, create two progress bars...You can use the `SwingWorker#publish` and `SwingWorker#process` methods to update the UI instead. – MadProgrammer Jun 14 '13 at 06:07
  • can you please elaborate a little. actually i am transferring a whole folder containing multiple files at once. now i want the progress bar to automatically pop up for each file as they start their transfer. – trisha mehta Jun 14 '13 at 06:16
  • I've add an updated example showing the use of two progress bars. If you still only wanted to show one, you would simply use the "overall" part of the code instead – MadProgrammer Jun 14 '13 at 06:18
  • this code is perfect but i am observing a problem here which is that the command prompt is showing the completion of the file transfer but the progress bar is lacking a lot behind. for eg. m getting the finished messages individually for all the files as soon as i run the programs in command prompts. but the progress bars are still going on. both the process should move simultaneously which is not happening. – trisha mehta Jun 14 '13 at 06:43
  • removing the Thread.sleep is not helping much. on removing its directly showing 100% and on keeping it as it is , its taking a lot of time updating itself. – trisha mehta Jun 14 '13 at 07:08
  • Have you actually linked the download code to the progress code, so that the `SwingWorker` is actually responding what is happening in the download classes? – MadProgrammer Jun 14 '13 at 07:12
  • i have made the ProgressBar.java class which is a part of my ClientMain.java application. the main() of ProgressBar.java is contained in the ClientMain.java class. and so m running in command prompt the ClientMain.java – trisha mehta Jun 14 '13 at 07:22
  • i have made the classes DirectoryTxr.java, ProgressBar.java and ClientMain.java all a part of the same package. how should i link it with the transfer process? – trisha mehta Jun 14 '13 at 07:25
  • You need some way for the client class doing the transfer (or server class if you're so inclined) to provide feedback to the `SwingWorker`, which can the `publish` the details back to the UI – MadProgrammer Jun 15 '13 at 01:31
  • my progress bar is working on random numbers, not the actual file size. how to make it a function of bytes sent so that it will sync it with the progress and update the progress bar periodically as it is? how do i predetermine the file size? – trisha mehta Jun 17 '13 at 04:49
  • You need to modify your protocol so it can 1- send the total number of expected bytes (for all the files) and 2- the size of the file about to be sent – MadProgrammer Jun 17 '13 at 05:04
  • how to predetermine the file size ? because every time i sent some file it may be of different size. – trisha mehta Jun 17 '13 at 05:08
  • Your protocol should using `File#length` to send the client the expected number of bytes it's about to send. Aspart of the protocol, you would need to build a file list and calculate the total number of bytes that are going to be sent. That way, each time you read a different directory, the protocol will be telling you what to expect – MadProgrammer Jun 17 '13 at 05:14
  • can you please share the code. because when i tried doing it i am getting nowhere. besides m not getting in which part of the client application i should invoke the code and how. being a newbie m facing these problems. – trisha mehta Jun 19 '13 at 09:00