Spring Framework auditng fields (CreatedAt, UpdatedAt) - spring

I'm working on a Spring Framework project. For fast development process, I'm using Spring Roo (1.3.2). For several entities, I have requirement to store the creation time and last time it was updated. I've made couple of experiments on Spring Roo tutorial project and this is one of the entities and the way I'm trying to do it.
package com.springsource.roo.pizzashop.domain;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord;
import org.springframework.roo.addon.tostring.RooToString;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.Date;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.springframework.format.annotation.DateTimeFormat;
#RooJavaBean
#RooToString
#RooJpaActiveRecord
public class Topping {
/**
*/
#NotNull
#Size(min = 2)
private String name;
/**
*/
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(style = "M-")
private Date createdAt;
/**
*/
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(style = "M-")
private Date updatedAt;
#PrePersist
protected void onCreate() {
createdAt= new Date();
}
#PreUpdate
protected void onUpdate() {
updatedAt = new Date();
}
}
When I create an object (Topping) it's getting the right value for createdAt and leaving "NULL" for updatedAt. Perfect! That's the way it has to be!
But when I update the object (Topping) it's getting the right value for updatedAt and losing the value of createdAt (NULL).
The problem is that when I update the object I am losing the value of createdAt.
Could you tell me why do I get this behavior? Could you help me with a possible solution for it?
However, createdAt and updatedAt fields don't need to appear in the "view" (create.jspx, update.jspx), so I've set its render attributes to false.
These are the forms for creating and updating.
create.jspx
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<div xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:field="urn:jsptagdir:/WEB-INF/tags/form/fields" xmlns:form="urn:jsptagdir:/WEB-INF/tags/form" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:spring="http://www.springframework.org/tags" version="2.0">
<jsp:directive.page contentType="text/html;charset=UTF-8"/>
<jsp:output omit-xml-declaration="yes"/>
<form:create id="fc_com_springsource_roo_pizzashop_domain_Topping" modelAttribute="topping" path="/toppings" render="${empty dependencies}" z="w4+E4tQPCNRPSYVWPNOBUuf9zNE=">
<field:input field="name" id="c_com_springsource_roo_pizzashop_domain_Topping_name" min="2" required="true" z="GRdEGRLiZ0QLjBH0pTEOZ252BD8="/>
<field:datetime dateTimePattern="${topping_ts_date_format}" field="ts" id="c_com_springsource_roo_pizzashop_domain_Topping_ts" render="false" z="user-managed"/>
<field:datetime dateTimePattern="${topping_updated_date_format}" field="updated" id="c_com_springsource_roo_pizzashop_domain_Topping_updated" render="false" z="user-managed"/>
</form:create>
<form:dependency dependencies="${dependencies}" id="d_com_springsource_roo_pizzashop_domain_Topping" render="${not empty dependencies}" z="bkqRYdlfs3kDAjK51P0O+7NiahE="/>
</div>
update.jspx
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<div xmlns:field="urn:jsptagdir:/WEB-INF/tags/form/fields" xmlns:form="urn:jsptagdir:/WEB-INF/tags/form" xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0">
<jsp:directive.page contentType="text/html;charset=UTF-8"/>
<jsp:output omit-xml-declaration="yes"/>
<form:update id="fu_com_springsource_roo_pizzashop_domain_Topping" modelAttribute="topping" path="/toppings" versionField="Version" z="YGl9ujJNQw182uzoCDgi1FdiafQ=">
<field:input field="name" id="c_com_springsource_roo_pizzashop_domain_Topping_name" min="2" required="true" z="GRdEGRLiZ0QLjBH0pTEOZ252BD8="/>
<field:datetime dateTimePattern="${topping_ts_date_format}" field="ts" id="c_com_springsource_roo_pizzashop_domain_Topping_ts" render="false" z="user-managed"/>
<field:datetime dateTimePattern="${topping_updated_date_format}" field="updated" id="c_com_springsource_roo_pizzashop_domain_Topping_updated" render="false" z="user-managed"/>
</form:update>
</div>

The render="false" on fields tags makes that this fields will not be included on page. So, on POST request, this value is missing and Spring Binding doesn't fill it (take a count that Binding process create new instance of entity, doesn't get it form DB). This makes merge operation to set missing values to null.
For more info about this you can read:
Spring MVC 3.0: How do I bind to a persistent object
Is it possible to update only a subset of attributes on an entity using Spring MVC with JPA?
The easiest workaround is include this value in a hidden input of edit form.
On the other hand, take a look to auditing feature of gvNIX. This feature includes auditing (stores creation/update time stamp and user who done it) and and revision log (using Hibernate Envers).
Good luck!

