I am working on an application using JSF 2.1 and PrimeFaces 3.2, server Tomcat 7. Right now, I am working on form to register new users. The problem is in converter.
I use few standard fields and two of them are passwords. I have custom data type for password, so I want to use converter to convert String data from field to Password variable in a bean. Primefaces forms use AJAX after submit, and there is probably the problem. If I fill in the form completely, without validation errors, everything works fine. But if there is a validaton error and no converter error (I check for the password length in the converter), whole form stops working at all. I have to refresh page to have it working again.
Here are some sources:
Password class:
public class Password {
public static final short MIN_LENGTH = 5;
private String text;
private String hash;
public Password(String text) {
this.text = text;
this.hash = Hasher.sha512(text);
}
/**
* Get password instance with known hash only
* #param hash SHA-512 hash
* #return Password instance
*/
public static Password getFromHash(String hash) {
Password password = new Password(null);
password.hash = hash;
return password;
}
#Override
public int hashCode() {
return hash.hashCode();
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Password other = (Password) obj;
if ((this.hash == null) ? (other.hash != null) : !this.hash.equals(other.hash)) {
return false;
}
return true;
}
#Override
public String toString() {
return hash;
}
/**
* #return the text
*/
public String getText() {
return text;
}
}
Password converter:
#FacesConverter(forClass = Password.class)
public class PasswordConverter implements Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
String text = (String) value;
if (text.length() >= Password.MIN_LENGTH) {
return new Password(text);
}
FacesMessage msg = new FacesMessage(Texter.get("forms/forms", "shortPassword").replace("%limit%", String.valueOf(Password.MIN_LENGTH)));
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ConverterException(msg);
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
try {
Password password = (Password) value;
return password.getText();
} catch (Exception ex) {
throw new ConverterException(ex);
}
}
}
The form in facelet:
<h:form id="registration">
<p:panelGrid columns="3">
<h:outputLabel value="#{commonTxt.email}:" for="email" />
<p:inputText id="email" value="#{userRegistrationForm.email}" required="true" requiredMessage="#{formsTxt.msgEmpty}">
<f:validator validatorId="email" />
<f:validator validatorId="unique" />
<f:attribute name="entity" value="SystemUser" />
<f:attribute name="field" value="email" />
<f:attribute name="uniqueMessage" value="#{formsTxt.nonUniqueEmail}" />
</p:inputText>
<p:message for="email" />
<h:outputLabel value="#{usersTxt.password}:" for="password" />
<p:password id="password" value="#{userRegistrationForm.password}" binding="#{password}" autocomplete="off" feedback="true" weakLabel="#{formsTxt.passwordWeak}" goodLabel="#{formsTxt.passwordGood}" strongLabel="#{formsTxt.passwordStrong}" promptLabel="#{formsTxt.passwordPrompt}" />
<p:message for="password" />
<h:outputLabel value="#{usersTxt.passwordCheck}:" for="passwordCheck" />
<p:password id="passwordCheck" value="#{userRegistrationForm.passwordCheck}" binding="#{passwordCheckInput}" autocomplete="off">
<f:validator validatorId="match" />
<f:attribute name="matchAgainst" value="#{password}" />
<f:attribute name="matchMessage" value="#{formsTxt.passwordMismatch}" />
</p:password>
<p:message for="passwordCheck" />
<p:column /><p:column /><p:column />
<h:outputLabel value="#{usersTxt.name}:" for="name" />
<p:inputText id="name" value="#{userRegistrationForm.name}" maxlength="255" required="true" requiredMessage="#{formsTxt.msgEmpty}" />
<p:message for="name" />
<f:facet name="footer">
<p:commandButton value="#{usersTxt.register}" action="#{userRegistrationForm.register()}" update="registration" />
</f:facet>
</p:panelGrid>
</h:form>
I won't post code of the bean #{userRegistrationForm}, there are two Passwords properties with getters and setters.
Any help leading to solution of my problem appreciated. Thanks in advance.
Solved! I just used FacesContext.getCurrentInstance().isValidationFailed() to see if the validation failed or not. In case of failure, the converter now returns null (the conversion won't be done), in other case the converter will return proper object. And the form works fine with the conversion working.
Related
below is my jsf code,
<h:outputText value="SP Id" styleClass="required"/>
<h:selectOneMenu style="padding-left:60px;" class="input" id="spid" required="true" requiredMessage="Select SP Id"
value="#{applicationController.spid}">
<p:ajax listener="#{applicationController.onFromChange()}"
update="fromnames" />
<f:selectItem itemValue="" itemLabel="--Select--" />
<f:selectItems value="#{applicationController.spids}"></f:selectItems>
</h:selectOneMenu>
<h:message for="spid" class="hmsg" />
<h:outputText value="Sp Name" class="left1"/>
<h:inputText class="input" id="fromnames"
value="#{applicationController.spname}" />
<h:message for="fromnames" />
backing bean code is(method),
public void onFromChange() {
if (spid != null && !spid.equals("")) {
int spId = Integer.parseInt(spid);
spname = baseService.getSalesPersonById(spId);
} else {
}
}
//setter-getters
public String getSpname() {
return spname;
}
public void setSpname(String spname) {
this.spname = spname;
}
public List<Integer> getSpids() {
return spids;
}
public void setSpids(List<Integer> spids) {
this.spids = spids;
}
from above code every thing works fine.
problem:if i select f:selectItems values, relating values(spname)
are displaying. after selecting f:selectItem spname should set to null but it's not setting to null, instead of that previous values are displayed.
change jsf code as below,
<h:selectOneMenu style="padding-left:60px;" class="input" id="spid" required="true" requiredMessage="Select SP Id"
value="#{applicationController.spid}">
<p:ajax listener="#{applicationController.onFromChange()}"
update="myForm1" event="change" process="#this"/>
<f:selectItem itemValue="0" itemLabel="--Select--" noSelectionOption="false" />
<f:selectItems value="#{applicationController.spids}"></f:selectItems>
</h:selectOneMenu>
<h:message for="spid" class="hmsg" />
and modify backing bean method as,
public void onFromChange() {
if (spid != null && !spid.equals("")) {
try{
int spId = Integer.parseInt(spid);
spname = baseService.getSalesPersonById(spId);
}
catch(Exception exception){
spname = null;
}
} else {
spname = null;
}
}
I have one p:selectManyMenu where I can choose multiple items, but I can't manage to get that values, it is always null so I'm not sure if I'm making mistake in processing components or my converter isn't good. Here is XHTML:
<h:form id="form">
<p:selectManyMenu id="advanced" value="#{pickListView.chosenItems}" converter="converterTest"
var="t" filter="true" filterMatchMode="contains" showCheckbox="true" >
<f:selectItems value="#{pickListView.allEquipment}" var="record" itemLabel="#{record.name}" itemValue="#{record}"/>
<p:column style="width:90%">
<h:outputText styleClass="f_text" value="#{t.name} - #{t.price}" />
</p:column>
</p:selectManyMenu>
<p:commandButton id="pojoSubmit" value="Spremi" oncomplete="PF('dlg').show()" actionListener="#{pickListView.saveRecords}" update=":form:table-wrapper" style="margin-top:5px" process="#this" />
<p:dialog header="Selected Values" modal="true" showEffect="fade" widgetVar="dlg" resizable="false">
<p:panelGrid columns="1" id="display" columnClasses="label,output">
<p:dataList value="#{pickListView.chosenItems}" var="t">
<h:outputText value="#{t}" />
</p:dataList>
</p:panelGrid>
</p:dialog>
</h:form>
So, my List<Equipment> chosenItems should contain selected items but is always null. I don't know what should I've done wrong, maybe it's up to converter not managing to return asObject, but I print data from converted object before return, as you can see below, and it's ok, so I'm very confused now...
Here is my Converter:
#FacesConverter(value = "converterTest")
public class ConverterTest implements Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if(value != null && value.trim().length() > 0) {
try {
SessionFactory factory = HibernateUtil.getSessionFactory();
Session session = factory.openSession();
Equipment o = (Equipment) session.get(Equipment.class, Integer.valueOf(value));
System.out.println("EQUIPMENT: " + o.getName() + " : " + o.getId());
return (Equipment) session.get(Equipment.class, Integer.valueOf(value));
} catch(NumberFormatException e) {
throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Conversion Error", "Not a valid equipment."));
}
}
else {
return null;
}
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object object) {
return object instanceof Equipment ?
((Equipment) object).getId().toString() : "";
}
}
In bean I created two lists, one for all items and one for selected items with their getters and setters. Problem is that chosenItems list is always null.
private List<Equipment> chosenItems;
private List<Equipment> allEquipment;
//getters and setters
Any thoughts? If you need more details, feel free to ask. Thank you in advance!
I have a problem, well when I save my object to the DB it works fine, but when i want to retrieve it from the DB doesn't work, I'm using selectItemsConverter by Omnifaces
I have my Object "Modelo" which has two other objects inside, which are "Marca" and "Gama"
These are my Java entities (the toString() is for Omnifaces):
Modelo:
private Marca marca;
private Gama gama;
getters and setters...
#Override
public String toString() {
return String.format("%s[codigo=%d]", getClass().getSimpleName(), getCodigo());
}
Marca:
getters and setters...
#Override
public String toString() {
return String.format("%s[codigo=%d]", getClass().getSimpleName(), getCodigo());
}
Gama:
getters and setters...
#Override
public String toString() {
return String.format("%s[codigo=%d]", getClass().getSimpleName(), getCodigo());
}
Well and this is my managedBean
ModeloBean
#ManagedBean
#ViewScoped
public class ModeloBean {
private Modelo modelo = new Modelo();
getters and setters ...
//This is for call the DB to retrieve the value, and works fine, but i cant show the preselected value to the xhtml
public void leer(Modelo mo) throws Exception {
ModeloDAO dao = new ModeloDAO();
try {
this.init();
this.modelo = dao.leer(mo);
} catch (Exception e) {
throw e;
} finally {
dao = null;
}
}
This is my xhtml Page
I have a dialog which I used it for save and update an object
<p:dialog id="dlgDatos" widgetVar="wdlgDatos" modal="true" appendToBody="true" header="#{modeloBean.accion}" draggable="false" resizable="false">
<h:form>
<h:panelGrid columns="2">
<p:outputLabel value="Marca" />
<p:selectOneMenu value="#{modeloBean.modelo.marca}" converter="omnifaces.SelectItemsConverter" filter="true" filterMatchMode="startsWith" required="true">
<f:selectItem itemLabel="Seleccione" itemValue="#{null}" noSelectionOption="true" />
<f:selectItems value="#{marcaBean.lstMarcasVigentes}" var="marca" itemLabel="#{marca.nombre}" itemValue="#{marca}" />
</p:selectOneMenu>
<p:outputLabel value="Gama" />
<p:selectOneMenu value="#{modeloBean.modelo.gama}" converter="omnifaces.SelectItemsConverter" filter="true" filterMatchMode="startsWith" required="true">
<f:selectItem itemLabel="Seleccione" itemValue="#{null}" noSelectionOption="true" />
<f:selectItems value="#{gamaBean.lstGamasVigentes}" var="gama" itemLabel="#{gama.nombre}" itemValue="#{gama}" />
</p:selectOneMenu>
<p:outputLabel for="txtNombre" value="Modelo" />
<p:column>
<p:inputTextarea id="txtNombre" value="#{modeloBean.modelo.nombre}" />
<p:watermark for="txtNombre" value="Para registrar varios modelos, sepárelos por comas (,)" />
</p:column>
<p:outputLabel value="Vigencia" rendered="#{modeloBean.accion eq 'Modificar'}"/>
<p:selectBooleanCheckbox value="#{modeloBean.modelo.vigencia}" rendered="#{modeloBean.accion eq 'Modificar'}"/>
<p:commandButton value="#{modeloBean.accion}" actionListener="#{modeloBean.operar()}" oncomplete="PF('wdlgDatos').hide(); PF('wdtLista').clearFilters();" update=":frmLista:dtLista, :msj"/>
<p:commandButton value="Cancelar" immediate="true" onclick="PF('wdlgDatos').hide();"/>
</h:panelGrid>
</h:form>
</p:dialog>
The selectOneMenu works fine for save, but for update only retrieve me the Strings value and not the preselected value of my comboBoxes
This is the dialog which only retrieve the String value of "105" cause is a String and my boolean value for the checkbox "Vigencia" but not my comboBoxes values. Where am I wrong?
I solved it adding this to my entites (hashCode and equals)
#Override
public int hashCode() {
int hash = 5;
hash = 83 * hash + this.codigo;
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Modelo other = (Modelo) obj;
if (this.codigo != other.codigo) {
return false;
}
return true;
}
I have a web application which have to implement login. user provide username and pwd after authenticating user should redirect to page which they have privilages pages are differant from user to user. Sometimes 2 or more users can get same page but available data should differant for do this I have pass users privilage ID(divisionId) to other beans
for now i have tried URL tagging parameter tagged to URL and dirrect to page successfully but I can't take it to bean variable.
Itried this with p:Button then textbox inputs won't get to bean class to execute the method when button click.
xhtml code -
<h:body>
<p:growl id="growl" showDetail="true" life="3000" />
<p:dialog id="dialog" header="Login" widgetVar="dlg" visible="true" closable="false" >
<h:form id="form">
<h:panelGrid columns="2">
<h:outputLabel for="username" value="Username: " />
<p:inputText id="username" value="#{loginBean.username}"
required="true" requiredMessage="Enter Username"/>
<h:outputLabel for="password" value="Password: " />
<p:password id="password" value="#{loginBean.password}"
required="true" requiredMessage="Enter Password"/>
</h:panelGrid>
<p:commandButton id="LoggingButton" value="Login" action="#{loginBean.doLogin()}"
update=":growl" oncomplete="handleLoginRequest(xhr, status, args),">
</p:commandButton>
</h:form>
</p:dialog>
</h:body>
loginbean-
public class LoginBean{
private String username;
private String password;
private int divisionId;
/**
* Creates a new instance of loginBean
*/
public LoginBean() {
}
public String doLogin() {
DbUser du = new DbUser();
divisionId = du.ValidateUser(username, password);
if(divisionId==0)
addMessage("Invalied username or password", false);
else{
if(divisionId==1){
// return "superuser.xhtml?faces-redirect=true";
return "superuser.xhtml?test="+divisionId+"faces-redirect=true";
//superAdmin
}
else if(divisionId==2||divisionId==3){
// return "engadmin_create_div.xhtml?faces-redirect=true";
return "engadmin_create_div.xhtml?test="+divisionId+"faces-redirect=true";
//ENG/IT ADMIN
}
else{
// return "viewonly_user.xhtml?faces-redirect=true";
return "viewonly_user.xhtml?test="+divisionId+"faces-redirect=true";
//View only users
}
}
return null;
}
I think that work :)
<p:growl id="growl" showDetail="true" life="3000" />
<p:dialog id="dialog" header="Login" widgetVar="dlg" visible="true" closable="false" >
<h:form id="form">
<h:panelGrid columns="2">
<h:outputLabel for="username" value="Username: " />
<p:inputText id="username" value="#{loginBean.username}"
required="true" requiredMessage="Enter Username"/>
<h:outputLabel for="password" value="Password: " />
<p:password id="password" value="#{loginBean.password}"
required="true" requiredMessage="Enter Password"/>
</h:panelGrid>
<p:commandButton id="LoggingButton" value="Login" actionListener="#{loginBean.doLogin()}">
</p:commandButton>
</h:form>
</p:dialog>
</h:body>
Bean
public class LoginBean{
private String username;
private String password;
private int divisionId;
/**
* Creates a new instance of loginBean
*/
public LoginBean() {
}
public static void redirect(String strDes) throws IOException {
ExternalContext ext = FacesContext.getCurrentInstance().getExternalContext();
ext.redirect(ext.getRequestContextPath() + strDes);
}
public void doLogin() {
DbUser du = new DbUser();
divisionId = du.ValidateUser(username, password);
if(divisionId==0)
addMessage("Invalied username or password", false);
else{
if(divisionId==1){
LoginBean.redirect("superuser.xhtml?test="+divisionId+"faces-redirect=true");
//superAdmin
}
else if(divisionId==2||divisionId==3){
LoginBean.redirect("engadmin_create_div.xhtml?test="+divisionId+"faces-redirect=true");
//ENG/IT ADMIN
}
else{
LoginBean.redirect("viewonly_user.xhtml?test="+divisionId+"faces-redirect=true");
//View only users
}
}
}
you get parameter from bean:
Map<String,String> params =
FacesContext.getExternalContext().getRequestParameterMap();
String action = params.get("test");
i am using this way in custom validation i am little bit confused if this way is correct or not if i assumed that i have this form:
<h:form id="myForm>
<h:outputText value="user name" />
<h:inputText value="#userBean.userName" id="userName" />
<h:outputText value="Password" />
<h:inputText value="#userBean.Password" id="passwd" />
</h:form>
and i have its Managed Bean :
#ManagedBean(name="userBean")
#SessionScoped
public class UserBeanData{
private String userName;
private String password;
// with setters and getters........
//
}
and the custom validator to validate the Managed Bean field and the Implmentation like :
#Override
public validate(FacesContext context, UIComponent component, Object value) throws ValidatorException{
Map<String, String> params = context.getExternalContext().getRequestParametersMap();
String username = params.get("myForm:username");
String pass = params.get("myForm:passwd");
// validate : if fields are not null check if the user exists if the result is empty , throws a validation Message Error
}
My Question is : Retrieving the Managed bean values like this is true or not ????
You're basically looking for the solution in the wrong direction. Validation is only applicable on the individual submitted values, e.g. minimum/maximum length, non-empty/null, regex pattern, etcetera. But you want to invoke a business action based on all submitted values: logging-in an user. This is not exactly input validation.
Just add required="true" to the both input components and perform the job in the action method.
E.g.
<h:form id="myForm>
<h:outputText value="user name" />
<h:inputText value="#{userBean.userName}" id="userName" />
<h:message for="userName" />
<h:outputText value="Password" />
<h:inputSecret value="#{userBean.password}" id="passwd" />
<h:message for="passwd" />
<h:commandButton value="Login" action="#{userBean.login}" />
<h:messages globalOnly="true" />
</h:form>
with
#ManagedBean
#RequestScoped
public class UserBean {
private String userName;
private String password;
#EJB
private UserService service;
public String login() {
User user = service.find(userName, password);
if (user != null) {
FacesContext.getCurrentInstance().getExternalContext().getSessionMap("user", user);
return "home?faces-redirect=true";
} else {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Unknown login"));
return null;
}
}
// ...
}
Pay attention to the validate method's firm. It has an UIComponent parameter that is the component validated by the method. This UIComponent has both the current value (getValue()) and the value that the user submitted (getSubmittedValue()).
You might have to cast that UIComponent to the particular type of component you're validating (int this case, it's an UIInput).
Now, if you're going to validate both username and password prior to a log in, there are several ways to do it. In your case, validating the username field with the password field as an added parameter should suffice. You can achieve that by doing this:
<h:outputText value="user name" />
<h:inputText value="#userBean.userName" id="userName" validator="#{yourBean.validateLogin}">
<f:attribute name="pass" value="#{passwordField}" />
</h:inputText>
<h:outputText value="Password" />
<h:inputText value="#userBean.Password" id="passwd" binding="#{passwordField}"/>
Note that the binding in the password <h:inputText/> is related to the value of the pass of the <f:attribute/> tag nested in your username <h:inputText/>. With this setup, you can perform your validation like this:
public void validateLogin(FacesContext context, UIComponent component, Object value) throws ValidatorException {
//I suppose it's a typo, but your validate method lacks the return type.
String username = (String) value;
UIInput passwordInput = component.getAttributes().containsKey("pass") ?
(UIInput) component.getAttributes().get("pass") : null;
if(passwordInput != null) {
//Just to be sure the input was added as a parameter successfuly
String submittedPassword = passwordInput.getSubmittedValue();
//Now, do your validations based on the strings "username"
//and "password".
}
}
Since all of this is being done in the validation phase, the values aren't set in your managed bean yet, that's why you have to play around a little with the submitted values.