Simple Ping Application with <rich:progressBar>

Problem

Create a simple ping application using <rich:progressBar> to show progress of ping.

Solution

Create a separate thread on the server to ping execution and track the changes in the <rich:progressBar>.

Details

To create a simple ping application we need to make basic JSF project with RichFaces support.

 

Back-end

Let's create apingThread class (implementing Runnable interface) that is responsible for creating a separate executive thread on the server. There are 2 main methods:

            1. start(), which runs thread and return String[] as result

                   public String[] start() {
                        thread = new Thread(this);
                        result = new String[hosts.size()];
                        currentValue = -1;
                        taskDone = false;
                        thread.start();
                        return result;
                   }
              

               

            2. run(), which implements a ping process using Runtime.getRuntime().exec(command). Command is a platform dependent.

              public void run() {
                        if (thread != null) {
                             for (int i = 0; i < hosts.size(); i++) {
                                  Process ping;
                                  try {
                                       os = System.getProperty("os.name");
                                       if(os.equals("Linux")){
                                            command = "ping " + hosts.get(i) + " -c 3 ";
                                       }else if(os.equals("Windows")){
                                            command = "ping " + hosts.get(i) + " -n 3 ";
                                       }
                                       ping = Runtime.getRuntime().exec(command);
                                       BufferedReader br = new BufferedReader(
                                                 new InputStreamReader(ping.getInputStream()));
                                       StringBuilder sb = new StringBuilder();
                                       String line;
                                       while ((line = br.readLine()) != null) {
                                            sb.append(line);
                                            sb.append("\n");
                                       }
                                       currentValue++;
                                       if (sb.length() != 0) {
                                            result[currentValue] = sb.toString();
                                       } else {
                                            result[currentValue] = "ping: unknown host "
                                                      + hosts.get(i);
                                       }
                                  } catch (IOException e) {
                                       FacesContext.getCurrentInstance().addMessage(
                                                 null,
                                                 new FacesMessage(FacesMessage.SEVERITY_ERROR, e
                                                           .getMessage(), null));
                                  }
                             }
                        }
                        taskDone = true;
                   }
              

               

 

Variable taskDone is used to indicate the process completion.

In order to make visible the current value of the variable “currentValue” for another thread, we should declare the method getCurrentValue() with a synchronized key word:

     public synchronized float getCurrentValue() {
          return (float) (currentValue + 1) / hosts.size();
     }

The full class listing is put below:

...
public class PingThread implements Runnable {

     private List<String> hosts = new ArrayList<String>();
     private String[] result;
     private int currentValue;
     private Thread thread;
     private boolean taskDone;
     private String command = new String();
     private String os = new String();
     
     public PingThread(List<String> hostArray) {
          taskDone = false;
          hosts = hostArray;
          currentValue = -1;
     }

     public String[] start() {
          thread = new Thread(this);
          result = new String[hosts.size()];
          currentValue = -1;
          taskDone = false;
          thread.start();
          return result;
     }
     
     public void run() {
          if (thread != null) {
               for (int i = 0; i < hosts.size(); i++) {
                    Process ping;
                    try {
                         os = System.getProperty("os.name");
                         if(os.equals("Linux")){
                              command = "ping " + hosts.get(i) + " -c 3 ";
                         }else if(os.equals("Windows")){
                              command = "ping " + hosts.get(i) + " -n 3 ";
                         }
                         ping = Runtime.getRuntime().exec(command);
                         BufferedReader br = new BufferedReader(
                                   new InputStreamReader(ping.getInputStream()));
                         StringBuilder sb = new StringBuilder();
                         String line;
                         while ((line = br.readLine()) != null) {
                              sb.append(line);
                              sb.append("\n");
                         }
                         currentValue++;
                         if (sb.length() != 0) {
                              result[currentValue] = sb.toString();
                         } else {
                              result[currentValue] = "ping: unknown host "
                                        + hosts.get(i);
                         }
                    } catch (IOException e) {
                         FacesContext.getCurrentInstance().addMessage(
                                   null,
                                   new FacesMessage(FacesMessage.SEVERITY_ERROR, e
                                             .getMessage(), null));
                    }
               }
          }
          taskDone = true;
     }



     public synchronized float getCurrentValue() {
          return (float) (currentValue + 1) / hosts.size();
     }

     public boolean isTaskDone() {
          return taskDone;
     }

     public List<String> getHosts() {
          return hosts;
     }

     public void setHosts(List<String> hosts) {
          this.hosts = hosts;
     }
}

 

Now you can create a managed-bean that contains all business logic and starts the ping process.

When a page is rendered for the first time "Start ping" button should be disabled until a host is added. The panel with a results should be hidden:

_1249580012819.png

...
public class MyProgressBarBean {

     private List<String> hosts = new ArrayList<String>();
     private String host = null;
     private String[] result;
     private PingThread pingThread = null;
     private boolean resultRendered = false;
     private boolean renderedProgressBar = false;
     private boolean renderedProgressPanel = false;
     private boolean startButtonDisabled = true;

     public boolean isRenderedPanel() {
          if (renderedProgressBar) {
               return pingThread.isTaskDone();
          } else
               return true;
     }
     ...
}

 

