How to invoke a JSF bean action from a link? - jsf

We have the following requirement in our project.
On click of a link,
A JSF managed bean method should be invoked which will return a URL
to a document.
This document should be opened in a new window.
How can I do this?

How about a <h:commandLink/> with a target="_blank" attribute:
<h:commandLink action="#{bean.action}" target="_blank" value="Open document"/>
And in your bean:
public void action() {
try {
FacesContext.getCurrentInstance().getExternalContext()
.redirect("page2.xhtml");
} catch (IOException ex) {
// do something here
}
}
Replace page2.xhtml with your target url.

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... */
}
}

am i using correct way of JSF coding?

I'm new in JSF. Can i use this way of coding instead of using EL in JSF view? and correct me if there is something wrong in my coding or should i use better way.
#Named
#RequestScoped
public class RegistrationBacking extends Root {
#EJB
private UserManagerLocal userManager;
public String register(){
Map<String, Object> parameterMap = getRequestMap();
User user = new User();
user.setUserName((String) parameterMap.get("userName"));
user.setPassword((String) parameterMap.get("password"));
user.setEmail((String) parameterMap.get("email"));
try{
userManager.registerUser(user);
} catch(UserExistsException ex) {
Logger.getLogger(RegistrationBacking.class.getName()).log(Level.SEVERE, null, ex);
getContext().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getBundle().getString("loginExist"), ex.getMessage()));
return null;
} catch(Exception ex) {
Logger.getLogger(RegistrationBacking.class.getName()).log(Level.SEVERE, null, ex);
getContext().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getBundle().getString("loginError"), ex.getMessage()));
return null;
}
return "index";
}
}
No. You're basically manually grabbing the submitted values from the request parameter map instead of binding the input values to the model. You're manually filling the model in the controller's action method. You won't be able to perform JSF-managed Conversion and Bean Validation on those inputs.
The right way is the following:
<h:form>
<h:inputText value="#{registrationBacking.user.userName}" />
<h:inputSecret value="#{registrationBacking.user.password}" />
<h:inputText value="#{registrationBacking.user.email}" />
<h:commandButton value="Register" action="#{registrationBacking.register}" />
</h:form>
And then in the backing bean:
private User user;
#PostConstruct
public void init() {
user = new User();
}
public String register {
try {
// ...
}
}
See also:
Passing a JSF2 managed pojo bean into EJB or putting what is required into a transfer object
Creating master-detail pages for entities, how to link them and which bean scope to choose
JSF Service Layer

JSF button is not working after AJAX call

I have this JSF button which calls Java method when it's pressed:
<h:commandButton id="editdata" value="HiddenDelete" style="position:absolute; bottom:25px; right:650px;" actionListener="#{bean.saveData}" rendered="#{bean.editable}">
<f:ajax render="#form" execute="#form"></f:ajax>
</h:commandButton>
public void saveData() throws SQLException
{
.....
}
When I make a AJAX call the button is not working properly. Can you help me to find why the Java method is not called after AJAX call?
You're not passing the event:
public void saveData(AjaxBehaviorEvent event) { ... }
Also, what do you expect to happen with the Exception you're throwing? Shouldn't you catch it?
try {
// logic
}
catch(SQLException ex) {
FacesContext facesContext = FacesContext.getCurrentInstance();
FacesMessage facesMessage = new FacesMessage(
"There was an error, ....");
facesContext.addMessage(null, facesMessage);
}
This will be printed in HTML by <h:messages />.

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 PrimeFaces FileDownload problem

I'm using PrimeFaces for a new project and it's quite an impressive set of components.
Anyway, I have problem with "real world" use of filedownload component.
In my page I have a datalist that shows the attachments related to a particular document, and I want provide a link to directly download that file inside the datalist item.
Here's my xhtml code:
<p:dataList id="ListaAllegati" value="#{documentBean.documento.allegati}" type="definition" var="attach" style="border: none" ">
<f:facet name="description">
<h:outputText value="#{attach.name}" />
<p:commandLink ajax="false" title="Download" action="#{documentBean.selectAttach}>
<h:graphicImage style="margin-left: 10px; border: none" value="./images/article.png" height="24" width="24" ></h:graphicImage>
<p:fileDownload value="#{documentBean.downloadFile}"/>
<f:setPropertyActionListener target="#{documentBean.selectedAttach}" value="#{attach}" />
</p:commandLink>
</f:facet>
</p:dataList>
and the relative java bean (request scoped):
private StreamedContent downloadFile;
public StreamedContent getDownloadFile() {
log.info("getter dell'allegato invocato");
InputStream stream = null;
byte[] rawFile = null;
if (selectedAttach == null) {
log.warn("Nessun allegato passato");
return null;
} else {
try {
log.info("Recupero del file " + selectedAttach.getGuid());
rawFile = attachManager.retrieveFile(selectedAttach.getGuid());
} catch (Exception e) {
String msg = "Errore durante il recupero del file";
log.error(msg, e);
FacesMessage fmsg = new FacesMessage(msg, "");
FacesContext.getCurrentInstance().addMessage(null, fmsg);
}
stream = new ByteArrayInputStream(rawFile);
DefaultStreamedContent file = new DefaultStreamedContent(stream,
selectedAttach.getMimeType(), selectedAttach.getName());
return file;
}
}
public void selectAttach() {
log.info("commandLink action invocata");
}
private Allegato selectedAttach;
public Allegato getSelectedAttach() {
return selectedAttach;
}
public void setSelectedAttach(Allegato selectedAttach) {
log.info("Allegato selezionato");
if (selectedAttach==null) log.warn("L'allegato passato รจ nullo");
this.selectedAttach = selectedAttach;
}
So, couple of question:
Am I doing the right thing trying to pass the selected attachment that way? Otherwise, how can I pass a parameter to tell the bean wich attachment has been clicked?
Why the first time I click the command link, nothing happen? It make a roundtrip with server, but nothing happens. Second time, it gives me an exception.
Why documentBean.selectAttach is never called and the documentBean.selectedAttach property is never set (neither the second time)?
Thanks to anyone for any hint
How to get the row object from the datatable is answered in this question:
How can I pass selected row to commandLink inside dataTable?
This answers basically all the three questions.
As to the exception in the second click, that's likely because you didn't return from the catch block when an exception is been thrown in your getDownloadFile() method. You're continuing the remnant of the code flow while the rawFile is still null. Fix it accordingly as well. Add a return null to the end of catch or something. Better yet, you should be posting the entire stacktrace in the question as you don't seem to be able to understand it. It basically already contains the answer :)
Primefaces has its own dedicated servlet for file download and upload components that handle all of this asynchronously.
Try doing something like what I have in my code
<p:commandLink ajax="false" actionListener="#{managedBean.downloadAction(object)}">
<span class="ui-icon icoFolderGo" style="padding-right: 1.5em;" />
<p:fileDownload value="#{managedBean.downloadContentProperty}" />
</p:commandLink>
And in the managed bean,
public void downloadAction(Object object) {
try {
InputStream stream = // get input stream from argument
this.setDownloadContentProperty(new DefaultStreamedContent(stream, "application/pdf", "filename.pdf");
} catch (Exception e) {
log.error(e);
}
}
public void setDownloadContentProperty(StreamedContent downloadContentProperty) {
this.downloadContentProperty = downloadContentProperty;
}
public StreamedContent getDownloadContentProperty() {
return downloadContentProperty;
}

Resources