Update the JSF 2 order portlet from the first recipe to send an event when an order is saved, and create a new portlet to display a list of active orders.
The following are required for this recipe:
To modify the existing order portlet to fire an event:
pom.xml
, add the following dependency:<dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <scope>provided</scope> <version>2.1</version> </dependency>
OrderEvent
within a package named gatein.cookbook.chapter10
with the following content:@XmlRootElement public class OrderEvent implements Serializable { private Order order; public static final QName QNAME = new QName("urn:chapter10:jsf:order:event", "OrderEvent"); public OrderEvent(Order order) { this.order = order; } public Order getOrder() { return order; } }
create
method of Order
by adding the following code before return "orderSuccess"
:Object response = FacesContext.getCurrentInstance().getExternalContext().getResponse(); if (response instanceof StateAwareResponse) { StateAwareResponse stateResponse = (StateAwareResponse) response; stateResponse.setEvent(OrderEvent.QNAME, new OrderEvent(this)); }
portlet.xml
just before </portlet>
:<supported-publishing-event> <qname xmlns:jsf="urn:chapter10:jsf:order:event">jsf:OrderEvent</qname> </supported-publishing-event>
portlet.xml
just before </portlet-app>
:<event-definition> <qname xmlns:jsf="urn:chapter10:jsf:order:event">jsf:OrderEvent</qname> <value-type>gatein.cookbook.chapter10.OrderEvent</value-type> </event-definition>
To create a new portlet listing the active orders:
OrderManagerEvent
within a package named gatein.cookbook.chapter10
with the following content:@ManagedBean @ApplicationScoped public class OrderManagerEvent implements Serializable { private static final long serialVersionUID = -5776345927432051634L; Set<Order> orders = new HashSet<Order>(); public void addOrder(Order order) { orders.add(order); } public Set<Order> getOrders() { return orders; } public void setOrders(Set<Order> orders) { this.orders = orders; } }
OrderEventHandler
within a package named gatein.cookbook.chapter10
with the following content:public class OrderEventHandler implements BridgeEventHandler { public EventNavigationResult handleEvent(FacesContext context, Event event) { ELResolver facesResolver = context.getELContext().getELResolver(); OrderManagerEvent mgrBean = (OrderManagerEvent) facesResolver.getValue(context.getELContext(), null, "orderManagerEvent"); mgrBean.addOrder(((OrderEvent)event.getValue()).getOrder()); return new EventNavigationResult("/", "/orderList.xhtml"); } }
OrderList
within a package named gatein.cookbook.chapter10
with the following content:@ManagedBean @RequestScoped public class OrderList { @ManagedProperty(value = "#{orderManagerEvent}") private OrderManagerEvent orderManager; public void setOrderManager(OrderManagerEvent orderManager) { this.orderManager = orderManager; } public List<Order> getActiveOrders() { List<Order> active = new ArrayList<Order>(); for (Order order : orderManager.getOrders()) { if (order.getStatus().equals(Status.WAITING)) { active.add(order); } } return active; } }
orderList.xhtml
in the src/main/webapp
folder of the project.orderList.xhtml
:<f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets"> <h:body> <ui:composition template="/templates/layout.xhtml"> <ui:define name="header"> <h3>Active Orders</h3> </ui:define> <ui:define name="content"> <h:outputText value="There are currently no active orders" rendered="#{empty orderList.activeOrders}" /> <h:dataTable value="#{orderList.activeOrders}" var="ord" rendered="#{not empty orderList.activeOrders}" border="1" style="text-align:center"> <h:column> <f:facet name="header">Order Type</f:facet> #{ord.type} </h:column> <h:column> <f:facet name="header">Trade Instruction</f:facet> #{ord.tradeInstruction} </h:column> <h:column> <f:facet name="header">Account Number</f:facet> #{ord.accountNumber} </h:column> <h:column> <f:facet name="header">Number of Stocks</f:facet> #{ord.numberStocks} </h:column> <h:column> <f:facet name="header">Date Entered</f:facet> <h:outputText value="#{ord.entryDate}"> <f:convertDateTime pattern="hh:mm:ssa d-M-yyyy" /> </h:outputText> </h:column> <h:column> <f:facet name="header">Status</f:facet> #{ord.status} </h:column> </h:dataTable> </ui:define> </ui:composition> </h:body> </f:view>
portlet.xml
just before </portlet-app>
:<portlet> <portlet-name>OrderList-JSF</portlet-name> <portlet-class>javax.portlet.faces.GenericFacesPortlet</portlet-class> <init-param> <name>javax.portlet.faces.defaultViewId.view</name> <value>/orderList.xhtml</value> </init-param> <init-param> <name>javax.portlet.faces.bridgeEventHandler</name> <value>gatein.cookbook.chapter10.OrderEventHandler</value> </init-param> <supports> <mime-type>text/html</mime-type> <portlet-mode>VIEW</portlet-mode> </supports> <portlet-info> <title>Order List JSF Portlet</title> </portlet-info> <supported-processing-event> <qname xmlns:jsf="urn:chapter10:jsf:order:event">jsf:OrderEvent</qname> </supported-processing-event> </portlet>
web.xml
:<context-param> <param-name>javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE</param-name> <param-value>true</param-value> </context-param>
>mvn clean package
chapter10-jsf-1.0.0.SNAPSHOT.war
, from the target
folder into the deployment folder of where you unpacked the GateIn installation.OrderList-JSF
portlet to it below the Order-JSF
portlet. The OrderList-JSF
portlet can be found under the Chapter10-jsf
category.The following step details relate to modifying the existing order portlet.
Step 2 created an event class that can be passed between the portlets, defining the namespace the event will reside in.
Step 3 modified the create
method, called during the process of saving an order, to set the OrderEvent
onto the response.
Steps 4 and 5 updated the portlet.xml
to include the definition of the OrderEvent
and define that as the order portlet
The following step details are for the new order list portlet.
Step 1 creates a new
@ApplicationScoped
bean to hold the orders that are received from the event.
Step 2 creates an event handler to process the incoming events. It uses the JSF resolver to retrieve the bean created in Step 1 and call addOrder
on it passing the event Order
.
Step 3 creates a
@RequestScoped
bean to retrieve the active orders from the @ApplicationScoped
bean for the page.
Steps 4 and 5 create the page to display the list of active orders. At its simplest, there are outputText
and dataTable
components, with differing rendered
attributes so that when there are no orders, a piece of text is displayed, but when there are orders, a table is displayed. The
<f:facet>
is present within <h:column>
to define a column heading for display as if the code read <th>
.
Step 6 defines the new portlet in portlet.xml
and informs the portlet container that it can process the OrderEvent
.
Step 7 informs JSF that any use of <f:convertDateTime>
, such as in Step 5, should use the timezone of the machine instead of UTC for displaying time.
18.117.230.81