You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by angelochen <an...@yahoo.com.hk> on 2011/12/26 15:06:33 UTC

T5 progress bar in a grid

Hi,

would like to have some ideas about how to implement following:

I have a t:grid, every row has a link, when click, it will do a process
which might take a while, once done, it will either disable the link or
re-display the link depending on the result. I'd like that, when clicked,
the link is replaced with a progress bar in place, until it is done. any
hints? Thanks,

Angelo

--
View this message in context: http://tapestry.1045711.n5.nabble.com/T5-progress-bar-in-a-grid-tp5101565p5101565.html
Sent from the Tapestry - User mailing list archive at Nabble.com.

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: T5 progress bar in a grid

Posted by lebenski <be...@hotmail.co.uk>.
Just wanted to say a big thanks for this Lance.  I ran your code and used it
extensively in my own project where I'm using a crawler to gather
information.  The UI is updated every second with the new total of saved
crawled results.  This taught me some stuff about threading and got me to
finally upgrade to 5.3.1 so big thanks.

--
View this message in context: http://tapestry.1045711.n5.nabble.com/T5-progress-bar-in-a-grid-tp5101565p5133879.html
Sent from the Tapestry - User mailing list archive at Nabble.com.

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: T5 progress bar in a grid

Posted by Lance Java <la...@googlemail.com>.
I have created a component to hide all the gubbins that I mentioned
earlier. All you need to do is create a more beautiful progress bar (my css
skills aren't great). I have created a simple page which adds 3
progressRunnableLinks on a page. Each fires a task that takes 10 seconds,
updating it's percentage complete as it goes.

1. Download the code from here
http://dl.dropbox.com/u/63354/tapestry-progress.zip
2. run "mvn jetty:run"
3. Go to http://localhost:8080/tapestry/progress

Cheers,
Lance.

Interesting bits of code:

AppModule.java
----------------------

    public ProgressRunnableManager buildProgressRunnableManager() {
        return new ProgressRunnableManagerImpl(20);
    }


Progress.tml
------------------
    <t:progressRunnableLink zoneId="zone1" linkText="start 1"
progressRunnable="progressRunnable" pollDelayMillis="500" />
    <t:progressRunnableLink zoneId="zone2" linkText="start 2"
progressRunnable="progressRunnable" pollDelayMillis="500" />
    <t:progressRunnableLink zoneId="zone3" linkText="start 3"
progressRunnable="progressRunnable" pollDelayMillis="500" />

Progress.java (page class)
--------------------

public class Progress {
    public ProgressRunnable getProgressRunnable() {
        return new AbstractProgressRunnable() {
            public void run() {
                for (int i = 1; i <= 10; ++i) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                    setProgressPercentage(i * 10);
                }
            }
        };
    }
}

ProgressRunnableLink.java (component)
----------------------------------------------------------
@Import (library="zonemanager.js")
public class ProgressRunnableLink {
    @Inject
    private ProgressRunnableManager manager;

    @Inject
    private AjaxResponseRenderer ajaxRenderer;

    @Inject
    private ComponentResources resources;

    @Inject
    private JavaScriptSupport jsSupport;

    @Parameter
    private Integer pollDelayMillis;

    @Parameter(defaultPrefix="literal", required=true)
    @Property
    private String linkText;

    @Parameter(defaultPrefix="literal", required=true)
    @Property
    private String zoneId;

    @Parameter(allowNull=false)
    private ProgressRunnable progressRunnable;

    @Property
    private Double progressPercentage;

    @Property
    private Exception exception;

    @InjectComponent
    private Zone progressZone;

    @OnEvent("startRunnable")
    Block startTask() {
        String taskId = manager.submit(progressRunnable);
        progressPercentage = 0D;
        doPoll(taskId);
        return progressZone.getBody();
    }

    @OnEvent("updateProgress")
    Block updateProgress(String taskId) {
        try {
            progressPercentage = manager.getProgressPercentage(taskId);
            if (progressPercentage < 100D) {
                doPoll(taskId);
            }
        } catch (Exception e) {
            exception = e;
        }
        return progressZone.getBody();
    }

    void doPoll(String taskId) {
        Link link = resources.createEventLink("updateProgress", taskId);
        final String url = link.toAbsoluteURI();
        ajaxRenderer.addCallback(new JavaScriptCallback() {
            public void run(JavaScriptSupport jsSupport) {
                if (pollDelayMillis == null) {
                    jsSupport.addScript("Tapestry.activateZone('%s',
'%s');", zoneId, url);
                } else {

jsSupport.addScript("setTimeout(\"Tapestry.activateZone('%s', '%s');\",
%s);", zoneId, url, pollDelayMillis);
                }
            }
        });
    }
}






On 3 January 2012 10:34, Lance Java <la...@googlemail.com> wrote:

