Is it possible to perform some actions (some cleanup) if jsf validation errors occur?
Fields are validated with tags in xhtml, for example 'required="true"', 'f:validateRegex pattern="\d*"', 'f:validator validatorId="someValidator"'.
I need to set some property field of managed bean to null (when there are any failures on the page).
But if validation fails, then JSF goes to Render Response Phase and managed bean method is not invoked.
Listener (using f:actionListener tag) also is not invoked in that case.
Now I'm thinking about to replace xhtml validation by validation using bean annotations like #AssertTrue, #Size, etc.
Then in some of this validating methods it would be possible to make a cleanup:
#ManagedBean
class SomeBean {
...
#AssertTrue
public void isClenup() {
cleanup();
}
...
}
But it seems not a good solution to me. Also I noticed that several methods annotated with #AssertTrue are called in undefined order. Therefore switching from xhtml validation to bean annotations validation is getting not so easy.
Is it possible to define some order of calling methods annotated with #AssertTrue?
In fact I have quite ordinary task: there is a page with search functionality.
On search success with no errors the result should be shown, but if validation errors occur (during next search), then previous result should not be shown (but it was visible and that was a problem).
My plan was as follows: to check for validation failures in initialize() method using facesContext.isValidationFailed() and if it is true, then to hide (delete) previous search results:
public void initialize() {
FacesContext context = FacesContext.getCurrentInstance();
boolean validationFailed = context.isValidationFailed();
if(validationFailed) {
clearPreviousSearchResult();
}
}
But then I found out that validation using bean annotations (like #AssertTrue) does not set facesContext.validationFailed();!
I.e. after this
#AssertTrue(message = "Some error message")
public boolean isValidateSomeField() {
return validate(getSomeFieldValue());
}
you get context.isValidationFailed() == false when fails occur (though I expected true)
(xhtml validation or validator or f:validator do set facesContext.validationFailed() as expected)
Therefore it is necessary to set context failed manually:
#AssertTrue(message = "Some error message")
public boolean isValidateSomeField() {
if(!validate(getSomeFieldValue())) {
FacesContext.getCurrentInstance().validationFailed();
return false;
}
return true;
}
But due to How to check in after phase of Validations phase if validation has failed? I realized that the problem can be resolved much more easier! Just to wrap with couple of lines:
<h:panelGroup rendered="#{!facesContext.validationFailed}">
...block not to show if validation errors occur...
</h:panelGroup>
And no need to use annotations bean validation and some initialize() method!
If a validation exception is thrown during the JSF validation phase then none of the submitted form values will be applied to the model. Also none of the invoked events that would otherwise execute during the Invoke Application JSF phase will be called. You do notice however that Render will still occur, and any components that need to be rendered or updated will still do so.
In theory this should be sufficient for rolling back most any user submissions if any of those submissions were invalid, however there are a few edge cases where additional cleanup will need to occur. I urge you however to closely evaluate the design decisions that led you to this need in the first place, as it is possible that perhaps there is a better way to meet your business requirements without having to resort to this.
With that being said, I would perform a Pre Render event that will execute on every postback and check for certain validations and perform necessary business and presentation logic.
<f:event listener="#{managedBean.initialize()}" type="preRenderView" />
Related
I have my regex patterns stored like:
private final Pattern regex1...
private final Pattern regex2...
As fields in my view. I have a validation check method in the view class which throws an exception to the controller when validation fails. Is this valid in MVC or not?
public void validation() throws Exception{
if(regex failed){
throw new exception("...");
}
...
}
It is always somehow up to you how you splitt the code, if there is a good reason behind your decision.
However, I would prefer to put the validation methode at least into the controller, because it looks like it will be triggered by an actionevent from a button. (Events should be handled in the controller)
What you can do, is to create a methode in your view, which shows an error message in the gui, if your validation has failed.
All this implice that also the regex is saved in the controller.
It is not good practice. Logic has to be moved into dedicated layed.
Best way is creating dedicated validator class OR create validation method of a service (if some operations like search in DB have to be done during the validation). In that way validator class can be well covered by unit tests.
#Autowire
UserInputValidator userInputValidator;
public void validation() throws Exception{
if(userInputValidator.validate(param1, param2)){
throw new exception("...");
}
...
}
While we're talking about MVC, it's always best to consider that as the app evolves, "input" may come from more than one place eventually.
User
service call
file
other
In this case we wouldn't want to build the validation mechanisms into the View or the Controller, but into another component that the Controller would just use/integrate with.
Validation can be a cross cutting concern (but not always)
Ideally we would want to avoid duplicating the validation of incoming data especially if the data is always valid in the same way. Duplicating the validation can cause inconsistencies. Imagine data being invalid from the UI, but the same data being considered "ok" from a service call.
There are a number of ways that you can separate the validation logic from your view:
Annotate beans for JSR-303
Create custom validation annotations (abstracting your defined regex's) and/or use libraries that provide some basic ones
Dedicated service
Resolving validation failures
I can see that you're throwing an exception when you have a validation failure. Consider the awesome article by Martin Fowler. The suggestion is that a validation failure can be expected and is not an Exception case. He also suggests a notification approach.
Another advantage of a notification approach is that your dedicated validation service/tier can support multiple validation failures. This would allow your view to highlight multiple fields or your API to return a list of failures.
I have a login.jsp page in my application. I am using Struts 2 and a simple validate() method to validate my form. I have two questions:
validate() method in my form bean class validates the form. I.e checks for empty fields etc. If I need to check my username and password combination should I do this inside validate() or in my action class?
If I am doing the same in my Action class, correct combination leads to success page. I want the incorrect combination to lead to my JSP page along with the error message: "Incorrect combination". How can I check in my JSP page that the request has come from action class so that it can print the error message "Incorrect combination"?
Authentication belongs in the action, not in validation, IMO.
I might consider using XML or annotation validations for the fields themselves and put the login attempt in validate(), but the code is small, and I'd be pretty comfortable with it either way.
public String execute() {
if (userService.loginValid(username, password) {
return SUCCESS;
}
addActionError(getText("login.failure"));
return FAILURE;
}
I would use the framework's support for action-level error messages rather than using a flag (and I wouldn't duplicate that flag with a local if I did), and I strongly recommend using something you can inject to do the actual logging in to make testing easier.
Using the validate() approach makes things pretty tight:
public void validate() {
if (!userService.loginValid(username, password)) {
addActionError(getText("login.failure"));
}
}
Assuming you define reasonable "input" and "success" results that might be all you need. If developers looking at the code are familiar with the framework the validate() version is relatively clear.
If you're not interested in using XML or annotation validations, you can do that manually as well. That definitely belongs in validate(), and for common utility methods like this, static imports make the code still relatively concise:
public void validate() {
boolean tryLogin = true;
if (isBlank(username)) {
addFieldError("username", getText("login.username.required"));
tryLogin = false;
}
if (isBlank(password)) {
addFieldError("password", getText("login.password.required"));
tryLogin = false;
}
if (tryLogin && !userService.loginValid(username, password)) {
addActionError(getText("login.failure"));
}
}
(I added the tryLogin flag to avoid seeing the error message for a login that will obviously fail, although this could be handled in other ways as well. Post-login processing elided.)
I would say you definitely don't want the login logic in the validate method; that's for validating data.
I would suggest that if your login fails, just expose a data property on the action like:
execute () {
boolean authenticated = login( getUsername(), getPassword() );
setLoginValid( authenticated );
if ( authenticated )
result = SUCCESS;
else
result = FAILURE;
return result;
}
And then in your login.jsp, simply wrap a message about bad credentials in the struts if tag, with a test on the loginValid property.
The purpose of the validation framework is to check field values to be valid to prevent unexpected errors while executing the action.
It is a good practice to separate the validation logic from the business logic. Authentication has nothing to do with validation logic. It is a separate process provided by security mechanisms. Of course you can create the action or interceptor that performs authentication, and as with any action you can configure it for validation.
In Struts2 it's even more simplified by applying a validation interceptor is a part of the job for processing request. In more sophisticated scenarios authentication becomes a part of the business logic, but the method to validate the input fields renames the same. If your action is only do is authenticating then you may not require the validation to process authentication.
To your second question: all you need is to addActionError(getText("error.key")) to invalidate the action. Then return to the result where <s:actionerror> to display the message.
What is more important the validation logic remains the same if you decide to move it to the action. In this case the only thing you have to do is to remove the validation stack. The only reason of such validation is to return the result that is different than "input".
I have a small JSF application and the scope of the pages are request. I would like to have a method in my JSF's managed bean for logging user_id and page name to database. When I added this method to the constructor of bean, details are getting logged for every method is being called due to the fact that scope of the page is request.
What is the best way to log the above details only once when user first access the pages after logging into my application? Idea is which all pages user visited for each logging.
What is the best way to achieve this?
My JSF version is 1.1.
Thanks
You can add a method to the bean and invoke it from the page when the page is loaded. For example
add this into the page:
<h:outputText value="#{fooBean.logUser}"/>
bean method:
public void logUser(){
//log user and page
}
This way the method is only invoked once the page is loaded. If you get a method not found
error, then another option is to use a hidden form hack. For example:
<body onload="document.getElementById('formId:buttonId').click()">
<h:form id="formId" style="display: none;">
<h:commandButton id="buttonId" value="submit" action="#{fooBean.logUser()}" />
</h:form>
...
</body>
So, you want to log into a database table all accesses of all users to the different pages of your site but, avoiding logging post-backs, right? (a post-back happens when a user performs an action in one of your pages and the URL that receives the action is the same than the one from where the action was launched - it's very common in JSF, specially on versions prior to 2.x)
So, basically, what you need is to recognize when a post-back happens and avoid logging under that condition. The ResponseStateManager will provide you with a isPostback(...) method that returns true when processing post-back requests:
FacesContext context = FacesContext.getCurrentInstance();
ResponseStateManager rsm = context.getRenderKit().getResponseStateManager();
if (!rsm.isPostback(context)) {
// do whatever you need here
}
By the way, I wouldn't recommend to put that code in the bean constructor at all as different JSF implementations may perform some bean lifecycle management tasks right after invoking the bean's constructor. If you think that logic should be part of the "bean initialization process" I suggest putting that code in a separate public method annotated with a #PostConstruct annotation.
However, if you want that logic to be run in every single access to the given pages, using a managed bean will force you to either copy & paste that logic in every bean or define an abstract/base class with that logic and make all your beans extend that one. I like to keep all my managed beans as close as possible to the POJO concept so, as an alternative, I would consider implementing the same logic but using a PhaseListener tied to the RENDER_RESPONSE phase. It will give you a under-the-hood (much cleaner) and versatile approach: if some day you want to log actions instead of renders then you tie your listener to the INVOKE_APPLICATION phase, etc.
P.D.: I hope you are using some kind of cache or 'batching' technique to log those records to your database, otherwise you will have a noticeable performance impact when too many users are surfing your site. Also, in my own opinion, you should update your JSF version to, at least, 1.2, and you'll avoid some annoying bugs or unexpected behaviour...
I have a JSF page where users can enter their car into my database. The form has three input fields:
Manufacturer
Model
Registration
The Manufacturer and Model field are both autocompletion fields. In order to complete the Model field, I need to know what value the user selected in the Manufacturer field prior to submitting the form. To that end, I set up an AJAX call to inform the managed bean of the selected value:
<p:autoComplete id="manufacturer"
minQueryLength="3"
completeMethod="#{carController.complete}"
forceSelection="true">
<p:ajax event="itemSelect"
listener="#{carController.manufacturerSelected}" />
</p:autoComplete>
And in the managed bean:
public void manufacturerSelected(SelectEvent se) {
manufacturer = se.getObject().toString();
}
The autocomplete field and handler method for the model look about the same, with slighly different values.
To retain the manufacturer value across the multiple XHR requests, I have set the bean to ConversationScoped and begin the conversation in a #PostConstruct annotated method:
#Named
#ConversationScoped
public class CarController implements Serializable {
#Inject
private Conversation conversation;
#PostConstruct
private void init() {
conversation.begin();
}
What I would expect is the bean getting only instantiated once for the page because the conversation has not been ended yet, and retaining the value in the manufacturer field. This, however, does not hold true, and the bean is instantiated again for each XHR request, causing the manufacturer field to be null as well. Setting a breakpoint in the PostConstruct method revealed that it is in fact getting called and so is the manufacturerSelected method.
I suspect this has something to do with the fact that I am not manually propagating the conversation ID but the documentation says that this ID should automatically be propagated with any faces request. Is this in fact true, and, does that mean that XHR requests are not necessarily faces requests?
Edit: Setting breakpoints at various locations in the bean has revealed that each XHR request has a new bean (conversation.getId() keeps changing) so I am obviously not propagating the ID right. How would one propagate the ID with p:ajax and where can I get it with EL?
Since you're not really using a conversation (at least not in the example you give), why not use the view scope? This will do exactly what you want, without the overhead of having to propogate a conversation id.
Do note that for #ViewScoped to work, you have to change the bean to a JSF managed bean (remove #Named). This is due to a design bug/spec oversight in Java EE 6. If you want to keep using CDI, then there's a Java EE 6 extension from Seam 3 available that fixes this bug.
Yup. This is an issue with JSF 2 and Primefaces together not propagating the conversation id. You can try the below workaround. (This is for other who will end up here due to the same issue).
<p:autoComplete id="manufacturer"
minQueryLength="3"
completeMethod="#{carController.complete}"
forceSelection="true" onchange="updateManufacturer([{name:'cid',value:'#{javax.enterprise.context.conversation.id}'}])">
</p:autoComplete>
<p:remoteCommand name="updateManufacturer" action="#{carController.manufacturerSelected}"
process="manufacturer" />
I have a dynamic Facelets page that needs to show information from database when the page loads. At this point in the flow, there have not been any form submissions. Every JSF example I can find only shows a form submission with dynamic results on the next page.
Every call I make to our database is currently takes place after an action has been triggered by a form submission. Where should this code go if there hasn't been a form submission, and how do I trigger it? A code snippet would really help me out!
You should be able to do your initialization work in the constructor (or lazily in one of your accessors) of your managed bean.
If you're using Spring integration (see here also), it's easy.
In your backing bean, simply use something like:
public class BackingBean implements InitializingBean
{
public void afterPropertiesSet()
{
loadInitialData();
}
}
If you're not integrating with Spring there are two options:
Load the initial data in the class constructor;
In your faces-config.xml, you can set properties to be injected. Properties are guaranteed to be set in the order they're specified in the config file. So, just create a dummy property and then within that method load up your default data. i.e. create a method public void setLoaded(boolean loaded) { loadInitialData(); }, and in your faces-config.xml have 'loaded' being set as a property on that backing bean.
Hope this is all clear!
You write (with my emphasis added):
Every call I make to our database is currently takes place after an action
has been triggered by a form submission. Where should this code go
if there hasn't been a form submission, and how do I trigger it? A
code snippet would really help me out!
It sounds to me that you want to retrieve information from the database prior to form submission.
It seems to me that you want to make an Ajax call to query the database. The Ajax call can fire on a different event than the form submisson event. This will probably entail using Javascript rather than the Faces framework.