Java JSF About Custom Validation - java

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.

Related

JSF access html element value in bean class

I have a JSF application in which I have a combo box.
<h:selectOneMenu id="collectorType"
value="#{activityDataSource.object.type}"
rendered="#{empty activityDataSource.object.id}"
disabled="#{!sp:hasRight(facesContext, 'ManageApplication')}"
readonly="#{!sp:hasRight(facesContext, 'ManageApplication')}"
onchange="$('editForm:selectTypeButton').click();">
<f:ajax event="change"
execute="#this"
render="dsTransformationRule dsCorrelationRule"
listener="#{activityDataSource.handleCollectorTypeChange}" />
<f:selectItem itemValue="" itemLabel="#{msgs.select_collector_type}"/>
<f:selectItems value="#{activityDataSource.collectorTypes}"/>
</h:selectOneMenu>
And I am getting selected value of that combo box in bean class like:
public void setSelectedTransformationRule(String transformationRule)
throws GeneralException {
String collectorType = (String) getRequestParam().get("editForm:collectorType");
}
And I am successful in doing so. I am calling this method through ajax onchage event of combobox.
But if I try to get same combo box value in a different method i get null value.
public void handleCollectorTypeChange() throws GeneralException {
String collectorType = (String) getRequestParam().get("editForm:collectorType");
}
Any help !
Because Process Events happens before Update Model Values you can retrieve the value from the component, from the UIViewRoot like this:
HtmlSelectOneMenu collectorTypeSelectMenu = (HtmlSelectOneMenu) FacesContext.getCurrentInstance().getViewRoot().findComponent("editForm:collectorType");
String collectorType = (String) collectorTypeSelectMenu.getValue();
try put the attributes process and partialSubmit in your ajax call with the values you need process like this:
<f:ajax event="change"
execute="#this"
render="dsTransformationRule dsCorrelationRule"
process="#this, collectorType"
partialSubmit="true"
listener="#{activityDataSource.handleCollectorTypeChange}" />
In the process atrribute you can put all ids you need to process with the updated values (like you see in the screen.

JF2 Dynamic form element doesn't remember input and page refreshes every time I add element

I am trying to make a form with options to add rows. However, after I type in some input and click the add button again, the input I enter disappears. I'm not sure what is wrong with my code. In addition, when I click the add button, the page refreshes. Is there way to stop this page refresh?
Person.java
public class Person{
private List<String> guys = new ArrayList<String>();
public List<String> getGuys() {
return guys;
}
public void setGuys(List<String> guys) {
this.guys = guys;
public void addNewItem(){
guys.add("");
}
}
form.xhtml
<h:form>
<h:panelGrid columns="2">
<h:outputText value="Guys: " />
<h:dataTable value="#{person.guys}" var="men">
<h:column>
<p:inputText value="#{men}" />
</h:column>
</h:dataTable>
<h:commandButton name="add" value="Add" action="#{person.addNewItem}" />
</h:panelGrid>
<br />
<h:commandButton name="submit" type="submit" value="Submit"></h:commandButton>
</h:form>
Provided that the bean is placed in the right scope for the functional requirement, the view scope, the only major mistake left is that you're expecting that the String class has some magic setter method.
It hasn't. The String class is immutable. The following will never work on a String:
<p:inputText value="#{men}" />
You have 2 options:
Create a real model class. You can find complete examples in the following answers:
How to dynamically add JSF components
Recommended JSF 2.0 CRUD frameworks
Set the value by row index instead:
<h:dataTable binding="#{table}" value="#{person.guys}">
<h:column>
<p:inputText value="#{person.guys[table.rowIndex]}" />
</h:column>
</h:dataTable>
(note: no additional bean property necessary for the table! the code is as-is)
This does basically a person.getGuys().add(table.getRowIndex(), submittedValue). I.e. the setter is invoked on the List itself, which works perfectly fine. See also the following related answers concerning ui:repeat:
Using <ui:repeat><h:inputText> on a List<String> doesn't update model values
How map multiple inputText to an array property?
You never update your list, you are just adding empty items. You should do something like this:
Person.java (viewscoped)
public class Person implements Serializable {
private List<String> guys = new ArrayList<String>();
private HtmlDataTable dtGuys;
public void addNewItem() {
guys.add("");
}
public void addToList(ValueChangeEvent e) {
guys.set(dtGuys.getRowIndex(), e.getNewValue().toString());
}
public String save() {
System.out.println("saving...");
for (String item : guys) {
System.out.println("item= " + item);
}
return null;
}
//gettes and setters
}
form.xhtml
<h:form id="frmPrincipal">
<h:panelGrid columns="2">
<h:outputText value="Guys: " />
<h:dataTable value="#{person.guys}" var="men" binding="#{person.dtGuys}" >
<h:column>
<p:inputText value="#{men}" valueChangeListener="#{person.addToList}" />
</h:column>
</h:dataTable>
<h:commandButton name="add" value="Add" action="#{person.addNewItem}" />
</h:panelGrid>
<br />
<h:commandButton id="submit" name="submit" value="Submit" action="#{person.save}"/>
</h:form>
Using jsf 2.0.10 and primefaces 3.5
Its because you don't have an scope for that bean, so its request scoped, so when you call the action the bean is created again, you can fix this using a sessionScope or conversationScope

How to send/recieve data to/from bean function using JSF Richfaces AJAX?

I'm trying to get some code working in an XHTML/JSF/Spring application through which I send an ID to a bean function and expect a string in return. I haven't found an understandable tutorial on this nor any answered question here on SO.
XHTML:
<h:form>
<h:inputText id="inputId" value="#{npBean.idString}"/>
<a4j:commandButton value="get def" render="out">
<f:param value="#{npBean.idString}" name="id" />
<f:setPropertyActionListener target="#{npBean.definition}"/>
</a4j:commandButton>
<a4j:outputPanel id="out">
<h:outputText id="outputId" value="#{npBean.def}"
rendered="#{not empty npBean.def}"/>
</a4j:outputPanel>
</h:form>
Java:
public String getDefinition(int id)
{
def = this.getXService().getXData(id).getDefinition();
return def;
}
All values shown have their getters and setters in the bean.
What we basically do:
Map the value of the <h:inputText> component to a property (with getter/setter) in the managed-bean (which is called myBean)
By using the reRender attribute of the <a4j:commandButton> component, we point which component on the page to be re-rendered (refreshed) when the button is clicked.
When clicking on the button, the invokeService() method from the managedBean is executed and it updates the other property of the managedBean.
In the <h:panelGroup> below, we have several <h:outputText> components and with the rendered attribute we specify when a component has to be displayed on the page.
Exploring the managed-bean, the only thing that is required, are the accessors for the property, which holds the result from the service invoke.
Here's the *.xhtml sample:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
<a4j:form>
<h:panelGrid columns="3">
<h:outputText value="String value:" />
<h:inputText value="#{myBean.value}" />
<a4j:commandButton value="Click" reRender="out">
<a4j:actionListener listener="#{myBean.invokeService}" />
</a4j:comandButton>
</h:panelGrid>
</a4j:form>
<rich:spacer height="7"/>
<br />
<h:panelGroup id="out">
<h:outputText value="Service returned: " rendered="#{not empty myBean.result}" />
<h:outputText value="#{myBean.result}" />
</h:panelGroup>
</ui:composition>
Managed-bean:
#ManagedBean(name = "myBean")
#SessionScoped //for example
public class MyBean {
private String value;
private String result;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getResult() {
return result;
}
public void invokeService(ActionEvent actionEvent) {
this.result = "Hello, " + value + "!";
}
}
As #Luiggi mentioned, the accessor methods MUST meet the following conventions (if we assume you have a private <some-type> property; in the managed-bean.)
public <some-type> getProperty {
return property;
}
public void setProperty(<some-type> property) {
this.property = property:
}
In order to learn how the RichFaces components work, combined with good code examples, I suggest you open this address and play around with the components.

JSF converter does not work after validation in PrimeFaces form

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.

Why can I not get the submitted value from component binding?

In register.xhtml page, I have 2 inputText components for password and confirm password as following:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.prime.com.tr/ui"
xmlns:f="http://java.sun.com/jsf/core">
<h:form>
<h:outputText style="font-weight: bold" value="Password: " />
<p:password feedback="true" minLength="9"
binding="#{mrBean.passwordComponent}"
id="password" value="#{mrBean.password}"/>
<p:message for="password" id="passwordMsg" />
<h:outputText style="font-weight: bold" value="Confirm password: " />
<p:password feedback="false" minLength="9"
id="confirmPassword" value="#{mrBean.confirmPassword}"
validator="#{mrBean.validateConfirmPassword}>
<f:attribute name="oriPassword" value="#{mrBean.passwordComponent.submittedValue}"/>
<p:ajax process="password confirmPassword" update="confirmPasswordMsg" />
</p:password>
<p:message for="confirmPassword" id="confirmPasswordMsg" />
</h:form>
</html>
And this is my mrBean:
#ManagedBean
#RequestScoped
public class MrBean {
private String password;
private String confirmPassword;
private UIInput passwordComponent;
public void validateConfirmPassword(FacesContext context, UIComponent toValidate,
Object value) throws ValidatorException {
String passwordStr = (String) toValidate.getAttributes().get("oriPassword");
String confirmPasswordStr = (String) value;
if (!confirmPasswordStr.equals(passwordStr)) {
FacesMessage message = new FacesMessage("The 2 passwords do not match.");
throw new ValidatorException(message);
}
}
}
In another page, I also have a similar bean with similar validate function for email & confirmEmail and it works perfectly. However, I have no idea why it couldn't work here. The passwordStr is always null even though I have already entered the password.
I'd be very grateful if someone could show me what I have done wrong here.
Best regards,
James Tran
JSF components are processed in the order they appear in the component tree. During validations phase, for each component the submitted value will be retrieved by getSubmittedValue(), converted and validated. If no exceptions occurred during conversion and validation, then the submitted value will be set to null and the converted and validated value will be set as local value by setValue().
You're trying to reference the submitted value of the component which has already been processed at that point. The submitted value will only be non-null when conversion/validation failed for that value. You need to reference its local value instead.
<f:attribute name="oriPassword" value="#{mrBean.passwordComponent.value}"/>
See also:
How validate two password fields by ajax? (this example does the other way round, so that you don't need an additional property for confirm password)

Categories

Resources