All hosts are populated in ArrayList<String>:

     public void addHost() {
          if (isUniquenessHost(host, hosts)) {
               hosts.add(host);
               host = "";
          }
          if (startButtonDisabled) {
               startButtonDisabled = false;
          }
     }

Before the host will be added it is needed to check its uniqueness:

private boolean isUniquenessHost(String host, List<String> hosts) {
          int counter = 0;
          if (hosts.isEmpty()) {
               return true;
          } else {
               for (String hostsItem : hosts) {
                    if (hostsItem.equals(host)) {
                         counter++;
                    }
               }
               if (counter > 0) {
                    return false;
               } else {
                    return true;
               }
          }
     }

 

You also need a method that removes all hosts:

     public void removeAllHosts() {
          hosts.clear();
          startButtonDisabled = true;
          renderedProgressPanel = false;
     }

Finally you need a method that starts a ping process and enables a progress bar:

     public void startProcess() {
          pingThread = new PingThread(hosts);
          result = pingThread.start();
          renderedProgressPanel = true;
          renderedProgressBar = true;
     }

Here is a full listing of Bean class:

...
public class Bean {

     private List<String> hosts = new ArrayList<String>();
     private String host = null;
     private String[] result;
     private PingThread pingThread = null;
     private boolean resultRendered = false;
     private boolean renderedProgressBar = false;
     private boolean renderedProgressPanel = false;
     private boolean startButtonDisabled = true;

     
     public void startProcess() {
          pingThread = new PingThread(hosts);
          result = pingThread.start();
          renderedProgressPanel = true;
          renderedProgressBar = true;
     }

     public int getCurrentValue() {
          float curVal = pingThread.getCurrentValue();
          return (int) (100.0 * curVal + 1);
     }

     public boolean isRenderedPanel() {
          if (renderedProgressBar) {
               return pingThread.isTaskDone();
          } else
               return true;
     }

     public void addHost() {
          if (isUniquenessHost(host, hosts)) {
               hosts.add(host);
               host = "";
          }
          if (startButtonDisabled) {
               startButtonDisabled = false;
          }
     }

     public void removeAllHosts() {
          hosts.clear();
          startButtonDisabled = true;
          renderedProgressPanel = false;
     }

     private boolean isUniquenessHost(String host, List<String> hosts) {
          int counter = 0;
          if (hosts.isEmpty()) {
               return true;
          } else {
               for (String hostsItem : hosts) {
                    if (hostsItem.equals(host)) {
                         counter++;
                    }
               }
               if (counter > 0) {
                    return false;
               } else {
                    return true;
               }
          }
     }
     
     public boolean isResultRendered() {
          return pingThread.isTaskDone();
     }
}

Front-end


As it is shown on the screenshot above you need <a4j:commandButton> components to call startProcess(), removeAllHosts(), and addHost() methods, <rich:progressBar> to show a ping process and <rich:dataList> to output the result:

     <rich:panel id="panelButton">
          <f:facet name="header">Hosts to ping</f:facet>
          <rich:messages />
          <h:outputText>
               Please, add hosts to ping. Every host will be pinged for 3 times.
          </h:outputText>
          <h:form>
               <h:inputText id="hosts" value="#{myProgressBarBean.host}" />
               <a4j:commandLink value="Add host"
                    action="#{myProgressBarBean.addHost}" reRender="panelButton" />
               <br />
               <h:outputLabel styleClass="remark" for="hosts" value="e.g. livedemo.exadel.com" />
               <rich:dataOrderedList id="hostsList"
                    value="#{myProgressBarBean.hosts}" var="host">
                    <h:outputText value="#{host}" />
               </rich:dataOrderedList>
               <a4j:commandButton id="startButton" styleClass="buttons"
                    action="#{myProgressBarBean.startProcess}" value="Start Ping"
                    reRender="progressPanelWrapper"
                    disabled="#{myProgressBarBean.startButtonDisabled}" />
               <a4j:commandButton id="resetButton"
                    action="#{myProgressBarBean.removeAllHosts}"
                    value="Remove all hosts" reRender="panelButton,progressPanelWrapper" />
          </h:form>
     </rich:panel>
     <a4j:outputPanel id="progressPanelWrapper">
          <rich:panel id="progressPanel" rendered="#{myProgressBarBean.renderedProgressPanel}">
               <f:facet name="header">Result</f:facet>
               <h:form>
                    <rich:progressBar value="#{myProgressBarBean.currentValue}"
                         label="#{myProgressBarBean.currentValue} %" interval="1000"
                         minValue="-1" maxValue="99"
                         rendered="#{myProgressBarBean.renderedProgressBar}"
                         reRenderAfterComplete="progressPanel">
                    </rich:progressBar>
                    <rich:dataList var="ping" value="#{myProgressBarBean.result}"
                         rendered="#{myProgressBarBean.resultRendered}">
                         <h:outputText value="#{ping}" />
                         <br />
                    </rich:dataList>
               </h:form>
          </rich:panel>
     </a4j:outputPanel>

Here is a result:

_1249581441524.png

_1249581646485.png

_1249581543832.png