Related

Can't get values from jsf page

My managed bean gets null values from a simple form in a jsf page. In reality I have a fairly developed interface but the problem is happening even with a simple form.
(JSF 2.1.0, java compiler 1.6, primefaces 6.0 and tomcat7)
It seems to be a duplicated question. But, 5 days ago I am looking for the solution to this strange problem. I found a lot of solutions, but it does not work for me. Maybe I did not quite understand them as the answer from BalusC (commandButton/commandLink/ajax action/listener method not invoked or input value not updated) .
The JSF page:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<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:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</h:head>
<h:body>
<h:form>
<h:inputText value="#{notification.typeSelected}"></h:inputText>
<p:commandButton value="Enregistrer"
actionListener="#{notificationBean.filtrer}" process="#this"
style="float:right">
</p:commandButton>
</h:form>
</h:body>
</html>
The managed bean:
package presentation;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.event.ActionEvent;
//import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;
import org.apache.log4j.Logger;
import entities.Contrainte;
import metier.ContrainteMetier;
import metier.ContrainteMetierImp;
#ManagedBean
#SessionScoped
public class NotificationBean implements java.io.Serializable{
private static final long serialVersionUID = 1L;
public static Logger log = Logger.getLogger(ProjetMODBean.class);
private ContrainteMetier contrainteM = new ContrainteMetierImp();
private List<Contrainte> contrainteL;
private List<Contrainte> filtreL;
private List<SelectItem> classificationL;
private String typeSelected;
//Constructeurs
public NotificationBean() {
}
public NotificationBean(ContrainteMetier contrainteM, List<Contrainte> contrainteL) {
super();
this.contrainteM = contrainteM;
this.contrainteL = contrainteL;
}
#PostConstruct
public void init() {
contrainteL = contrainteM.findAll();
classificationL = new ArrayList<SelectItem>();
for(Contrainte c:contrainteL)
{//Attention, il ne faut pas dupliquer les types dans la liste déroulante
classificationL.add(new SelectItem(c.getClassification()));
}
log.info(" dans init je filtre selon: " + getTypeSelected());
}
//Méthodes
public void filtrer(ActionEvent e)
{
setTypeSelected(typeSelected);
log.info("je filtre selon: " + getTypeSelected());
}
The console output:
2017-03-24 18:06:43 INFO ProjetMODBean:57 - dans init je filtre selon: null
2017-03-24 18:06:43 INFO ProjetMODBean:76 - je filtre selon: null
I tried to correct my error but a detail escapes me.
Imho your problem is process="#this" change it to process="#form" (it is default value so change it only if you have good reason) or add id to input and use process="#this idOfInputField".
See question.
Please post questions fully in english.
I will assume, that //Méthodes mean getter/setter for fields (JSF require getter/setter for inputs).
Also use injection for services.
Change method header from public void filtrer(ActionEvent e) to public void filtrer()

TabChangeEvent not reaching listener with validation error

I am currently working on a project using Primefaces 4.0 and JEE 6. As a build-tool we use maven, and we got a JBoss Application Server.
So it was supposed to be simple. When a validation error occurs, I was supposed to prevent a tab-change in my view. Nothing big, but it needed to be done.
What happened next totally flabberghasted me, but first what I did:
Define a backing bean to handle the event.
Define a listener there.
Use <p:ajax /> to fire the tabChange event to my bean.
Well it was simple enough until there. When there were no validation errors, it worked just fine. Then I tried to validate the values in the view against my Model-Bean and was quickly stopped in my tracks.
As soon as I willingly produced errors in the View, to trigger the faces messages, the tabChange listener was not executed anymore. In fact, not even the #RequestScoped controller-class with the listener was constructed.
I proceeded to create a minimal working example with help of the Weld CDI maven archetype.
Now here I stand, at wits end and present to you my example:
home.xhtml:
I removed the surrounding xml-declaration and ui:define stuff, but that's what I took to reproduce it.
<h1>Hello World!</h1>
<p>
Your CDI bean
<code>HelloWorld</code>
says <span style="color: blue;">#{helloWorld.text}</span> using the
Unified EL.
</p>
<h:form id="bv">
<h2>Bean Validation examples</h2>
<p>Enforces annotation-based constraints defined on the model
class.</p>
<p:tabView id="tabView" effect="fade"
effectDuration="normal">
<p:ajax event="tabChange" update="tabView" listener="#{controller.tabChange}"/>
<p:tab title="Tab 1">
<table>
<tr>
<th style="text-align: right;"><h:outputLabel for="letters"
value="Letters:" /></th>
<td><p:inputText id="letters" value="#{helloWorld.letters}" />
<p:message for="letters" errorClass="invalid" /></td>
</tr>
</table>
</p:tab>
<p:tab title="Tab 2">
<p>Random text to be displayed</p>
</p:tab>
</p:tabView>
</h:form>
Controller.java:
here I only removed the package-declaration, for the protection of the innocent.
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
import org.primefaces.event.TabChangeEvent;
#Named
#RequestScoped
public class Controller implements Serializable {
private static final long serialVersionUID = -1126987875831465303L;
public Controller() {
}
#PostConstruct
public void init() {
System.out.println("Constructed " + this.getClass().getSimpleName());
}
public void tabChange(final TabChangeEvent event) {
System.out.println("Listener was reached");
}
}
Last but not least, the model-bean, slightly shortened from what the archetype provides:
HelloWorld.java:
Again I removed the namespace declaration.
import javax.annotation.PostConstruct;
import javax.enterprise.inject.Model;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.NotEmpty;
public #Model
class HelloWorld {
private final String text = "Hello World!";
private String letters;
public HelloWorld() {
}
#PostConstruct
public void initialize() {
System.out
.println(this.getClass().getSimpleName() + " was constructed");
}
public String getText() {
return text;
}
#NotNull
#NotEmpty
#Pattern(regexp = "[A-Za-z]*", message = "must contain only letters")
public String getLetters() {
return letters;
}
public void setLetters(final String letters) {
this.letters = letters;
}
}
It seems that the JSF lifecycle interferes with what I want to do.
Taken from this german webiste:
It seems, that the event listener will only get invoked in the "Invoke Application"-phase.
Assuming that, it becomes quite obvious, that after "Process Validations" we skip to "Render Response" and our whole backing bean gets ignored.
It is possible to circumvent this, using immediate="true", but upon realizing there is a way better solution to the underlying problem I used that on, namely <p:wizard /> instead, that does exactly what I want.

EclipseLink MOXy: Logical operators in XmlPath annotation

Do logical operators work in XmlPath annotations of EclipseLink MOXy?
I tried and could not make it work (no Exception is thrown and nothing is bound to "elements").
For example, I would like to have in a bindings file something like this:
<java-type name="Content">
<java-attributes>
<xml-element java-attribute="elements" xml-path="/a/b/ | /c/d"
type="ElementType" container-type="java.util.List" />
</java-attributes>
</java-type>
Is there a way to achieve the same result from a modification of the bindings without using the logical or in the xml-path?
I can only think of a workaround where one would use getters and settings in the domain model, bind both /a/b and /c/d to elements and have the setters append elements to the List rather then replacing the list upon each call to setElements(). I'd rather handle it in the bindings file, though.
Does there exist a place in the documentation that specifies which parts of XPath are supported in MOXy?
Here is an example of how you could support this use case.
Mapping Document (bindings.xml)
You could use the xml-elements mapping for this use case. On each of the nested xml-element mappings you would specify a different xml-path.
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="forum17977009">
<java-types>
<java-type name="Content">
<xml-root-element/>
<java-attributes>
<xml-elements java-attribute="elements">
<xml-element xml-path="a/b"/>
<xml-element xml-path="c/d"/>
</xml-elements>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
Java Model (Content)
Below is the Java model we will use for this example.
package forum17977009;
import java.util.List;
public class Content {
private List<ElementType> elements;
public List<ElementType> getElements() {
return elements;
}
public void setElements(List<ElementType> elements) {
this.elements = elements;
}
}
jaxb.properties
To specify MOXy as your JAXB provider you include a file called jaxb.properties in the same package as your domain model with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html).
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Input (input.xml)
Below is a sample input document.
<?xml version="1.0" encoding="UTF-8"?>
<content>
<a>
<b/>
<b/>
</a>
<c>
<d/>
<d/>
</c>
</content>
Demo
Below is some demo code you can run to prove that everything works:
package forum17977009;
import java.io.File;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, "forum17977009/bindings.xml");
JAXBContext jc = JAXBContext.newInstance(new Class[] {Content.class}, properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum17977009/input.xml");
Content content = (Content) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(content, System.out);
}
}
Output
Since all of the items are of the same type, they will output based on the xml-path of the first xml-element in the xml-elements mapping:
<?xml version="1.0" encoding="UTF-8"?>
<content>
<a>
<b/>
<b/>
<b/>
<b/>
</a>
</content>
UPDATE
Does there exist a place in the documentation that specifies which
parts of XPath are supported in MOXy?
Here are some examples that should help:
http://blog.bdoughan.com/2010/07/xpath-based-mapping.html
http://blog.bdoughan.com/2011/03/map-to-element-based-on-attribute-value.html
http://blog.bdoughan.com/2010/09/xpath-based-mapping-geocode-example.html
We are going to add some validation on the XPath statements that are entered for mappings. You can track our progress on this using the following link:
http://bugs.eclipse.org/397101

