Page 1 of 2 12 LastLast
Results 1 to 20 of 21
  1. #1
    unaligned is offline Member
    Join Date
    Jun 2011
    Posts
    23
    Rep Power
    0

    Default Concurrently writing to a JComponent

    Greetings. I'll get right to it. I'm writing a program where several threads (each thread is one instance of a data processing procedure, and there are an undetermined number that need to execute, though a maximum of 2 will ever be executing simultaneously) need to write to a shared console (JTextArea) indicating something has happened in that thread's execution. Along with this, indicators such as JLabels and JProgressBars also need to update with information showing how far along the overall process is (how many procedures are waiting to execute, the current status of the overall execution, and the overall percentage complete). However, I'm having issues with the concurrency of the threads and getting these components to update. What happens is that each component waits until the overall completion has ended before it updates, so the indicators are basically useless.

    To this end, I have constructed an example with just the console. This code is displayed below. It is meant to provide an idea of what I'm doing, as well as show my logic as to what I believe it's doing. What I believe it should do, it is not doing, and that is where I need help. Basically, I create 3 threads that I want to print a simple message to the console in intervals of 2 seconds. However, what happens is that each thread waits for the execution of the other threads to complete, and they all print at the same time.

    My question is, what is flawed about this? Is it my logic or is concurrency defeating me? Any insight into this would be greatly apprciated. Thanks in advance.

    Java Code:
    import java.awt.BorderLayout;
    import java.awt.Container;
    import java.awt.FlowLayout;
    import java.awt.Font;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTextArea;
    
    public class ConTesting {
    
    	static JTextArea console = new JTextArea();
    
    	public static void main(String[] args) {
    		ConTesting test = new ConTesting();
    		test.setup();
    	}
    
    	public void setup() {
    		JFrame frame = new JFrame();
    		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		frame.setLayout(new BorderLayout());
    		frame.setSize(500, 400);
    		frame.setTitle("Activity Console - UL/DL Execution Progress");
    		frame.setResizable(false);
    		frame.setLocation(1700, 200);
    		Container pane = frame.getContentPane();
    
    		JPanel progPanel = new JPanel();
    		progPanel.setLayout(new FlowLayout());
    		final JButton exButton = new JButton("Start");
    		exButton.addActionListener(new ActionListener() {
    
    			@Override
    			public void actionPerformed(ActionEvent arg0) {
    				execute();
    			}
    		});
    
    		final JButton clButton = new JButton("Clear");
    		clButton.addActionListener(new ActionListener() {
    
    			@Override
    			public void actionPerformed(ActionEvent arg0) {
    				console.setText("");
    			}
    		});
    
    		progPanel.add(exButton);
    		progPanel.add(clButton);
    
    		console = new JTextArea();
    		console.setEditable(false);
    		console.setFont(new Font("Courier", Font.PLAIN, 11));
    		JScrollPane consolePane = new JScrollPane(console);
    
    		pane.add(consolePane, "Center");
    		pane.add(progPanel, "South");
    		frame.setVisible(true);
    
    	}
    
    	public static void writeToConsole(String message) {
    		if (!message.equals(""))
    			console.append(message);
    	}
    
    	public void execute() {
    		for (int i = 0; i < 3; i++) {
    			
    			Worker w = new Worker();
    			Thread t = new Thread(w);
    			t.start();
    			
    			try {
    				Thread.sleep(2000);
    			} catch (Exception e){}
    			
    		}			
    	}
    
    	private class Worker implements Runnable {
    
    		@Override
    		public void run() {
    			try {
    				long time =  System.nanoTime();
    				Thread t = Thread.currentThread();
    				writeToConsole("This is " + t.getName() + " being printed; Time: " + time + "\n");
    			} catch (Exception e) {
    			}
    		}
    	}
    }

  2. #2
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    You're calling Thread.sleep(...) in Swing's event thread, the EDT, so it's not surprising that the GUI will become unresponsive. Solution: don't do that. Consider doing that in a background thread such as with a SwingWorker, or using a Swing Timer if all you need to do is to delay the action of something.

  3. #3
    unaligned is offline Member
    Join Date
    Jun 2011
    Posts
    23
    Rep Power
    0

    Default

    Well, this is just an example, and I'm not necessarily talking about having a problem with it becoming unresponsive (though I would like to fix that as well). My logic was that the Sleep call would wait 2 seconds before proceeding to executing the next thread, effectively creating a 2 second interval between console prints. But like I said, they all wait until all are done executing before they print.

  4. #4
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    Quote Originally Posted by unaligned View Post
    Well, this is just an example, and I'm not necessarily talking about having a problem with it becoming unresponsive (though I would like to fix that as well). My logic was that the Sleep call would wait 2 seconds before proceeding to executing the next thread, effectively creating a 2 second interval between console prints. But like I said, they all wait until all are done executing before they print.
    But that's entirely the problem -- your gui is not displaying anything because you are not doing threading properly and you are putting your GUI to sleep.

    Please see this link for more: Lesson: Concurrency in Swing (The Java™ Tutorials > Creating a GUI With JFC/Swing)

  5. #5
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    For example (quick and dirty):

    Java Code:
    import java.awt.*;
    import java.awt.event.*;
    import java.util.List;
    import javax.swing.*;
    
    @SuppressWarnings("serial")
    public class ConTesting2 extends JPanel {
       private JTextArea textArea = new JTextArea(25, 50);
    
       public ConTesting2() {
          JPanel buttonPanel = new JPanel();
          buttonPanel.add(new JButton(new StartAction1()));
          buttonPanel.add(new JButton(new StartAction2()));
          buttonPanel.add(new JButton(new ClearAction()));
          
          setLayout(new BorderLayout());
          add(new JScrollPane(textArea), BorderLayout.CENTER);
          add(buttonPanel, BorderLayout.SOUTH);
       }
    
       public void appendText(String text) {
          textArea.append(text);
       }
    
       private class StartAction1 extends AbstractAction {
          protected static final int MAX_COUNT = 3;
    
          public StartAction1() {
             super("Start 1: Timer");
          }
    
          public void actionPerformed(ActionEvent e) {
             int timerDelay = 2000;
             new Timer(timerDelay, new ActionListener() {
                private int count = 0;
    
                @Override
                public void actionPerformed(ActionEvent e) {
                   if (count < MAX_COUNT) {
                      new Thread(new Runnable() {
                         public void run() {
                            long time = System.nanoTime();
                            Thread t = Thread.currentThread();
                            final String text = "This is " + t.getName()
                                  + " being printed; Time: " + time + "\n";
                            SwingUtilities.invokeLater(new Runnable() {
                               public void run() {
                                  appendText(text);
                               }
                            });
                         }
                      }).start();
                      count++;
                   } else {
                      ((Timer) e.getSource()).stop();
                   }
                }
             }).start();
          }
       }
    
       private class StartAction2 extends AbstractAction {
          protected static final long SLEEP_TIME = 2000;
    
          public StartAction2() {
             super("Start 2: SwingWorker");
          }
    
          public void actionPerformed(ActionEvent e) {
             new SwingWorker<Void, String>() {
                @Override
                protected Void doInBackground() throws Exception {
                   for (int i = 0; i < 3; i++) {
                      Thread.sleep(SLEEP_TIME);
                      long time = System.nanoTime();
                      Thread t = Thread.currentThread();
                      String text = "This is " + t.getName()
                            + " being printed; Time: " + time + "\n";
    
                      publish(text);
                   }
                   return null;
                }
                
                @Override
                protected void process(List<String> chunks) {
                   for (String chunk : chunks) {
                      appendText(chunk);
                   }
                }
             }.execute();
          }
       }
    
       private class ClearAction extends AbstractAction {
          public ClearAction() {
             super("Clear");
          }
    
          public void actionPerformed(ActionEvent e) {
             textArea.setText("");
          }
       }
    
       private static void createAndShowGui() {
          JFrame frame = new JFrame("ConTesting 2");
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.getContentPane().add(new ConTesting2());
          frame.pack();
          frame.setLocationRelativeTo(null);
          frame.setVisible(true);
       }
    
       public static void main(String[] args) {
          SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                createAndShowGui();
             }
          });
       }
    }

  6. #6
    unaligned is offline Member
    Join Date
    Jun 2011
    Posts
    23
    Rep Power
    0

    Default

    Quote Originally Posted by Fubarable View Post
    But that's entirely the problem -- your gui is not displaying anything because you are not doing threading properly and you are putting your GUI to sleep.

    Please see this link for more: Lesson: Concurrency in Swing (The Java™ Tutorials > Creating a GUI With JFC/Swing)
    Good call. I'll try that.

  7. #7
    unaligned is offline Member
    Join Date
    Jun 2011
    Posts
    23
    Rep Power
    0

    Default

    Quote Originally Posted by Fubarable View Post
    For example (quick and dirty):
    Thank you very much, this helped immensely.

  8. #8
    d3n1s is offline Member
    Join Date
    Apr 2011
    Posts
    69
    Rep Power
    0

    Default

    Take note of the SwingUtilities.invokeLater() call. Anytime you update a component, always do it this way. This will have the main thread process it instead of whatever thread you are calling from.

  9. #9
    unaligned is offline Member
    Join Date
    Jun 2011
    Posts
    23
    Rep Power
    0

    Default

    Ok, doing what has been suggested I have fixed the lockup of the UI. However, I still cannot get the progress indicators to update (updateProgressIndicators()) with every 'activity' that occurs (I've inserted several calls to this just for testing purposes). It updates the first time through the loop, but never again after that. The progress indicators include a JTextArea that is the 'console', a JLabel showing how many items are left in the queue, and a JProgressBar showing percent complete.

    In addition, it also still completely executes one activity before moving to the next, which is not how I want it to work. I want a maximum of 2 instances of SCPActivity to be executing at a given time. An SCPActivity is just a file download or upload automated through WinSCP's command-line interface. To do this, I create a process using a Runtime.exec() call to the cmd.exe program. I also pull off this process's stdout stream so that I can print it to the console when it has completed.

    Basically, I want to go thorugh the loop and create a new thread for a new activity if less than 2 instances of winscp.com are currently executing, and wait if there are 2 or more, with each thread updating the progress indicators whenever it finishes. Also, it continues to loop even after the while loop ends and I don't really understand why. Does it have something to do with being in a run() call?

    Any ideas?

    The code I have for a 'StartAction' inner class is as follows (sorry for the mess, it's deep):

    Java Code:
    	
    
    private class StartAction extends AbstractAction {
    
    public StartAction() {
    	super("Execute");
    }
    
    @Override
    public void actionPerformed(ActionEvent e) {
    	if (queue.size() > 0) {
    
    		new SwingWorker<Void, String>() {
    
    			public Void doInBackground() {
    						
    				while (true) {
    							
    					if (queue.size() <= 0)
    						break;
    						new Thread(new Runnable() {
    								
    						@Override
    						public void run() {
    							updateProgressIndicators();															SwingUtilities.invokeLater(new Runnable() {
    									
    								@Override
    								public void run() {
    
    									int instances = Utilities.getNumberOfProcesses("winscp.com");
    											
    									System.out.println("WinSCP instances: " + instances);
    									System.out.println("Remaining: " + remaining);
    
    									if (instances < 2 && queue.size() > 0) {
    										SCPActivity act = queue.pop();
    										act.execute();
    										InputStream stream = act.getStream();
    										console.append("File '" + act.getFilename() + "' " + 
    											act.getType() + " initiated..." + newline);
    										String line;
    												
    										BufferedReader reader = new BufferedReader(new 														InputStreamReader(stream));
    
    										try {
    
    											line = reader.readLine();
    											while (!line.contains("Active session:")) {
    												line = reader.readLine();
    											}
    													
    											line = reader.readLine();
    											console.append(line + newline + newline);
    											remaining--;
    											updateProgressIndicators();
    
    										} catch (IOException e1) {
    											e1.printStackTrace();
    										}
    									}
    								}
    							});
    						}
    					}).start();
    					updateProgressIndicators();
    				}
    				return null;
    			}
    		}.execute();
    	} else {				
    	writeToConsole("There are no activities in the queue. Please select modules to " +
    		 "execute or wait for" + newline + "the queue to populate." + newline);
    	}
    	}
    }
    Last edited by unaligned; 07-28-2011 at 07:02 PM. Reason: clarifications

  10. #10
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    I highly doubt that anyone will be able to make heads or tails out of the code you've posted, and I strongly urge you to put in the effort to create and post an SSCCE that demonstrates your problem (see the link). I don't think that it's asking too much, as I've already put in a similar effort to try to help you (see my code above for example).

  11. #11
    unaligned is offline Member
    Join Date
    Jun 2011
    Posts
    23
    Rep Power
    0

    Default

    Quote Originally Posted by Fubarable View Post
    I highly doubt that anyone will be able to make heads or tails out of the code you've posted, and I strongly urge you to put in the effort to create and post an SSCCE that demonstrates your problem (see the link). I don't think that it's asking too much, as I've already put in a similar effort to try to help you (see my code above for example).
    I was afraid this might be the case. I tried hard to explain it fully so that it was at least slightly understandable without the rest of the code, but I understand that there's no way anyone can truly know what I'm trying to do until they see it.

    As such, I will try to make one and post it on here, though it will not be for a few days as this is for work and I am off until Monday. I hope you're still still around when I post it next week. Thanks for the help, I greatly appreciate it.

  12. #12
    unaligned is offline Member
    Join Date
    Jun 2011
    Posts
    23
    Rep Power
    0

    Default

    Ok, here is an SSCCE for this project. I have changed the WinSCP portion of the original project to use ping instead, as it is conceptually the same idea as WinSCP in this context (executing a new process via command line to perform a procedure). This is why some of the files contain SCP in the classname.

    What I want it to do is update the console (JTextArea), which is the main window of the program, with the text resulting from the ping command, a JLabel showing status, and a JProgressBar showing progress. Currently they don't update at all, even when all tasks are complete.

    Additionally, I want each of these tasks to create a new thread so a maximum of 2 are executing simultaneously, though right now it completely goes through the loop for one task before moving on the the next. Also, I've noticed that after all tasks are completed, the program continues to loop even though queue.size() is 0, which is the loop break condition. I don't fully understand how this is all happening.

    *EDIT: this program will not run on a non-windows system because it utilizes several Windows-specific calls to execute the procedures (cmd.exe, tasklist.exe, ping.exe).
    Attached Files Attached Files
    Last edited by unaligned; 08-03-2011 at 09:42 PM.

  13. #13
    Norm's Avatar
    Norm is online now Moderator
    Join Date
    Jun 2008
    Location
    SW Missouri
    Posts
    17,421
    Rep Power
    25

    Default

    Its interesting that you have documented here what you want your code to do, but when I look in the code there are NO comments saying what the code is supposed to do.
    Why is that?

    Do you expect us to copy your comments from this thread into your code so that we know what the code is supposed to do?

  14. #14
    unaligned is offline Member
    Join Date
    Jun 2011
    Posts
    23
    Rep Power
    0

    Default

    Updated code with some changes and comments.

    EDIT: I missed an initialization,
    Java Code:
     String line
    at line 185 of ActivityQueue needs to be
    Java Code:
     String line = "";
    Apologies... I figured this would be better than reposting the entire code.
    Attached Files Attached Files
    Last edited by unaligned; 08-04-2011 at 04:24 PM.

  15. #15
    unaligned is offline Member
    Join Date
    Jun 2011
    Posts
    23
    Rep Power
    0

    Default

    Quote Originally Posted by unaligned View Post
    Updated code with some changes and comments.

    EDIT: I missed an initialization,
    Java Code:
     String line
    at line 185 of ActivityQueue needs to be
    Java Code:
     String line = "";
    Apologies... I figured this would be better than reposting the entire code.
    I noticed a bug so this time I will be reposting the entire code.
    Attached Files Attached Files

  16. #16
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    I've looked some at your code, and it's a bit much to digest during the work week, but one thing that strikes me as odd is that you seem to be trying to call code that takes a long time to run in the SwingWorker but on the event dispatch thread:

    e.g.,
    Java Code:
                new SwingWorker<Void, String>() {
    
                   public Void doInBackground() {
                      while (queue.size() > 0) {
                         new Thread(new Runnable() {
                            public void run() {
                               SwingUtilities.invokeLater(new Runnable() {
                                  public void run() {
                                     // *** this now is all run on the event dispatch thread ***
                                     // ...
                                     if (instances < 2 && queue.size() > 0) {
                                        SCPActivity act = queue.pop();
                                        act.execute(); // how long does this take?
                                        //...
                                        BufferedReader reader = new BufferedReader(
                                                 new InputStreamReader(stream));
    
                                        try {
                                           // *** this should freeze the EDT
                                           while (!reader.ready()) {
                                           }
                                           line = reader.readLine();
                                           while (!(line == null)) {
                                              console.append(line + newline
                                                       + newline);
                                              line = reader.readLine();
                                           }
                                           updateProgressIndicators();
                                        } catch (IOException e1) {
                                           e1.printStackTrace();
                                        }
                                     }
                                  }
                               });
                            }
                         }).start();
                      }
                      return null;
                   }
                }.execute();
    I may look at it more over the weekend, but would appreciate it if you could shrink it and simplify it greatly. Do that -- and then post the finished product here -- and you'll have a much greater chance of me or someone else looking at it in greater depth. Also, is this cross-posted elsewhere? Also, if you solve it yourself, please post that here asap so we don't spin our wheels on an already solved problem.

    Luck.

  17. #17
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    Edit: I was thinking along these lines for the SwingWorker:

    Java Code:
                new SwingWorker<Void, String>() {
                   private int taskCount = queue.size();
                   private CountDownLatch latch = new CountDownLatch(queue.size());
                   private ExecutorService pool = Executors
                            .newFixedThreadPool(taskCount);
    
                   @Override
                   protected Void doInBackground() throws Exception {
                      // if wanted to do tasks all at once
                      // Set<Future<String>> futures = new HashSet<Future<String>>(taskCount);
    
                      for (int i = 0; i < queue.size(); i++) {
                         MyTask task = new MyTask("My Task " + i, latch);
                         // futures.add(pool.submit(task)); // to do tasks all at once
                         publish(pool.submit(task).get()); // to do tasks one at a time
                      }
    
                      // to do tasks all at once
                      // for (Future<String> future : futures) {
                      // publish(future.get());
                      // }
                      
                      latch.await(); // wait for countdown to finish
                      return null;
                   }
    
                   @Override
                   protected void process(List<String> chunks) {
                      for (String chunk : chunks) {
                         updateProgressIndicators(taskCount, (int) latch.getCount());
                         console.append(chunk + "\n");
                      }
                   }
    
                   @Override
                   protected void done() {
                      updateProgressIndicators(taskCount, (int) latch.getCount());
                   }
                }.execute();

    And using a separate class to do most of the "innards" of the SwingWorker:

    Java Code:
    // test class just for demonstration purposes
    class MyTask implements Callable<String> {
       private String text;
       private CountDownLatch latch;
    
       public MyTask(String text, CountDownLatch latch) {
          this.text = text;
          this.latch = latch;
       }
    
       @Override
       public String call() throws Exception {
          Thread.sleep(4000);
          latch.countDown();
          return text;
       }
    }
    Requiring a change in updateProgressIndicators:

    Java Code:
       public void updateProgressIndicators(int totals, int count) {
          String status = "";
    
          int progress = Utilities.getPercentage(totals - count, totals);
    
          if (progress >= 100)
             status = "complete!";
          else
             status = "executing...";
    
          setProgLabel("Number of items in queue: " + queue.size() + " | Status: "
                   + status);
          pBar.setValue(progress);
       }

  18. #18
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    Not quite working yet, but almost:

    Java Code:
    import java.awt.BorderLayout;
    import java.awt.event.ActionEvent;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.beans.PropertyChangeSupport;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    import java.util.concurrent.Callable;
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    import javax.swing.*;
    import javax.swing.SwingWorker.StateValue;
    
    @SuppressWarnings("serial")
    public class ActivityQueue2 extends JPanel {
    
       // instance variables //
       private LinkedList<SCPActivity> queue; // the queue of activities that were
       // added to execute
       private JProgressBar pBar; // progress bar showing the overall progress of
       // the execution
       private JLabel progLabel; // label displaying the status of the execution and
       // the number of activities remaining
       private JTextArea console; // main window of the UI; output of the activities
       // will be printed here
       private static final String newline = "\n"; // IV used for a new line in the
       // console
       private int total; // the total number of activities that were added to the
    
       // queue
    
       /**
        * Constructor for the ActivityQueue, initializes the IVs
        * 
        * @param queue
        *           - an ArrayList from which the queue is built
        */
       public ActivityQueue2(ArrayList<SCPActivity> queue) {
          this.queue = new LinkedList<SCPActivity>();
    
          // initializes the counter used to update the progress indicators to 0.
          total = 0;
    
          // create and initialize the progress bar
          pBar = new JProgressBar(0, 100);
          pBar.setValue(0);
          pBar.setStringPainted(true);
    
          // initialize the console and the progress label
          progLabel = new JLabel("");
          console = new JTextArea(25, 50);
          console.setEditable(false);
    
          // add each item from the ArrayList to the queue
          for (SCPActivity act : queue) {
             addToQueue(act);
          }
    
          // initialize and set up the panel that holds the start
          // button, progress bar and progress label.
          JPanel buttonPanel = new JPanel();
          setLayout(new BorderLayout());
          buttonPanel.add(new JButton(new StartAction()));
          buttonPanel.add(progLabel);
          buttonPanel.add(pBar);
    
          // add the console and the button panel to the frame
          add(buttonPanel, BorderLayout.SOUTH);
          add(new JScrollPane(console), BorderLayout.CENTER);
       }
    
       /**
        * Method called in order to show the UI and set up the ActivityQueue
        * 
        * @param queue
        *           - ArrayList passed into the ActivityQueue constructor
        */
       public static void createAndShowGui(ArrayList<SCPActivity> queue) {
          JFrame frame = new JFrame("Activity Console");
          frame.getContentPane().add(new ActivityQueue2(queue));
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.setSize(750, 600);
          frame.pack();
          frame.setResizable(false);
          frame.setLocation(1700, 200);
          frame.setLocationRelativeTo(null);
          frame.setVisible(true);
       }
    
       /**
        * Adds the activity parameter to the queue if it doesn't already exist
        * 
        * @param activity
        *           - an activity that will be added to the queue
        */
       public void addToQueue(SCPActivity activity) {
          if (!queue.contains(activity)) {
    
             // the the queue doesn't contain the activity, it is added to the queue
             queue.add(activity);
    
             // updates the console to note that the activity was added
             writeToConsole("*" + activity.getActivityID() + " added to queue.");
    
             // increments the number of total activities in the queue
             total++;
          }
          // updates the progress label to indicate the number of activities in the
          // queue
          setProgLabel("Number of items in queue: " + queue.size()
                   + " | Status: waiting...");
       }
    
       /**
        * Updates all indicators that display the overall progress of the activity
        * execution
        * 
        * @param count
        * @param totals
        */
       public void updateProgressIndicators(int totals, int count) {
          String status = "";
    
          int progress = Utilities.getPercentage(totals - count, totals);
    
          if (progress >= 100)
             status = "complete!";
          else
             status = "executing...";
    
          setProgLabel("Number of items in queue: " + queue.size() + " | Status: "
                   + status);
          pBar.setValue(progress);
       }
    
       /**
        * Writes the provided message to the console then prints a new line
        * 
        * @param message
        *           - the message to print to the console
        */
       public void writeToConsole(String message) {
          if (!message.equals(""))
             console.append(message + newline);
       }
    
       /**
        * Sets the progress label to the value of 'message'
        * 
        * @param message
        *           - the message which to set the progress label
        */
       public void setProgLabel(String message) {
          if (!(message.equals("")))
             progLabel.setText(message);
       }
    
       /**
        * Private inner class that is used to execute the activities in the queue
        */
       private class StartAction extends AbstractAction {
          // constructor for StartAction - sets the name to 'Execute'.
          public StartAction() {
             super("Execute");
          }
    
          @Override
          public void actionPerformed(ActionEvent e) {
             if (queue.size() > 0) {
                new SwingWorker<Void, String>() {
                   private int taskCount = queue.size();
                   private CountDownLatch latch = new CountDownLatch(queue.size());
                   private ExecutorService pool = Executors
                            .newFixedThreadPool(taskCount);
                   private Map<MyTask, Future<String>> taskFutureMap = new HashMap<MyTask, Future<String>>();
    
                   @Override
                   protected Void doInBackground() throws Exception {
                      PropertyChangeListener myPropChngListener = new PropertyChangeListener() {
                         public void propertyChange(PropertyChangeEvent evt) {
                            String name = evt.getPropertyName();
                            SwingWorker.StateValue state = (StateValue) evt.getNewValue();
                            System.out.printf("property name: %s;  state value: %s%n", name, state);
                            if (name.equals(MyTask.STATE)
                                     && (state == SwingWorker.StateValue.DONE)) {
                               MyTask task = (MyTask) evt.getSource();
                               Future<String> future = taskFutureMap.get(task);
                               System.out.println("here 006");
                               try {
                                  String text = future.get();
                                  System.out.println("Text: " + text);
                                  publish(text);
                               } catch (InterruptedException e) {
                                  e.printStackTrace();
                               } catch (ExecutionException e) {
                                  e.printStackTrace();
                               }
                            }
                         }
                      };
    
                      while (queue.size() > 0) {
                         SCPActivity act = queue.pop();
                         MyTask task = new MyTask("My Task", latch, act);
                         task.addPropertyChangeListener(myPropChngListener);
                         taskFutureMap.put(task, pool.submit(task));
                      }
    
                      latch.await(); // wait for countdown to finish
                      return null;
                   }
    
                   @Override
                   protected void process(List<String> chunks) {
                      for (String chunk : chunks) {
                         updateProgressIndicators(taskCount, (int) latch.getCount());
                         console.append(chunk + "\n");
                      }
                   }
    
                   @Override
                   protected void done() {
                      updateProgressIndicators(taskCount, (int) latch.getCount());
                   }
    
                }.execute();
    
             } else {
                // note if there are no activities in the queue
                writeToConsole("There are no activities in the queue. Please select modules to "
                         + "execute or wait for"
                         + newline
                         + "the queue to populate." + newline);
             }
          }
       }
    
       public static void main(String[] args) {
    
          SwingUtilities.invokeLater(new Runnable() {
             public void run() {
    
                // create an ArrayList of activities and add them to the queue
                ArrayList<SCPActivity> q = new ArrayList<SCPActivity>();
                SCPping act = new SCPping("google.com");
                q.add(act);
                act = new SCPping("yahoo.com");
                q.add(act);
                act = new SCPping("facebook.com");
                q.add(act);
    
                createAndShowGui(q);
             }
          });
       }
    }
    
    // test class just for demonstration purposes
    class MyTask implements Callable<String> {
       public static final String STATE = "state";
       private String text;
       private CountDownLatch latch;
       private PropertyChangeSupport propChngSupport = new PropertyChangeSupport(
                this);
       private SwingWorker.StateValue state = SwingWorker.StateValue.PENDING;
       private SCPActivity act;
    
       public MyTask(String text, CountDownLatch latch, SCPActivity act) {
          this.text = text;
          this.latch = latch;
          this.act = act;
       }
    
       @Override
       public String call() throws Exception {
          setState(SwingWorker.StateValue.STARTED);
          System.out.println("here 004"); // !!
          // Thread.sleep(4000);
    
          while (state != SwingWorker.StateValue.DONE) {
             System.out.println("here 003"); // !!
             int instances = Utilities.getNumberOfProcesses("ping.exe");
             if (instances < 2) {
                act.execute();
                InputStream stream = act.getStream();
                String line = "";
    
                // create a new reader for the stream
                BufferedReader reader = new BufferedReader(new InputStreamReader(
                         stream));
    
                try {
                   System.out.println("here 001"); // !!
                   while (!reader.ready()) {
                   }
                   line = reader.readLine();
                   while (!(line == null)) {
                      text += " " + line;
                      line = reader.readLine();
                   }
    
                } catch (IOException e1) {
                   e1.printStackTrace();
                }
                System.out.println("here 002"); // !!
                latch.countDown();
                setState(SwingWorker.StateValue.DONE);
             }
          }
          // TODO: finish
          return text;
       }
    
       private void setState(SwingWorker.StateValue newValue) {
          SwingWorker.StateValue oldValue = this.state;
          this.state = newValue;
          PropertyChangeEvent evt = new PropertyChangeEvent(this, STATE, oldValue,
                   newValue);
          propChngSupport.firePropertyChange(evt);
       }
    
       public void addPropertyChangeListener(PropertyChangeListener listener) {
          propChngSupport.addPropertyChangeListener(listener);
       }
    
       public void removePropertyChangeListener(PropertyChangeListener listener) {
          propChngSupport.removePropertyChangeListener(listener);
       }
    }

  19. #19
    unaligned is offline Member
    Join Date
    Jun 2011
    Posts
    23
    Rep Power
    0

    Default

    Quote Originally Posted by Fubarable View Post
    Not quite working yet, but almost:

    I'm trying to wrap my head around what you've done - it actually completes and updates the indicators now which is a major step forward. I am going to try to figure out how to get the console to print the output from the ping calls.


    Quote Originally Posted by Fubarable View Post
    I may look at it more over the weekend, but would appreciate it if you could shrink it and simplify it greatly. Do that -- and then post the finished product here -- and you'll have a much greater chance of me or someone else looking at it in greater depth. Also, is this cross-posted elsewhere? Also, if you solve it yourself, please post that here asap so we don't spin our wheels on an already solved problem.
    I greatly appreciate the help you've given me and will continue to work on it. And no, this is the only place it's posted.
    Last edited by unaligned; 08-05-2011 at 04:07 PM.

  20. #20
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    Next incarnation: works better:

    Java Code:
    import java.awt.BorderLayout;
    import java.awt.event.ActionEvent;
    import java.beans.*;
    import java.io.*;
    import java.util.*;
    import java.util.concurrent.*;
    import javax.swing.*;
    
    @SuppressWarnings("serial")
    public class ActivityQueue2b extends JPanel {
    
       // instance variables //
       private LinkedList<SCPActivity> queue; // the queue of activities that were
       // added to execute
       private JProgressBar pBar; // progress bar showing the overall progress of
       // the execution
       private JLabel progLabel; // label displaying the status of the execution and
       // the number of activities remaining
       private JTextArea console; // main window of the UI; output of the activities
       // will be printed here
       private static final String newline = "\n"; // IV used for a new line in the
       // console
       private int total; // the total number of activities that were added to the
    
       // queue
    
       /**
        * Constructor for the ActivityQueue, initializes the IVs
        * 
        * @param queue
        *           - an ArrayList from which the queue is built
        */
       public ActivityQueue2b(ArrayList<SCPActivity> queue) {
          this.queue = new LinkedList<SCPActivity>();
    
          // initializes the counter used to update the progress indicators to 0.
          total = 0;
    
          // create and initialize the progress bar
          pBar = new JProgressBar(0, 100);
          pBar.setValue(0);
          pBar.setStringPainted(true);
    
          // initialize the console and the progress label
          progLabel = new JLabel("");
          console = new JTextArea(25, 50);
          console.setEditable(false);
    
          // add each item from the ArrayList to the queue
          for (SCPActivity act : queue) {
             addToQueue(act);
          }
    
          // initialize and set up the panel that holds the start
          // button, progress bar and progress label.
          JPanel buttonPanel = new JPanel();
          setLayout(new BorderLayout());
          buttonPanel.add(new JButton(new StartAction()));
          buttonPanel.add(progLabel);
          buttonPanel.add(pBar);
    
          // add the console and the button panel to the frame
          add(buttonPanel, BorderLayout.SOUTH);
          add(new JScrollPane(console), BorderLayout.CENTER);
       }
    
       /**
        * Method called in order to show the UI and set up the ActivityQueue
        * 
        * @param queue
        *           - ArrayList passed into the ActivityQueue constructor
        */
       public static void createAndShowGui(ArrayList<SCPActivity> queue) {
          JFrame frame = new JFrame("Activity Console");
          frame.getContentPane().add(new ActivityQueue2b(queue));
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.setSize(750, 600);
          frame.pack();
          frame.setResizable(false);
          frame.setLocation(1700, 200);
          frame.setLocationRelativeTo(null);
          frame.setVisible(true);
       }
    
       /**
        * Adds the activity parameter to the queue if it doesn't already exist
        * 
        * @param activity
        *           - an activity that will be added to the queue
        */
       public void addToQueue(SCPActivity activity) {
          if (!queue.contains(activity)) {
    
             // the the queue doesn't contain the activity, it is added to the queue
             queue.add(activity);
    
             // updates the console to note that the activity was added
             writeToConsole("*" + activity.getActivityID() + " added to queue.");
    
             // increments the number of total activities in the queue
             total++;
          }
          // updates the progress label to indicate the number of activities in the
          // queue
          setProgLabel("Number of items in queue: " + queue.size()
                + " | Status: waiting...");
       }
    
       /**
        * Updates all indicators that display the overall progress of the activity
        * execution
        * 
        * @param count
        * @param totals
        */
       public void updateProgressIndicators(int totals, int count) {
          String status = "";
    
          int progress = Utilities.getPercentage(totals - count, totals);
    
          if (progress >= 100)
             status = "complete!";
          else
             status = "executing...";
    
          setProgLabel("Number of items in queue: " + queue.size() + " | Status: "
                + status);
          pBar.setValue(progress);
       }
    
       /**
        * Writes the provided message to the console then prints a new line
        * 
        * @param message
        *           - the message to print to the console
        */
       public void writeToConsole(String message) {
          if (!message.equals(""))
             console.append(message + newline);
       }
    
       /**
        * Sets the progress label to the value of 'message'
        * 
        * @param message
        *           - the message which to set the progress label
        */
       public void setProgLabel(String message) {
          if (!(message.equals("")))
             progLabel.setText(message);
       }
    
       /**
        * Private inner class that is used to execute the activities in the queue
        */
       private class StartAction extends AbstractAction {
          // constructor for StartAction - sets the name to 'Execute'.
          public StartAction() {
             super("Execute");
          }
    
          @Override
          public void actionPerformed(ActionEvent e) {
             if (queue.size() > 0) {
                new SwingWorker<Void, String>() {
                   private int taskCount = queue.size();
                   private CountDownLatch latch = new CountDownLatch(queue.size());
                   private ExecutorService pool = Executors
                         .newFixedThreadPool(taskCount);
                   private Map<MyTask2b, Future<String>> taskFutureMap = new HashMap<MyTask2b, Future<String>>();
    
                   @Override
                   protected Void doInBackground() throws Exception {
                      PropertyChangeListener myPropChngListener = new PropertyChangeListener() {
                         public void propertyChange(PropertyChangeEvent evt) {
                            String name = evt.getPropertyName();
                            Object newValue = evt.getNewValue();
                            System.out.printf(
                                  "property name: %s;  new value: %s%n", name,
                                  newValue);
                            if (name.equals(MyTask2b.STATE)
                                  && (newValue == SwingWorker.StateValue.DONE)) {
                               MyTask2b task = (MyTask2b) evt.getSource();
                               Future<String> future = taskFutureMap.get(task);
                               try {
                                  String text = future.get();
                                  System.out.println("Text: " + text);
                                  publish(text);
                               } catch (InterruptedException e) {
                                  e.printStackTrace();
                               } catch (ExecutionException e) {
                                  e.printStackTrace();
                               }
                            } else if (name.equals(MyTask2b.LINE)) {
                               MyTask2b task = (MyTask2b) evt.getSource();
                               publish(task.getLine()); //!!
                            }
                         }
                      };
    
                      while (queue.size() > 0) {
                         SCPActivity act = queue.pop();
                         MyTask2b task = new MyTask2b("My Task", latch, act);
                         task.addPropertyChangeListener(myPropChngListener);
                         taskFutureMap.put(task, pool.submit(task));
                      }
    
                      latch.await(); // wait for countdown to finish
                      return null;
                   }
    
                   @Override
                   protected void process(List<String> chunks) {
                      for (String chunk : chunks) {
                         updateProgressIndicators(taskCount, (int) latch.getCount());
                         console.append(chunk + "\n");
                      }
                   }
    
                   @Override
                   protected void done() {
                      updateProgressIndicators(taskCount, (int) latch.getCount());
                   }
    
                }.execute();
    
             } else {
                // note if there are no activities in the queue
                writeToConsole("There are no activities in the queue. Please select modules to "
                      + "execute or wait for"
                      + newline
                      + "the queue to populate."
                      + newline);
             }
          }
       }
    
       public static void main(String[] args) {
    
          SwingUtilities.invokeLater(new Runnable() {
             public void run() {
    
                // create an ArrayList of activities and add them to the queue
                ArrayList<SCPActivity> q = new ArrayList<SCPActivity>();
                SCPping act = new SCPping("google.com");
                q.add(act);
                act = new SCPping("yahoo.com");
                q.add(act);
                act = new SCPping("facebook.com");
                q.add(act);
    
                createAndShowGui(q);
             }
          });
       }
    }
    
    class MyTask2b implements Callable<String> {
       public static final String STATE = "state";
       public static final String LINE = "line";
       private String text;
       private CountDownLatch latch;
       private PropertyChangeSupport propChngSupport = new PropertyChangeSupport(
             this);
       private SwingWorker.StateValue state = SwingWorker.StateValue.PENDING;
       private SCPActivity act;
       private String line = "";
    
       public MyTask2b(String text, CountDownLatch latch, SCPActivity act) {
          this.text = text;
          this.latch = latch;
          this.act = act;
       }
    
       @Override
       public String call() throws Exception {
          setState(SwingWorker.StateValue.STARTED);
    
          while (state != SwingWorker.StateValue.DONE) {
             System.out.println("state: " + state);
             int instances = Utilities.getNumberOfProcesses("ping.exe");
             if (instances < 2) {
                act.execute();
                InputStream stream = act.getStream();
                String line = "";
    
                BufferedReader reader = new BufferedReader(new InputStreamReader(
                      stream));
    
                try {
                   while (!reader.ready()) {
                   }
                   line = reader.readLine();
                   while (!(line == null)) {
                      setLine(line);
                      line = reader.readLine();
                   }
    
                } catch (IOException e1) {
                   e1.printStackTrace();
                }
                latch.countDown();
                setState(SwingWorker.StateValue.DONE);
             }
          }
          System.out.println("just before return text"); //!!
          return text;
       }
    
       private void setState(SwingWorker.StateValue newValue) {
          SwingWorker.StateValue oldValue = this.state;
          this.state = newValue;
          PropertyChangeEvent evt = new PropertyChangeEvent(this, STATE, oldValue,
                newValue);
          propChngSupport.firePropertyChange(evt);
       }
    
       private void setLine(String newValue) {
          String oldValue = this.line;
          this.line = newValue;
          PropertyChangeEvent evt = new PropertyChangeEvent(this, LINE, oldValue,
                newValue);
          propChngSupport.firePropertyChange(evt);
       }
       
       public String getLine() {
          return act.getActivityID() + ": " + line;
       }
    
       public void addPropertyChangeListener(PropertyChangeListener listener) {
          propChngSupport.addPropertyChangeListener(listener);
       }
    
       public void removePropertyChangeListener(PropertyChangeListener listener) {
          propChngSupport.removePropertyChangeListener(listener);
       }
    }

Page 1 of 2 12 LastLast

Similar Threads

  1. Center text in a JComponent?
    By Zman3359 in forum New To Java
    Replies: 4
    Last Post: 04-17-2011, 10:44 PM
  2. Question on getGraphics() in a JComponent
    By Shayke_ in forum Java 2D
    Replies: 2
    Last Post: 02-10-2011, 07:31 PM
  3. Replies: 2
    Last Post: 10-01-2010, 07:18 PM
  4. SetBackground for JComponent
    By tulasi.neppali in forum AWT / Swing
    Replies: 5
    Last Post: 09-12-2010, 10:14 PM
  5. Random size of JComponent
    By Karl-von-bahnhof in forum AWT / Swing
    Replies: 0
    Last Post: 04-13-2010, 08:14 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •