progress bar while long running server job with Primefaces - jsf

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

Related

Trigger listener clicking on ace:textEntry

I'm using JSF 2.0 and I want to invoke a function defined in a Java controller when I click on an ace:textEntry.
I tried in this way:
<ace:textEntry readonly="true" value="#{myController.getValue()}"
onclick="#{myController.myFunc()}"/>
but when my page is open, the click event is called instantly.
So, I tried with:
<ace:textEntry readonly="true" value="#{myController.getValue()}">
<ace:ajax event="click" listener="#{myController.myFunc()}"/>
</ace:textEntry>
but my page is not rendered.
Is there another way to implement this behaviour ?
PS: I can use similar JSF components instead of ace:textEntry too.
First, you do not access getters directly in JSF for value backing - you access the property. Secondly, you should call the listener with the correct signature. To correct your example I would first rewrite the call like this,
<ace:textEntry readonly="true" value="#{myController.value}">
<ace:ajax event="click" listener="#{myController.myFunc}"/>
</ace:textEntry>
Then define MyController, like this;
#Named
#ViewScoped
public class MyController {
private value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public void myFunc(javax.faces.event.AjaxBehaviorEvent event) {
/* Do somethinig here... */
}
}

How to Compare the values JSF selectonemenu

I am developing a JSF application
I have 2 selectOnemenu controls and submit button.
I need to disable the button if the values of 2 fields are equal
<h:selectOneMenu id="from" value="#{currencyBean.history.fromCurrency}" >
<f:selectItems value="#{currencyBean.currency}" var="c" itemValue="#{c}" itemLabel="#{c.name}"/>
</h:selectOneMenu>
<p:outputLabel for="to" value="to:" />
<h:selectOneMenu id="to" value="#{currencyBean.history.toCurrency}" >
<f:selectItems value="#{currencyBean.currency}" var="c" itemValue="#{c}" itemLabel="#{c.name}"/>
</h:selectOneMenu>
<p:commandButton id="calculateButton" value="Convert" update=":convert :historyPanel" onstart="PF('statusDialog').show()" onsuccess="PF('statusDialog').hide()" validateClient="true" ajax="true" action="#{currencyBean.Calculate()}" />
I tried to use onchange with ajax but everytime I change one dropdown the value of the second drowpdown became null in the backbean so I cannot read it.
Here is my backbean
#Named(value = "currencyBean")
#RequestScoped
public class CurrencyBean implements Serializable {
/**
* Creates a new instance of CurrencyBean
*/
private History history;
private Currency currency;
private Date currentDate;
#Inject
private Loginbean loginBean;
private List<History> historyList;
public List<History> getHistoryList() {
int userId = loginBean.getUserId();
if (userId != -1) {
return new HistoryHelper().GetHistoryListByUser(userId);
}
return null;
}
public CurrencyBean() {
history = new History();
}
public History getHistory() {
return history;
}
public void setHistory(History history) {
this.history = history;
}
public Currency[] getCurrency() {
return Currency.values();
}
public Date getCurrentDate() {
return new Date();
}
public void Calculate() {
int userId = loginBean.getUserId();
if (userId != -1) {
new CurrencyClient().Convert(userId, this.history);
}
}
}
any clue ?
My assumption is that all of your problems come from your managed bean scope. You have #Request scope so every request your managed bean will be removed from container, thus when you define onchange="submit()" (this is only my assumption because you haven't define how you implement onchange attribute) and you select value from one selectBox component values for this component is updated but the first one is still null. When you select second selectBox value updated from first selectBox doesn't exists anymore as managed bean has been removed after first request. You should try with wider scope for instance #ViewScope. If it doesn't help then further informations like implementation onchange attribute will be needed

p:commandbutton update not updating immediately for ScheduledExecutorService

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.

Session Scoped Managed Bean constructor being called on each page refresh