JSF: only able to use sessionscoped view with ajax commandlink

The scenario: I want to partially execute and render part of a form in JSF, using AJAX, through the use of a commandLink. Since this will be done through AJAX, from my understanding ViewScoped should hold the values of the components in the page between AJAX requests.
I created an example below, where I have an input box where an Order Name is entered, the commandLink is pressed (labeled "Enter Order"), the order name from the inputText is added to an ArrayList named "orders", and the "orders" are displayed in a DataTable below the CommandLink.
The AJAX request from the CommandLink executes the inputBox that adds the String value to the "orderName" variable. The AJAX request sends an ActionEvent to the processDataTable() method, that takes the "orderName" value and adds it to the "orders" list. The "orderName" is then nulled. The AJAX request then renders the inputText component with the nulled "orderName", and the DataTable that displays all the previously entered orders, including the newly added "orderName" from this request.
Problem: The code works if I'm using a SessionScoped bean, but NOT if I use a ViewScoped bean. I added System.out.println()'s to the code to see what was happening. If I make the bean SessionScoped, then everything works as planned. The inputText value is set through the set method, the processOrder() method adds the "orderName" String to the "orders" List, and the DataTable is re-rendered to show this added name.
...
With a ViewScoped bean, the "orderName" value is set to the value of the InputText Component, but is "null" inside of the ProcessOrder() method, adds "null" to the "orders" List, and the DataTable has nothing to show besides null.
If I manually add an orderName in processOrder() with orders.add("Some Name") before the "orderName" is added, "orders" will then hold {"Some Order", "null"} and the change to the Orders is still NOT re-rendered with the AJAX.
All works great with a SessionScoped bean and NOT with a ViewScoped bean? I have also tried an Action attribute with the CommandLink instead of the ActionListener, and the same story.. works with SessionScoped but NOT with ViewScoped.
I can only think of two things here, 1) Either I am missing a crucial point in how AJAX and CommandLink work together, and how ViewScoped is supposed to work (very possible); or 2) for some reason, how I submit the AJAX call with CommandLink it is refreshing the page each time it is clicked, thus erasing previous values of the "orders" list. However this still does not explain why if I manually enter an order into the List, it is still not rendered in the AJAX request with a ViewScoped bean, but WILL with a SessionScoped bean.
Help please!!??
Here's my code:
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ActionEvent;
#Named(value = "testBean")
#ViewScoped
public class DataTableTest implements Serializable {
private String orderName;
private List<String> orders = new ArrayList<String>();
public DataTableTest () {}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
System.out.println(orderName + " in setOrderName");
}
public List<String> getOrders() {
return orders;
}
public String processDataTable(ActionEvent event) {
System.out.println(orderName + " before getting added to orders list in processDataTable");
orders.add(orderName); // adds the orderName to the orders list, so it can be viewed in the DataTable
orderName = null; // nulling variable so it displays BLANK once again on the form
// Loops through and displays order names in the orders list
for (String name : orders) {
System.out.println(name + " in orders List");
}
return null;
}
}
and here's my jsf page:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Test</title>
</h:head>
<h:body>
<h:form>
<h:panelGrid columns="3">
<h:outputText value="Enter Order Name >>" />
<h:inputText id="orderName" value="#{testBean.orderName}" label="# {testBean.orderName}" />
<h:message for="orderName" />
</h:panelGrid>
<h:commandLink value="Enter Order" actionListener="#{testBean.processDataTable}">
<f:ajax execute="orderName dataTable" render="orderName dataTable" />
</h:commandLink>
<h:dataTable id="dataTable" value="#{testBean.orders}" var="order">
<f:facet name="header">Orders Entered Shown Below: </f:facet>
<h:column>
<h:outputText value="#{order}" />
</h:column>
</h:dataTable>
</h:form>
</h:body>
</html>
You are using an CDI-Bean, but the #ViewScoped-Annotation, that you are using, is JSF-specific and does not work in a CDI-Bean.
You could use a JSF-managedBean instead
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean(name="testBean")
#ViewScoped
public class DataTableTest implements Serializable { .. }
If changing to a managedBean is not an option for you, take a look at CDI-specific #ConversationScope or Seam, where you have a #ViewScoped annotation that also works fine with CDI-Beans.

