My progressbar is not updated, why ?
The controller method is called as it should and the progess variable is correctly incremented:
XHTML
<p:dialog>
<h:outputLabel value="Count:" for="batchCount"/>
<p:inputText id="batchCount" required="true"
value="#{batchModel.count}">
</p:inputText>
<p:commandButton id="generateBatchButton" value="GO"
actionListener="#{batchController.sendBatch()}"
onclick="PF('progressVar').start();"
oncomplete="PF('dialogBatchParams').hide();"/>
<p:progressBar id="progressBar"
widgetVar="progressVar"
value="#{batchModel.progress}"
labelTemplate="{value}%">
</p:progressBar>
</p:dialog>
CONTROLLER Method
public void sendBatch() {
for (int i = 0; i < batch.size(); i++) {
batchModel.setProgress(Math.round(100 * (float) i / (float) batch.size()));
// Do stuff here
}
}
MODEL
#Named
#ViewScoped // or #SessionScoped
public class BatchModel implements Serializable {
private static final long serialVersionUID = 1L;
private int count = 100;
private int progress;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public int getProgress() {
return progress;
}
public void setProgress(int progress) {
this.progress = progress;
}
}
My progress is correctly updated, I get this output when logging it:
2016-10-19 10:08:49,707 INFO controller.BatchController -> Sending batch
0
10
20
30
40
50
60
70
80
90
2016-10-19 10:08:57,432 INFO controller.BatchController -> Done sending batch
I am using PF 6. I tried with and without "update" tag, and I played around with the ajax tag, but no dice.
Your question started of with a RequestScoped bean. Those are created each request. Since an update of the bar requires a request, you will get a new bean with progress set to 0 again.
It's best to use ViewScoped on your bean (and controller).
Also, you are missing ajax="true" in your progress bar (it expects you to do the updates on the client side). You should change it to:
<p:progressBar id="progressBar"
ajax="true"
widgetVar="progressVar"
value="#{batchModel.progress}"
labelTemplate="{value}%"/>
Related
I'm having a hard time doing basic AJAX updates of a timeline.
Let me start with a basic example where I want to update the start and end times of a timeline based on the selection of a dropdown list:
<h:form id="form">
<h:outputLabel for="period" value="#{str.schedule_period}"/>
<h:selectOneMenu id="period" value="#{timelineController.period}" label="#{str.schedule_period}">
<f:selectItems value="#{timelineController.periodWeeks}" />
<p:ajax event="change" update="timeline" />
</h:selectOneMenu>
<pe:timeline id="timeline" value="#{timelineController.model}"
editable="true"
eventMargin="0"
minHeight="120"
stackEvents="false"
start="#{timelineController.timelineStart}"
min="#{timelineControllertimelineStart}"
end="#{timelineController.timelineEnd}"
max="#{timelineController.timelineEnd}"
showNavigation="false" showButtonNew="false"
showCurrentTime="false"
axisOnTop="true"
timeZone="#{timelineController.timezone}"
zoomMin="28800000"
dropActiveStyleClass="ui-state-highlight" dropHoverStyleClass="ui-state-hover">
<p:ajax event="drop" listener="#{timelineController.onDrop}"
global="false" process="timeline"/>
</pe:timeline>
</h:form>
When I select an item in the dropdown list, an AJAX event fires and sets the period property in the backing bean, but the new value is not reflected in the timeline component. As a workaround, I wrapped the timeline in a p:outputPanel and updated the wrapper instead and it works:
...
<h:selectOneMenu id="period" value="#{timelineController.period}" label="#{str.schedule_period}">
<f:selectItems value="#{timelineController.periodWeeks}" />
<p:ajax event="change" update="wrapper" />
</h:selectOneMenu>
...
<p:outputPanel id="wrapper">
<pe:timeline id="timeline" value="#{timelineController.model}"
editable="true"
eventMargin="0"
minHeight="120"
stackEvents="false"
start="#{timelineController.timelineStart}"
min="#{timelineControllertimelineStart}"
end="#{timelineController.timelineEnd}"
max="#{timelineController.timelineEnd}"
showNavigation="false" showButtonNew="false"
showCurrentTime="false"
axisOnTop="true"
timeZone="#{timelineController.timezone}"
zoomMin="28800000"
dropActiveStyleClass="ui-state-highlight" dropHoverStyleClass="ui-state-hover">
<p:ajax event="drop" listener="#{timelineController.onDrop}"
global="false" process="wrapper"/>
</pe:timeline>
</p:outputPanel>
Note that I also had to change the process attribute of p:ajax to wrapper.
So my first question is: why doesn't the update work without wrapping the timeline component?
My second question is about drag and drop. As you can you see from my code above, I have attached a drop listener to the timeline. And I'm also able to drag and drop events from a p:dataList BEFORE I make a selection in the dropdown list. Once I select a new period in the dropdown list, the timeline gets updated appropriately, but I'm not able to drag and drop events to the timeline any more (the onDrop listener doesn't get fired). Here's my p:dataList:
<p:dataList id="eventsList" value="#{timelineController.users}"
var="user" itemType="none">
<h:panelGroup id="eventBox" layout="box" style="z-index:9999; cursor:move;">
#{user.toString()}
</h:panelGroup>
<p:draggable for="eventBox" revert="true" helper="clone" cursor="move"/>
</p:dataList>
Any ideas what's wrong here?
I'm also including the TimelineController class for reference:
#ManagedBean
#ViewScoped
public class TimelineController {
#EJB UserService userDao;
private TimelineModel model;
private String name;
private ZoneId timezone;
private Period period;
private Duration defaultShiftDuration;
private LocalDateTime timelineStart;
private LocalDateTime timelineEnd;
#PostConstruct
protected void initialize() {
timezone = ZoneId.of("Europe/Berlin);
period = Period.ofWeeks(2);
defaultShiftDuration = Duration.ofHours(8);
timelineStart = LocalDateTime.now().with(DayOfWeek.MONDAY).withHour(0).withMinute(0).truncatedTo(ChronoUnit.MINUTES);
// create timeline model
model = new TimelineModel();
}
public TimelineModel getModel() {
return model;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTimezone() {
return timezone.getId();
}
public void setTimezone(String timezone) {
this.timezone = ZoneId.of(timezone);
}
public List<SelectItem> getPeriodWeeks() {
List<SelectItem> weeks = Lists.newArrayList();
weeks.add(new SelectItem(1, "1 " + JsfUtil.getStringResource("schedule_week")));
weeks.add(new SelectItem(2, "2 " + JsfUtil.getStringResource("schedule_weeks")));
weeks.add(new SelectItem(3, "3 " + JsfUtil.getStringResource("schedule_weeks")));
return weeks;
}
public int getPeriod() {
return period.getDays() / 7;
}
public void setPeriod(int nWeeks) {
this.period = Period.ofWeeks(nWeeks);
timelineEnd = null;
}
public Date getTimelineStart() {
return Date.from(timelineStart.atZone(timezone).toInstant());
}
public Date getTimelineEnd() {
if (timelineEnd == null) {
timelineEnd = timelineStart.plus(period);
}
return Date.from(timelineEnd.atZone(timezone).toInstant());
}
public void setStartsOn(String startsOn) {
timelineStart = LocalDateTime.parse(startsOn + "T00:00");
timelineEnd = null;
}
public List<User> getUsers(){
return userDao.findAll();
}
public void onDrop(TimelineDragDropEvent e) {
// get dragged model object (event class) if draggable item is within a data iteration component,
// update event's start and end dates.
User user = (User) e.getData();
Date endDate = Date.from(e.getStartDate().toInstant().plus(defaultShiftDuration));
// create a timeline event (not editable)
TimelineEvent event = new TimelineEvent(user, e.getStartDate(), endDate, true, e.getGroup());
// add a new event
TimelineUpdater timelineUpdater = TimelineUpdater.getCurrentInstance(":form:timeline");
model.add(event, timelineUpdater);
}
}
The problem was a missing widgetVar attribute in the timeline component. This looks like a bug to me, since I'm not using the client side API of the component. I will file a bug in PF Extensions project.
I have a question regarding the lifecycle of session scoped CDI beans.
As far as I understand, a session scoped CDI bean is constructed by the container when the session starts and destroyed when the session ends. Before the bean is destroyed the #PreDestroy Method is invoked as described here https://docs.oracle.com/javaee/6/tutorial/doc/gmgkd.html. It also says to release resources in this method.
In a JSF application I build I experience Memory Leak because the bean doesn't seem to be destroyed and hence the #PreDestroy Method is not invoked to free some references for the garbage collector. So I built a simple Application to test the behavior. My experience is that the session bean doesn't get destroyed when the session is over and furthermore it doesn't even get destroyed when the memory space is needed. I cannot believe I am the first to encounter this, but I don't find any information about this behavior..
So my question is: Shouldn't a CDI bean be destroyed - and hence the #PreDestroy Method be invoked - immediately after its context expired? And if not shouldn't it be at least destroyed when the space is needed?
My test Application:
I am not allowed to post a picture, but the outline is the very basic jsf webapp generated by eclipse. I also have the beans.xml file.
Test.java:
package com.test;
import java.io.Serializable;
import java.util.ArrayList;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
#SessionScoped
#Named
public class Test implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private String test;
private ArrayList<ComplexType> cps;
private ArrayList<ComplexType> cps_2;
#PostConstruct
public void init() {
System.out.println("test postconstruct..");
test = "Cdi Test";
}
#PreDestroy
public void cleanUp() {
cps = null;
cps_2 = null;
System.out.println("test cleanUp....");
}
public void data_1() {
cps = new ArrayList<ComplexType>();
for(int i = 0; i < 800; i++) {
String[] s = new String[100000];
ComplexType cp = new ComplexType(i, s);
cps.add(cp);
System.out.println(i);
}
System.out.println("data_1");
}
public void free_1() {
cps = null;
System.out.println("free_1");
}
public void data_2() {
cps_2 = new ArrayList<ComplexType>();
for(int i = 0; i < 800; i++) {
String[] s = new String[100000];
ComplexType cp = new ComplexType(i, s);
cps_2.add(cp);
System.out.println(i);
}
System.out.println("data_1");
}
public void free_2() {
cps_2 = null;
System.out.println("free_1");
}
public String getTest() {
return test;
}
public void setTest(String test) {
this.test = test;
}
}
ComplexType.java:
package com.test;
public class ComplexType {
private int id;
private String[] name;
public ComplexType(int id, String[] name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String[] getName() {
return name;
}
public void setName(String[] name) {
this.name = name;
}
}
index.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<h:head>
<title>Cdi test </title>
</h:head>
<h:body>
<h:outputText value="#{test.test}"></h:outputText>
<h:form>
<h:commandButton value="cp_1 data" actionListener="#{test.data_1}">
<f:ajax></f:ajax>
</h:commandButton>
<h:commandButton value="cp_1 Free" actionListener="#{test.free_1}">
<f:ajax></f:ajax>
</h:commandButton>
<br></br>
<h:commandButton value="cp_2 data" actionListener="#{test.data_2}">
<f:ajax></f:ajax>
</h:commandButton>
<h:commandButton value="cp_2 Free" actionListener="#{test.free_2}">
<f:ajax></f:ajax>
</h:commandButton>
</h:form>
</h:body>
</html>
I open the index.xhtml page and the #PostConstruct Method gets invoked as expected. The heap space is exceeded when I invoke data_1 and data_2 both without freeing in between. When I free one of the resources in between or I invoke one method twice in a row the heap space is enough, as the garbage collector frees the memory. This works as I would expect it to work.
But when I invoke one data function, close the browser and hence the session, open a new browser and invoke one of the data functions again, then the application stops working as (I guess) the memory space is exceeded. The point is: the first session bean doesn't get destroyed and its #PreDestroy Method not invoked and therefore the ArrayList is still in the memory.
Can someone please explain to me what is going on here? Shouldn't a CDI bean be destroyed by the container as soon its context expires so that references can be set to null and the garbage collector can free resources?
I am using JBoss AS 7.1.1 and its default implementation JSF Mojarra 2.1.
Session beans (regardless CDI or JSF managed) stay alive until some session timeout exceeds (usually 30 minutes by default, dependent on application server), which you can specify in web.xml. Just closing the browser doesn't invalidate session and it wait to be destroyed by servlet container after timeout expiration. So, my assumption, such behaviour is just fine, #PreDestroy method will be invoked later.
The answer of #olexd basically explains what I was getting wrong in my mind, thank you very much! But invalidating the session after a determined period is not an option, so I had to use the comment of #geert3 as well, thank you for that! I am answering my own question to show how I have solved my particular problem in detail here.
What I was wrong about: I thought the session expires as soon as the browser is closed. This is wrong and it makes sense. One may want to close the browser and open it again to work in the same session as before.
For me this behaviour is not appropriate because I want to release resources as soon as the browser gets closed. So the answer is to manually invalidate the session like this:
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
As soon as this method is called, the #PreDestroy Method is called, exactly as I want it. Now I had to determine when to call this function. I searched for a way to listen to something like a browserclose event. There are the onbeforeunload and onunload events. onunload doesn't seem to work for me in Chrome, but the onbeforeunload does. See also this answer:
https://stackoverflow.com/a/16677225/1566562
So I wrote a hidden button that gets clicked by javascript on beforeunload and invokes an appropriate backingbean method. This works as I would expect it to work. I tested it on Chrome 43.0.2357.65 and IE 11, for now I am content with it. However it doesn't work with onunload, but this is not of concern for me right now.
So my final code likes this:
index.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Cdi test</title>
<h:outputScript library="default" name="js/jquery-1.11.3.min.js"
target="head"></h:outputScript>
</h:head>
<h:body>
<h:outputText value="#{test.test}"></h:outputText>
<h:form id="overall">
<h:commandButton value="cp_1 data" actionListener="#{test.data_1}">
<f:ajax></f:ajax>
</h:commandButton>
<h:commandButton value="cp_1 Free" actionListener="#{test.free_1}">
<f:ajax></f:ajax>
</h:commandButton>
<br></br>
<h:commandButton value="cp_2 data" actionListener="#{test.data_2}">
<f:ajax></f:ajax>
</h:commandButton>
<h:commandButton value="cp_2 Free" actionListener="#{test.free_2}">
<f:ajax></f:ajax>
</h:commandButton>
<br></br>
<h:commandButton id="b" style="display:none"
actionListener="#{test.invalidate}"></h:commandButton>
</h:form>
<script type="text/javascript">
$(window).on('beforeunload', function() {
$('#overall\\:b').click();
});
</script>
</h:body>
</html>
Test.java
package com.test;
import java.io.Serializable;
import java.util.ArrayList;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Named;
#SessionScoped
#Named
public class Test implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private String test;
private ArrayList<ComplexType> cps;
private ArrayList<ComplexType> cps_2;
#PostConstruct
public void init() {
System.out.println("test postconstruct..");
test = "Cdi Test";
}
#PreDestroy
public void cleanUp() {
cps = null;
cps_2 = null;
System.out.println("test cleanUp....");
}
public void data_1() {
cps = new ArrayList<ComplexType>();
for (int i = 0; i < 800; i++) {
String[] s = new String[100000];
ComplexType cp = new ComplexType(i, s);
cps.add(cp);
System.out.println(i);
}
System.out.println("data_1");
}
public void free_1() {
cps = null;
System.out.println("free_1");
}
public void data_2() {
cps_2 = new ArrayList<ComplexType>();
for (int i = 0; i < 800; i++) {
String[] s = new String[100000];
ComplexType cp = new ComplexType(i, s);
cps_2.add(cp);
System.out.println(i);
}
System.out.println("data_2");
}
public void free_2() {
cps_2 = null;
System.out.println("free_2");
}
public void invalidate() {
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
System.out.println("invalidate");
}
public String getTest() {
return test;
}
public void setTest(String test) {
this.test = test;
}
}
Note that I have used JQuery. This works with JBoss AS 7.1.1 and the default Weld implementation as well.
One thing to add: one doesn't have to set all the referenes manually to null. This makes sense as well, as it would be tedious..
I'd like a bar showing progress of a long-running server job launched with commandButton in jsf / Primefaces.
The showcase for Primefaces shows how to create a pb which updates according to the state of some variable on server side, with Ajax: http://www.primefaces.org/showcase/ui/misc/progressBar.xhtml
<h3>Ajax ProgressBar</h3>
<p:commandButton value="Start" type="button" onclick="PF('pbAjax').start();PF('startButton2').disable();" widgetVar="startButton2" />
<p:commandButton value="Cancel" actionListener="#{progressBarView.cancel}" oncomplete="PF('pbAjax').cancel();PF('startButton2').enable();" />
<br /><br />
<p:progressBar widgetVar="pbAjax" ajax="true" value="#{progressBarView.progress}" labelTemplate="{value}%" styleClass="animated" global="false">
<p:ajax event="complete" listener="#{progressBarView.onComplete}" update="growl" oncomplete="startButton2.enable()"/>
</p:progressBar>
I try to add an action on the commandButton, that should have for effect to update the progress value:
<p:commandButton value="Start" type="button" onclick="PF('pbAjax').start();
PF('startButton2').disable();" widgetVar="startButton2" action="#{computer.compute()}"/>
The Computer bean:
#ManagedBean
#SessionScoped
public class Computer {
long i;
public Computer() {
}
public String compute() throws InterruptedException {
i = 1;
while (i < 10) {
i++;
Thread.sleep(1000);
}
return "welcomePrimefaces.xhtml";
}
}
The ControllerBean:
ManagedBean
#ViewScoped
public class ControllerBean {
#Inject Computer computer;
public ControllerBean() {
}
private Integer progress;
public Integer getProgress() {
if (computer.i == 1){
progress = 30;
}
if (computer.i == 2){
progress = 60;
}
if (computer.i == 3){
progress = 90;
}
if (computer.i == 4){
progress = 100;
}
return progress;
}
public void setProgress(Integer progress) {
this.progress = progress;
}
public void onComplete() {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Progress Completed"));
}
public void cancel() {
progress = null;
}
}
But the compute method is never called, i is never updated. Surely this is this logic (injecting computer into controllerbean) which is incorrect. Any pointer to get it to work is appreciated!
Two possible problems with your code
A button of type button will not execute a server-side action, it's meant only for navigation and client-side business (mostly javascript). Unless you really mean to, you shouldn't have to set the type attribute on your buttons (it defaults to type="submit", the kind that executes server-side actions).
Depending on your version of JSF, you probably won't have a successful bean injection when combining #Inject and #ManagedBean-type beans. Prior to JSF-2.2, the handshake between CDI (#Inject) and JSF(#ManagedBean etc) was very buggy. The most effective way to inject JSF-managed beans is using the #ManagedProperty annotation.
Putting both together, you should have:
<p:commandButton value="Start" onclick="PF('pbAjax').start();
PF('startButton2').disable();" widgetVar="startButton2" action="#{computer.compute()}"/>
And in your backing bean
#ManagedProperty(value="#{computer}")
Computer computer;
The #ManagedProperty annotation will use an all-lowercase version of your class name since you didn't explicitly specify a name for that managed bean
Related Reading:
Primefaces - commandButton does not work
I'm working on a JSF + Primefaces Web App in which I need to make a RESTful GET request every 20 seconds to a server, and display the data returned. This currently works, with the exception of the "every 10 seconds" part. I can click my command button to retrieve and show the data. I tried to implement the repitition with ScheduledExecutorService. Now when I click the commandButton, the backing function runs every 10 seconds (I can see this through System.out.println output), but the table will not update to show data until the button is clicked a second time. Here is my code below:
HTML (This is embedded inside a form)
<p:commandButton id="andon_layout--board0--loadboard0"
value="Load board"
actionListener="#{decryptionBean.loadBoardListen0}"
update="dataPanelGrid" />
<div id="andon_layout--board0--display_div"
class="ui-datatable ui-widget ">
<h:panelGrid id="dataPanelGrid"
columns="#{decryptionBean.displayBoardArray[0].datatableNumberOfCols}"
headerClass="ui-datatable ui-widget-header ">
<f:facet name="header">
<h:outputText
value="#{decryptionBean.displayBoardArray[0].locationName}" />
</f:facet>
<c:forEach var="row"
items="#{decryptionBean.displayBoardArray[0].displayData}">
<c:forEach var="value" items="#{row}">
<div class="ui-dt-c">#{value}</div>
</c:forEach>
</c:forEach>
</h:panelGrid>
</div>
JAVA
#ManagedBean
#ViewScoped
public class DecryptionBean implements Serializable {
...
private Updater left = new Updater(0);
public void loadBoardListen0(ActionEvent event){
left.stopBoardLoading();
left.beginBoardLoading();
}
public final class Updater {
#PreDestroy
public void destroy() {
fScheduler.shutdownNow();
}
private ScheduledExecutorService fScheduler;
//
private long fDelayBetweenRuns = 10;
int boardNumber;
/**
* If invocations might overlap, you can specify more than a single
* thread.
*/
private int NUM_THREADS = 1;
public int isRunning = 0;
private boolean DONT_INTERRUPT_IF_RUNNING = false;
private ScheduledFuture<?> loadBoardFuture;
private class BoardLoaderTask implements Runnable {
private int boardNumber;
public BoardLoaderTask(int boardNumber) {
this.boardNumber = boardNumber;
}
public void run() {
DecryptionBean.this.loadBoard(boardNumber);
}
}
public Updater(int boardNumber){
this.boardNumber = boardNumber;
fScheduler = Executors.newScheduledThreadPool(NUM_THREADS);
}
void beginBoardLoading(){
if(isRunning == 1){
this.stopBoardLoading();
}
isRunning = 1;
Runnable boardLoaderTask = new BoardLoaderTask(this.boardNumber);
loadBoardFuture = fScheduler.scheduleWithFixedDelay(boardLoaderTask,
0, fDelayBetweenRuns, TimeUnit.SECONDS);
}
void stopBoardLoading(){
if(isRunning == 1){
isRunning = 0;
Runnable stopBoard = new StopLoadingTask(loadBoardFuture);
fScheduler.schedule(stopBoard, 0, TimeUnit.SECONDS);
}
isRunning = 0;
}
private class StopLoadingTask implements Runnable {
StopLoadingTask(ScheduledFuture<?> aSchedFuture) {
fSchedFuture = aSchedFuture;
}
private ScheduledFuture<?> fSchedFuture;
#Override
public void run() {
// TODO Auto-generated method stub
fSchedFuture.cancel(DONT_INTERRUPT_IF_RUNNING);
}
}
}
loadBoard(int boardNum) is kind of a large function, so I haven't posted it here, however I will if you guys deem it necessary.
It seems to me that the problem comes from the p:commandbutton update attribute: it seems like the dataPanelGrid is being updated at the start of loadBoardListen0, as opposed to the end. To be clear: The backing function runs on the first click, but only updates the GUI on the second, third, fourth etc. click Any guidance on this one? Thanks in advance!
EDIT 1:
I'm now trying to do this using PrimePush and a socket, but I'm running into trouble there too. I added this to my code:
HTML
<p:socket onMessage="handleMessage" channel="/IPVS" autoConnect="false"/>
...
function handleMessage(data) {
console.log("data received: " + data);
var elm = "andon_layout--board" + data + "--display_div";
elm.style.display="none";
var redrawFix = elm.offsetHeight;
elm.style.display="block";
}
JAVA (at the end of loadBoard(int))
System.out.println("Loading data... no exceptions thrown");
System.out.println("context created");
PushContextFactory.getDefault().getPushContext().push("/IPVS", Integer.toString(displayBoardNum));
System.out.println("Just pushed to /IPVS");
Whenever I attempt to run the code, it simply halts at the PushContextFactory line. The output I get is as follows:
Loading data... no exceptions thrown
context created
And simply no more. This also prevents the loop from running. Note that I am still using a ScheduledExecutorService, and just trying to push some data every time the task completes. Any ideas?
You should try using the Primefaces poll tag. This will fire an ajax event every x seconds. You could use this to call your "getData" method on your backing bean. This will move the logic of the polling into your JSF page, rather than the backing bean.
For example:
<p:poll interval="10" listener="#{decryptionBean.getData}" update="dataPanelGrid" />
This requires you to have a simple "getData" method in your backing bean, without the scheduling code.
In RichFaces 4.1, rich:progressBar 'currentValue' from the ManagedBean does not updating with for-loop.
progressBar.xhtml
<h:form id="formProgress">
<h:commandLink action="#{progressBarBean.startProcess}" value="click here"/>
<rich:progressBar mode="ajax" value="#{progressBarBean.currentValue}" interval="1000" id="pb"
enabled="#{progressBarBean.enabled}" minValue="0" maxValue="100">
<h:outputText value="Retrieving #{progressBarBean.currentValue} of #{progressBarBean.totalRecords}" />
</rich:progressBar>
</h:form>
Bean
package ap;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class ProgressBarBean implements Serializable {
private static final long serialVersionUID = 8775622106408411357L;
private boolean enabled = false;
private Integer totalRecords;
private Integer currentValue;;
public String startProcess() {
setEnabled(true);
setTotalRecords(100);
return null;
}
public Integer getCurrentValue() {
if (isEnabled()) {
for(currentValue=0;currentValue < totalRecords;) {
currentValue++;
}
}
return currentValue;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public Integer getTotalRecords() {
return totalRecords;
}
public void setTotalRecords(Integer totalRecords) {
this.totalRecords = totalRecords;
}
}
When i click the 'click here' link, the currentValue updates very fastly and reaches the totalRecords to 100 suddenly. It was not updating in the incremental way(present value in for-loop). The progress bar is not updated by the present value return by the method.
Any help please.
There are two problems: your Java code does not do what you want it to do and you're not telling the page to update (that won't happen automatically).
Take a look at the getCurrentValue() again: It increments currentValue from 0 to 100 and returns the result which is 100. #{progressBarBean.currentValue} does not care (or know) what happens with the variable, it only cares about the result of the getCurrentValue() method.
So in order for it all to work it will have to look like this:
Page
<a4j:commandLink action="#{progressBarBean.startProcess}" value="click here" render="pb" execute="#this"/>
<rich:progressBar mode="ajax" value="#{progressBarBean.currentValue}" interval="1000" id="pb"
enabled="#{progressBarBean.enabled}" minValue="0" maxValue="100">
<a4j:ajax event="begin" listener="#{progressBarBean.increment}" render="text"/>
<h:outputText value="Retrieving #{progressBarBean.currentValue} of #{progressBarBean.totalRecords}" id="text" />
</rich:progressBar>
The a4j:ajax is fired each second (i.e. each interval), it increments the currentValue and updates the text.
You also need a4j:commandLink (or a4j:ajax inside the h:commandLink) in order to rerender the progressbar - in your example you enable the progressbar in the bean but the value on the page does not change.
Bean
public Integer getCurrentValue() {
return currentValue;
}
public void increment() {
if (isEnabled() && currentValue < totalRecords) {
currentValue++;
}
}
Ask if anything isn't clear.