> There are a couple of approaches to do this, since tapestry does not
> support ajax push (aka reverse ajax) out-of-the box, a simple solution
> would be to have the client poll the server for the current percentage
> complete.
>
> In order to display a progress bar to the client, you must do the actual
> work for the task on a separate thread to the Ajax request thread. It is
> probably best to have a singleton ExecutorService (using
> java.util.concurrent.Executors.newFixedThreadPool(threadCount) or similar)
>
> The Ajax request thread should:
> 1. Create a runnable and give it a unique taskId
> 2. Put the runnable in a serverside map keyed on taskId (map could be a
> singleton or perhaps stored in each user's session)
>
> 3. Call executorService.submit(myRunnable)
> 4. Use the AjaxResponseRenderer to fire the "updateProgressBar" event
> passing the taskId in the context
> 5. Return the progress bar zone's getBody() with a percentageComplete of 0
>
> Your runnable would be something like
>
> public class MyWorker implements Runnable {
>    private int taskId;
>    private ConcurrentMap workers;
>    private AtomicInteger percentComplete = new AtomicInteger(0);
>    public MyWorker(ConcurrentMap workers, String taskId) {
>       this.workers = workers;
>       this.taskId = taskId;
>    }
>    public int getPercentComplete() {
>       return percentComplete.get();
>    }
>    public void run() {
>       try {
>          doSomeWork();
>          percentComplete.set(10);
>          doSomeMoreWork();
>          percentComplete.set(50);
>          doEvenMoreWork();
>          percentComplete.set(100);
>       } finally {
>          workers.remove(taskId);
>       }
>    }
> }
>
>
> In your serverside event handler [onUpdateProgressBar(String taskId)]
> lookup the runnable in the map and call getPercentComplete() then return
> the updated progress zone's getBody(). If the percentageComplete() is less
> than 100, use the AjaxResponseRenderer to fire the "updateProgressBar"
> event again.
>
> @see
> http://tawus.wordpress.com/2011/10/01/tapestry-5-3-new-features-part-2/for AjaxResponseRenderer usage
>
> Cheers,
> Lance.
>
>
> On Monday, 26 December 2011, angelochen <an...@yahoo.com.hk>
> wrote:
> > Hi,
> >
> > would like to have some ideas about how to implement following:
> >
> > I have a t:grid, every row has a link, when click, it will do a process
> > which might take a while, once done, it will either disable the link or
> > re-display the link depending on the result. I'd like that, when clicked,
> > the link is replaced with a progress bar in place, until it is done. any
> > hints? Thanks,
> >
> > Angelo
> >
> > --
> > View this message in context:
> http://tapestry.1045711.n5.nabble.com/T5-progress-bar-in-a-grid-tp5101565p5101565.html
> > Sent from the Tapestry - User mailing list archive at Nabble.com.
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > For additional commands, e-mail: users-help@tapestry.apache.org
> >
> >
>

Re: T5 progress bar in a grid

Posted by Lance Java <la...@googlemail.com>.
There are a couple of approaches to do this, since tapestry does not
support ajax push (aka reverse ajax) out-of-the box, a simple solution
would be to have the client poll the server for the current percentage
complete.

In order to display a progress bar to the client, you must do the actual
work for the task on a separate thread to the Ajax request thread. It is
probably best to have a singleton ExecutorService (using
java.util.concurrent.Executors.newFixedThreadPool(threadCount) or similar)

The Ajax request thread should:
1. Create a runnable and give it a unique taskId
2. Put the runnable in a serverside map keyed on taskId (map could be a
singleton or perhaps stored in each user's session)

3. Call executorService.submit(myRunnable)
4. Use the AjaxResponseRenderer to fire the "updateProgressBar" event
passing the taskId in the context
5. Return the progress bar zone's getBody() with a percentageComplete of 0

Your runnable would be something like

public class MyWorker implements Runnable {
   private int taskId;
   private ConcurrentMap workers;
   private AtomicInteger percentComplete = new AtomicInteger(0);
   public MyWorker(ConcurrentMap workers, String taskId) {
      this.workers = workers;
      this.taskId = taskId;
   }
   public int getPercentComplete() {
      return percentComplete.get();
   }
   public void run() {
      try {
         doSomeWork();
         percentComplete.set(10);
         doSomeMoreWork();
         percentComplete.set(50);
         doEvenMoreWork();
         percentComplete.set(100);
      } finally {
         workers.remove(taskId);
      }
   }
}


In your serverside event handler [onUpdateProgressBar(String taskId)]
lookup the runnable in the map and call getPercentComplete() then return
the updated progress zone's getBody(). If the percentageComplete() is less
than 100, use the AjaxResponseRenderer to fire the "updateProgressBar"
event again.

@see http://tawus.wordpress.com/2011/10/01/tapestry-5-3-new-features-part-2/for
AjaxResponseRenderer usage

Cheers,
Lance.

On Monday, 26 December 2011, angelochen <an...@yahoo.com.hk> wrote:
> Hi,
>
> would like to have some ideas about how to implement following:
>
> I have a t:grid, every row has a link, when click, it will do a process
> which might take a while, once done, it will either disable the link or
> re-display the link depending on the result. I'd like that, when clicked,
> the link is replaced with a progress bar in place, until it is done. any
> hints? Thanks,
>
> Angelo
>
> --
> View this message in context:
http://tapestry.1045711.n5.nabble.com/T5-progress-bar-in-a-grid-tp5101565p5101565.html
> Sent from the Tapestry - User mailing list archive at Nabble.com.
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>