#ViewScoped doesn't work, bean is created for every request

I am migrating from JSF1.2 to 2.1, I changed entries for beans in faces-config.xml to annotations. I try use #ViewScoped instead #RequestScoped and #ManagedProperties(To many params in few classes), but every time i click submit for my form bean with annotated as #ViewScoped is recreated. For #SessionScoped everything works correctyl.
I read few Q&A here, and This article, but i didn't force it to work.
I change JSTL tags to rendered atribute, or c:if with ui:param rendered.
in my web.xml i set params:
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>CLIENT</param-value>
</context-param>
I tried javax.faces.PARTIAL_STATE_SAVING = true, but didn't work too. With javax.faces.STATE_SAVING_METHOD = SERVER the same problem.
I removed tags handler for test, but it didn't help too.
In project is used: Mojarra 2.1.13, hibernate 3.6, spring 3.1(far as i know updated form 2.x by my predecessor), acegi-security-1.0.5, tomahawk20, urlrewrite-3.2.0.
I use tomcat 6
EDIT:
This is my bean:
package my.package;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.bean.ViewScoped;
import my.package.MyOtherBean;
#ManagedBean(name="someNameBean")
#ViewScoped
//#SessionScoped
public class MyBean extends MyOtherBean {
public MyBean(){
super();
//XXX
System.out.println("-->> someNameBean is being created");
}
}
package my.package;
#ManagedBean(name="someNameMyOtherBean")
//#ViewScoped
#SessionScoped
public class MyOtherBean extends BaseBean {
private ClassWithFormFields dataIn; //getter & setter exist
//a lot of code here
}
Example use of bean
<h:selectOneMenu value="#{someNameBean.dataIn.currencyId}" id="currencyId" tabindex="2" >
<f:selectItems value="#{someNameBean.dataIn..availableCurrencies}"/>
</h:selectOneMenu>
Update
serviceLocalizator is managed by Spring xml files ans JSF annotation
#ManagedBean
public class BaseBean implements Serializable {
private static final long serialVersionUID = 1L;
protected transient Logger log = Logger.getLogger(this.getClass());
#ManagedProperty(value="#{serviceLocalizator}")
protected transient ServiceLocalizator serviceLocalizator;
//few more lines
}
Update 2:
It's My fault. Thanks for #kolossus that he the indicated direction.
I i was looking for answer and I found and read BalusC article And now i now, i shouldn't return string in backing bean action. With null instead string it works. I badly understood concept of a view, I thought that ViewSoped bean id live as long as tab/windows is the same. Now i know that is it JSF View.
I'am sory for a trouble.
Maybe is a way to use #ViewSoped with redirect to new page?
NB: If you reference the same (non-session scoped) bean from 2 different views, two instances of that bean will be created
Navigating in JSF is very basic and straightforward from whatever kind of a bean that is backing a JSF view.
return the name (view id) of the page you're trying to navigate to as the return value of a public method
public String navigateAway(){
//Do whatever processing you want here
return "page2"; //where page2 is the name of an actual .xhtml file in your application
}
Return a JSF navigation case outcome as specified in a faces_config.xml file
public String navigateAway(){
//Prior processing
return "go somewhere else" ; //where go somewhere else is a navigation outcome you've specified in your faces_config.xml file
}
In your faces_config.xml file, you'll have this
<navigation-rule>
<from-view-id>/register.xhtml</from-view-id>
<navigation-case>
<from-outcome>go somewhere else</from-outcome>
<to-view-id>/review_registration.xhtml</to-view-id>
<redirect/>
</navigation-case>
If you want to remain on the same page after an action however, just return null instead of a string in your method and you will not be taken to another view. Also, depending on the scope of your backing bean, you can be sure you will be using the same instance of the bean if you return a null value
For more detail look here

Resources