I am using a session scoped managed bean for handling login in a Java EE application. After I authenticate the user, the user object is saved in this session bean. However, after I refresh the page, the session bean values are gone.
I was debugging the code and it results that the constructor of the session scoped managed bean is called again on page refresh, therefore initializing the user object with a new user. I guess this is not a normal behavior since it should be preserved on the session shouldn't it?
I am posting some parts of the login managed bean including the parameters and the login method. Basically the enteredEmail and enteredPassword stand for the entered data on the login form. If the authentication succeeds, the loggedIn boolean is turned to true and the logged in user object is stored in the checkedUser variable.
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class LoginController implements Serializable {
#EJB
private LoginSessionBean loginSessionBean;
#EJB
private LecturerFacade lecturerFacade;
private Lecturer checkedUser;
private String enteredEmail;
private String enteredPassword;
private boolean loggedIn;
/** Creates a new instance of loginController */
public LoginController() {
loggedIn = false;
checkedUser = new Lecturer();
}
public String login(){
RequestContext context = RequestContext.getCurrentInstance();
FacesMessage msg = null;
this.setCheckedUser(lecturerFacade.findLecturerByEmail(enteredEmail));
if(loginSessionBean.checkPassword(checkedUser, enteredPassword))
{
loggedIn = true;
msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Welcome", checkedUser.getFirstName()+ " " + checkedUser.getLastName());
FacesContext.getCurrentInstance().addMessage(null, msg);
context.addCallbackParam("loggedIn", loggedIn);
}
return "Index";
I am also posting the two EJBs that the above managed bean uses. The lecturerFacade retrieves the user object with the entered email, while the loginSessionBean checks the password.
#Stateless
public class LecturerFacade extends AbstractFacade<Lecturer> {
#PersistenceContext(unitName = "EffectinetWebPU")
private EntityManager em;
Logger logger = Logger.getLogger("MyLog");
FileHandler fh;
protected EntityManager getEntityManager() {
return em;
}
public LecturerFacade() {
super(Lecturer.class);
}
public Lecturer findLecturerByEmail(String email) {
try {
return (Lecturer) this.getEntityManager().createQuery("SELECT l FROM Lecturer l WHERE l.email = :email").setParameter("email", email).getSingleResult();
} catch (NoResultException e) {
System.err.println("Caught NOResultException: "+ e.getMessage());
return null;
} catch (NonUniqueResultException e) {
System.err.println("Caught NonUniqueResultException: "+ e.getMessage());
return null;
} catch (IllegalStateException e) {
System.err.println("Caught IllegalStateException: "+ e.getMessage());
return null;
}
}
_
#Stateless
public class LoginSessionBean {
// Add business logic below. (Right-click in editor and choose
// "Insert Code > Add Business Method")
#PersistenceContext(unitName = "EffectinetWebPU")
private EntityManager em;
protected EntityManager getEntityManager() {
return em;
}
public void setEntityManager(EntityManager em) {
this.em = em;
}
public boolean checkPassword(Lecturer user, final String enteredPassword) {
if (user.getPassword().equals(enteredPassword)) {
return true;
} else {
return false;
}
}
}
Please if someone has any suggestion of what is going wrong, please tell me
Im using glassfish 3.1 as application server and Primefaces as JSF library. Also, I have checked and the imported the sessionScoped annotation from the right package and not from javax.enterprise...
Your problem is thus here:
<p:menuitem value="Logout" ... onclick="#{loginController.logout()}"/>
The onclick attribute should represent a JavaScript handler function which is to be executed in the webbrowser when the enduser clicks the element. Something like
onclick="alert('You have clicked this element!')"
The onclick attribute also accepts a ValueExpression, so you can even let JSF/EL autogenerate its value accordingly:
onclick="#{bean.onclickFunction}"
with
public String getOnclickFunction() {
return "alert('You have clicked this element!')";
}
All the EL is thus evaluated when the page is rendered. In your particular case, the logout() method is called everytime the EL is evaluated and thus you're invalidating the session everytime the page is rendered!
You need to bind it to an attribute which takes a MethodExpression like <h:commandLink action>, <h:commandButton action> and in this particular case <p:menuitem action>.
<p:menuitem value="Logout" ... action="#{loginController.logout()}"/>
This can be understood by understanding basic HTML and JavaScript concepts and keeping in mind that JSF ultimately produces HTML/CSS/JS. Open the JSF page in webbrowser, rightclick and View Source to realize it.
Well I managed to solve it today. This was the problem, although I cannot explain why:
I was using Primefaces 3.2 as JSF library so this was the main menu of the index page.
<h:form>
<p:menubar >
<p:menuitem id="registerLink" value="Register" rendered="#{!loginController.loggedIn}" onclick="registerDialog.show()" />
<p:menuitem id="loginLink" value="Login" rendered="#{!loginController.loggedIn}" onclick="loginDialog.show()" />
<p:submenu label="Units" rendered="true">
<p:menuitem id="addNew" value="Add New" onclick="createUnitDialog.show()" />
<p:menuitem id="myUnits" value="My Units" onclick="" />
</p:submenu>
<p:menuitem id="results" value="Results/Statistics" rendered="#{loginController.loggedIn}" onclick=""/>
<p:menuitem id="profile" value="My Profile" rendered="#{loginController.loggedIn}" onclick=""/>
<p:menuitem id="logout" value="Logout" rendered="#{loginController.loggedIn}" onclick="#{loginController.logout()}"/>
</p:menubar>
</h:form>
After setting breakpoints to the whole code I discovered that the logout() method, which is supposed to destroy the managed bean, was called on every page refresh. I don't know why this happened as it should be called when the logout menuitem was clicked.
However, after changing the onclick="#{loginController.logout()} with action="#{loginController.logout()} the problem was solved.
I checked the documentation of Primefaces but nowhere this behavior was explained

JSF Dynamic Rendered Component's Value becomes null when the form is submitted

I have a JSF page which renders a text field depending on the value of a drop down using primefaces ajax listner. The dynamic rendering is done fine. but the problem is once I submit the form the the bound value of that textfield doesn't get bound instead it is shown as null.
this is the part of my JSF only the necessary fields are included here
<h:panelGroup id="textPanel" >
<h:form id="main" prependId="false">
<h:outputText value="WorkFlow ID:" />
<h:selectOneMenu id="workFlows" value="#{workFlowSelectionController.selectedWorkFlowId}" >
<p:ajax event="change" listener="#{workFlowSelectionController.dropDownChange}" update="textPanel"/>
<f:selectItems value="#{workFlowSelectionController.allActiveworkFlows}"/>
</h:selectOneMenu>
<p:inputText value="#{workFlowSelectionController.texField}" rendered="#{workFlowSelectionController.textfieldVisibility}"/>
<p:commandButton ajax="false" value="Next" action="#{workFlowSelectionController.addWorkFlowselectionDetails}"/>
</h:form>
</h:panelGroup>
this is my managed bean
#ManagedBean
#RequestScoped
public class WorkFlowSelectionController {
private boolean textfieldVisibility = false;
private String texField;
public void dropDownChange() {
logger.info("WorkFlowSelectionController.dropDownChange() entered");
if (selectedWorkFlowId != null) {
if (selectedWorkFlowId.equals("-1")) {
textfieldVisibility = true;
operationListStatus = false;
} else {
textfieldVisibility = false;
operationListStatus = true;
}
} else {
textfieldVisibility = false;
operationListStatus = true;
}
public void addWorkFlowselectionDetails() throws CloneNotSupportedException {
System.out.println("Selected Value of Text Field is" + texField);
}
public String getTexField() {
return texField;
}
public void setTexField(String texField) {
this.texField = texField;
}
}
i haven't included the dropdown code of the backing bean. i just need an idea of what i am doing wrong here if i remove the rendered attribute of the textfield it works fine.
thank you
Put the bean in the view scope instead of request scope. A request scoped is recreated on every single HTTP request. The boolean property will default to false again whenever you submit the form, so the submitted value won't be processed then.
#ManagedBean
#ViewScoped
public class WorkFlowSelectionController {
//
}
A view scoped bean will live as long as you're (ajax-) interacting with the same view by returning null or void from action(listener) methods.

Resources