Enterprise Java Development@TOPIC@
Provides a rich Model View Controller (MVC) framework for developing web-based UIs
Integrates well with many CDI concepts
Provides access to model state and actions
Referred by assigned name in page #{sellerController.xxx}
Caches state for page
Scope of state depends on declaration
@RequestScoped - stateless
@ConversationScoped - state maintained across requests within a conversation boundary
@SessionScoped - state maintained for lifetime of user session
@ApplicationScoped - state maintained for life of application
Figure 104.2. Example JSF Controller Bean
@Named("sellerController") //named used by the JSF page to access properties and actions
@ConversationScoped //controls lifespan of instance
public class SellerController implements Serializable { //#{sellerController.xxx}
CDI @Named used to specify name for page to use
Class required to implement Serializable unless RequestScoped
Figure 104.3. Controller Bean Example Business Data State
private Product product;
public Product getProduct() { return product; } //value="#{sellerController.product.name}
public void setProduct(Product product) { //value="#{sellerController.product.name}
this.product = product;
}
<h:inputText value="#{sellerController.product.name}" required="true"/>
Page refers to @Name.property and accesses using associated methods (SellerController.getProperty() and Product.setName() in this case)
Controller holds this state until action called
Figure 104.4. Controller Bean Example Action
public String addNew() { //action="#{sellerController.addNew}"
this.product = new Product(); //create a new Product instance
return null; //for navigation
}
public String add() { //action="#{sellerController.add}"
products.add(product);
return "/seller/seller-products"; //for navigation
}
public String save() { //action="#{sellerController.save}"
product.setSeller(user.getMember());
try {
product = catalog.addProduct(product);
Collections.sort(products, new Product.ProductASC());
return null; //for navigation
} catch (InvalidProduct ex) {
error.setError("error saving product:" + product);
error.setException(ex);
return "error"; //for navigation
}
}
<h:commandButton ...
action="#{sellerController.addNew}"
value="Sell New Product"/>
...
<h:commandButton value="Add Product" action="#{sellerController.add}"/>
...
<h:commandButton value="save" action="#{sellerController.save}">
...
</h:commandButton>
Page refers to action using @Name.methodName
Action methods take no arguments. They act on state supplied by setters.
Action methods return a String result used for navigation
Action methods may interact with business methods/resources to perform task
Figure 104.6. Controller Bean Back-end Business Resources
public class SellerController implements Serializable {
...
@Inject @Tx //back-end business logic that can manage products
private ProductCatalog catalog;
@Inject //place to stash errors to be displayed
private ErrorController error;
Useful in interacting with back-end resources and other page controllers
ProductCatalog is a Java business interface that is implemented by a DAO and EJB.
@Inject tells the provider to inject an implementation that matches the specified type
@Tx is defined within the application to further qualify which provider of the ProductCatalog interface is used
ErrorController is a sibling PageController for crudely displaying error messages and stack traces
Figure 104.7. Example Error Controller Bean
@Named("errorController") // #{errorController.xxx}
@SessionScoped
public class ErrorController implements Serializable {
private String error;
private Exception exception;
public String getError() { return error; } // #{errorController.error}
public void setError(String error) {
this.error = error;
}
public String getStackTrace() { // #{errorController.stackTrace}
if (exception != null) {
StringWriter sw = new StringWriter();
exception.printStackTrace(new PrintWriter(sw));
return sw.toString();
} else {
return null;
}
}
public void setException(Exception exception) {
this.exception = exception;
}
}
Simple example contains business data state and data access methods
Many mark-up languages can be used (e.g., JSP, XHTML, etc.)
Figure 104.8. Example XHTML Error Page
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<title>Error Page</title>
</h:head>
<h:body>
<h2>Error: #{errorController.error}</h2>
<p>
#{errorController.stackTrace}
</p>
<h:link value="Home" outcome="/index" />
</h:body>
</html>
Page uses XHTML markup -- must be a legacy XML document
Page uses JSF types xmlns:h="http://xmlns.jcp.org/jsf/html"
to interact with framework and controller bean
Figure 104.10. Outer Page Structure
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Sell Products (#{sellerController.seller.name})</title>
</h:head>
<h:body>
<h3>Sell Products (#{sellerController.seller.name})</h3>
</h:body>
</html>
Standard html begin/end tags and basic HTML document formatting
JSF provides replacement h:head and h:body tags
Figure 104.11. Example Form
<h:form binding="#{sellerController.form}">
<h:outputText value="Category"/>
<h:selectOneMenu value="#{sellerController.product.category}" required="true">
<f:selectItems value="#{sellerController.categories}"/>
</h:selectOneMenu>
<h:outputText value="Name"/>
<h:inputText value="#{sellerController.product.name}" required="true"/>
<h:outputText value="Year"/>
<h:inputText value="#{sellerController.product.year}"/>
<h:outputText value="Price"/>
<h:inputText value="#{sellerController.product.price}"/>
<p></p>
<h:commandButton value="Add Product" action="#{sellerController.add}"/>
</h:form>
public class SellerController implements Serializable {
private UIForm form;
public UIForm getForm() { return form; } //binding="#{sellerController.form}"
public void setForm(UIForm form) { //binding="#{sellerController.form}"
this.form = form;
}
Form bound to UIForm
instance supplied by provider. Permits controller bean to manage page form.
Form will display the starting state of Product
Form will update the properties of Product
commandButton registered to action method in controller
Figure 104.12. Example Choice List
<h:selectOneMenu value="#{sellerController.product.category}" required="true">
<f:selectItems value="#{sellerController.categories}"/>
</h:selectOneMenu>
public List<SelectItem> getCategories() {
List<SelectItem> list = new ArrayList<SelectItem>(ProductCategory.values().length);
for (ProductCategory pc: ProductCategory.values()) {
list.add(new SelectItem(pc, pc.getPrettyName()));
}
return list;
}
selectMenu calls getCategories()
to obtain choice list
selectMenu will store that value in SellerController.getProduct().setCatagory()
Figure 104.13. Example commandButton
<h:commandButton value="Add Product" action="#{sellerController.add}"/>
private UIForm form;
private UICommand addCommand;
public String add() {
products.add(product);
Collections.sort(products, new Product.ProductASC());
form.setRendered(false);
addCommand.setRendered(true);
return "/seller/seller-products";
}
commandButton calls SellerController.add()
action
SellerController.add() action acts on the state and provides a navigation result
Figure 104.14. Example Table with Row Actions
<h:form>
<h:dataTable value="#{sellerController.products}" var="p">
...
<h:column>
<f:facet name="header">
<h:column>
<h:outputText value="Name"></h:outputText>
</h:column>
</f:facet>
<h:outputText value="#{p.name}"/>
</h:column>
...
<h:column>
<f:facet name="header">
<h:column>
<h:outputText value="Actions"></h:outputText>
</h:column>
</f:facet>
<h:panelGrid columns="2">
<h:commandButton value="save" action="#{sellerController.save}">
<f:setPropertyActionListener
target="#{sellerController.product}"
value="#{p}"/>
</h:commandButton>
</h:panelGrid>
</h:column>
</h:dataTable>
</h:form>
public String save() {
product.setSeller(user.getMember());
product = catalog.addProduct(product); //EJB call
Collections.sort(products, new Product.ProductASC());
return null;
}
Table displays column and row data
Example shows columns for each property of the product
Example adds commandButton to each row to control actions with back-end
Figure 104.15.
target/cdisales-war |-- index.xhtml |-- seller | `-- seller-products.xhtml `-- WEB-INF |-- beans.xml |-- classes |-- content | `-- error.xhtml |-- faces-config.xml |-- lib `-- web.xml
index.xhtml and seller-products.xhtml meant to be bookmarked and called at any time -- please in public web space
error.xhtml meant to be navigated to from other controllers. Placed in non-public WEB-INF directory
faces-config.xml can be used for navigation flow and pre-dates @Annotations
beans.xml enables CDI processing
Figure 104.16. Example JSF web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
</web-app>
FacesServlet
declared to process all JSF pages
PROJECT_STAGE=Development enables extra debug in output
Figure 104.17. Example welcome-file
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>CDI Sales</title>
</h:head>
<h:body>
<h2>CDI Sales Main Menu</h2>
<ul>
<li><h:link value="Sell Products" outcome="seller/seller-products"/></li>
</ul>
</h:body>
</html>
Provides a top level entry page
Example provides link(s) to more detailed pages
This and follow-on pages may or may not reference a controller
Figure 104.18. Example faces-config.xml
<?xml version="1.0"?>
<faces-config
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
version="2.2">
<navigation-rule>
<from-view-id>/seller/seller-products.xhtml</from-view-id>
<navigation-case>
<from-outcome>error</from-outcome>
<to-view-id>/WEB-INF/content/error.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
Any "error"
output from seller-products will navigate to error page
Figure 104.19. Example (empty) beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans bean-discovery-mode="all" version="1.1"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd">
</beans>
CDI activated when file exists (blank, empty, or populated)